From 946a17f457563687c0b9f4c895ee84373e22ca5e Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 28 Jan 2016 16:44:47 +0000 Subject: [PATCH] changed void to int for some event handlers. deprecated the on_accepted callback for tcp. added stio_dev_send(), stio_tcp_dev_send() and changed stio_exec() to send queued messages moved tcp and udp defintions to stio-tcp.h and stio-udp.h respectively --- stio/lib/Makefile | 2 +- stio/lib/main.c | 48 ++++++--- stio/lib/stio-prv.h | 2 + stio/lib/stio-sck.c | 23 +++++ stio/lib/stio-tcp.c | 200 ++++++++++++++++------------------- stio/lib/stio-tcp.h | 168 ++++++++++++++++++++++++++++++ stio/lib/stio-udp.c | 8 +- stio/lib/stio-udp.h | 62 +++++++++++ stio/lib/stio.c | 176 ++++++++++++++++++++++++++++--- stio/lib/stio.h | 247 ++++++++++++++++++++------------------------ 10 files changed, 656 insertions(+), 280 deletions(-) create mode 100644 stio/lib/stio-tcp.h create mode 100644 stio/lib/stio-udp.h diff --git a/stio/lib/Makefile b/stio/lib/Makefile index c0c02b7..729b7f6 100644 --- a/stio/lib/Makefile +++ b/stio/lib/Makefile @@ -1,2 +1,2 @@ all: - cc -o stio main.c stio.c stio-tcp.c stio-udp.c stio-sck.c + cc -g -I. -Wall -o stio main.c stio.c stio-tcp.c stio-udp.c stio-sck.c diff --git a/stio/lib/main.c b/stio/lib/main.c index fe245f7..a530f24 100644 --- a/stio/lib/main.c +++ b/stio/lib/main.c @@ -25,7 +25,10 @@ */ -#include "stio.h" +#include +#include +#include + #include #include #include @@ -50,13 +53,6 @@ static stio_mmgr_t mmgr = STIO_NULL }; - - -static void tcp_on_connected (stio_dev_tcp_t* tcp) -{ - printf ("REALLY CONNECTED.......\n"); -} - static void tcp_on_disconnected (stio_dev_tcp_t* tcp) { if (tcp->state & STIO_DEV_TCP_LISTENING) @@ -76,12 +72,33 @@ static void tcp_on_disconnected (stio_dev_tcp_t* tcp) printf ("TCP DISCONNECTED - THIS MUST NOT HAPPEN (%d)\n", tcp->sck); } } -static void tcp_on_accepted (stio_dev_tcp_t* tcp, stio_dev_tcp_t* clitcp) +static int tcp_on_connected (stio_dev_tcp_t* tcp) { - printf ("device accepted client device... ....\n"); + + if (tcp->state & STIO_DEV_TCP_CONNECTED) + { +printf ("device connected to a remote server... .asdfjkasdfkljasdlfkjasdj...\n"); + } + else if (tcp->state & STIO_DEV_TCP_ACCEPTED) + { +printf ("device accepted client device... .asdfjkasdfkljasdlfkjasdj...\n"); + } + + return stio_dev_tcp_send (tcp, "hello", 5, STIO_NULL); } +static int tcp_on_sent (stio_dev_tcp_t* tcp, void* sendctx) +{ + printf (">>> TCP SENT MESSAGE\n"); + return 0; +} + +static int tcp_on_recv (stio_dev_tcp_t* tcp, const void* buf, stio_len_t len) +{ + return stio_dev_tcp_send (tcp, "HELLO", 5, STIO_NULL); +} + static stio_t* g_stio; static void handle_signal (int sig) @@ -99,6 +116,7 @@ int main () struct sigaction sigact; stio_dev_tcp_connect_t tcp_conn; stio_dev_tcp_listen_t tcp_lstn; + stio_dev_tcp_make_t tcp_make; stio = stio_open (&mmgr, 0, STIO_NULL); @@ -169,7 +187,13 @@ int main () } #else sin.sin_port = htons(1234); - tcp = stio_dev_tcp_make (stio, (stio_sckadr_t*)&sin); + + + STIO_MEMCPY (&tcp_make.addr, &sin, STIO_SIZEOF(sin)); + tcp_make.on_sent = tcp_on_sent; /* inherit this handler */ + tcp_make.on_recv = tcp_on_recv; /* inherit this handler */ + + tcp = stio_dev_tcp_make (stio, 0, &tcp_make); if (!tcp) { printf ("Cannot make tcp\n"); @@ -177,7 +201,7 @@ int main () } tcp_lstn.backlogs = 100; - tcp_lstn.on_accepted = tcp_on_accepted; + tcp_lstn.on_connected = tcp_on_connected; tcp_lstn.on_disconnected = tcp_on_disconnected; if (stio_dev_tcp_listen (tcp, &tcp_lstn) <= -1) { diff --git a/stio/lib/stio-prv.h b/stio/lib/stio-prv.h index 92ccded..60d5cc2 100644 --- a/stio/lib/stio-prv.h +++ b/stio/lib/stio-prv.h @@ -62,6 +62,8 @@ stio_sckhnd_t stio_openasyncsck (int domain, int type); void stio_closeasyncsck (stio_sckhnd_t sck); int stio_makesckasync (stio_sckhnd_t sck); +int stio_getsckadrinfo (stio_t* stio, const stio_sckadr_t* addr, stio_scklen_t* len, stio_sckfam_t* family); + #ifdef __cplusplus } #endif diff --git a/stio/lib/stio-sck.c b/stio/lib/stio-sck.c index 099786a..c36551f 100644 --- a/stio/lib/stio-sck.c +++ b/stio/lib/stio-sck.c @@ -28,7 +28,10 @@ #include "stio-prv.h" #include #include +#include #include +#include +#include /* ------------------------------------------------------------------------ */ void stio_closeasyncsck (stio_sckhnd_t sck) @@ -83,3 +86,23 @@ stio_sckhnd_t stio_openasyncsck (int domain, int type) return sck; } +int stio_getsckadrinfo (stio_t* stio, const stio_sckadr_t* addr, stio_scklen_t* len, stio_sckfam_t* family) +{ + struct sockaddr* saddr = (struct sockaddr*)addr; + + if (saddr->sa_family == AF_INET) + { + if (len) *len = STIO_SIZEOF(struct sockaddr_in); + if (family) *family = AF_INET; + return 0; + } + else if (saddr->sa_family == AF_INET6) + { + if (len) *len = STIO_SIZEOF(struct sockaddr_in6); + if (family) *family = AF_INET6; + return 0; + } + + stio->errnum = STIO_EINVAL; + return -1; +} diff --git a/stio/lib/stio-tcp.c b/stio/lib/stio-tcp.c index c5b7ac9..5fbd013 100644 --- a/stio/lib/stio-tcp.c +++ b/stio/lib/stio-tcp.c @@ -26,7 +26,9 @@ #include "stio-prv.h" +#include "stio-tcp.h" +#include #include #include #include @@ -38,38 +40,29 @@ static int tcp_make (stio_dev_t* dev, void* ctx) /* NOTE: this can be extended to use ctx to tell between INET and INET6 or other types of sockets without creating a new dev method set. */ stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; - struct sockaddr* saddr = (struct sockaddr*)ctx; + stio_dev_tcp_make_t* arg = (stio_dev_tcp_make_t*)ctx; + stio_scklen_t len; + stio_sckfam_t family; + int iv; - tcp->sck = stio_openasyncsck (AF_INET, SOCK_STREAM); + if (stio_getsckadrinfo(dev->stio, &arg->addr, &len, &family) <= -1) return -1; + + tcp->sck = stio_openasyncsck (family, SOCK_STREAM); if (tcp->sck == STIO_SCKHND_INVALID) goto oops; - if (saddr) + //setsockopt (udp->sck, SOL_SOCKET, SO_REUSEADDR, ...); + // TRANSPARENT, ETC. + iv = 1; + if (setsockopt (tcp->sck, SOL_SOCKET, SO_REUSEADDR, &iv, STIO_SIZEOF(iv)) == -1 || + bind (tcp->sck, (struct sockaddr*)&arg->addr, len) == -1) { - stio_scklen_t len; - int iv; - - if (saddr->sa_family == AF_INET) - len = STIO_SIZEOF(struct sockaddr_in); - else if (saddr->sa_family == AF_INET6) - len = STIO_SIZEOF(struct sockaddr_in6); - else - { - dev->stio->errnum = STIO_EINVAL; - goto oops; - } - - //setsockopt (udp->sck, SOL_SOCKET, SO_REUSEADDR, ...); - // TRANSPARENT, ETC. - - iv = 1; - if (setsockopt (tcp->sck, SOL_SOCKET, SO_REUSEADDR, &iv, STIO_SIZEOF(iv)) == -1 || - bind (tcp->sck, saddr, len) == -1) - { - //dev->stio->errnum = STIO_EINVAL; TODO: - goto oops; - } + // TODO: set errnum from errno ... + //dev->stio->errnum = STIO_EINVAL; + goto oops; } + tcp->on_sent = arg->on_sent; + tcp->on_recv = arg->on_recv; return 0; oops: @@ -92,7 +85,6 @@ static int tcp_make_accepted (stio_dev_t* dev, void* ctx) return 0; } - static void tcp_kill (stio_dev_t* dev) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; @@ -119,13 +111,13 @@ static stio_syshnd_t tcp_getsyshnd (stio_dev_t* dev) static int tcp_recv (stio_dev_t* dev, void* buf, stio_len_t* len) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; - int x; + ssize_t x; -printf ("TCP RECV...\n"); x = recv (tcp->sck, buf, *len, 0); if (x <= -1) { if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data available */ + if (errno == EINTR) return 0; return -1; } @@ -135,26 +127,29 @@ printf ("TCP RECV...\n"); static int tcp_send (stio_dev_t* dev, const void* data, stio_len_t* len) { - stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)tcp; + stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; ssize_t x; -#if 0 - x = sendto (tcp->sck, data, *len, skad, stio_getskadlen(skad)); +/* flags MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB, MSG_NOSIGNAL */ + x = sendto (tcp->sck, data, *len, 0, STIO_NULL, 0); if (x <= -1) { if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data can be written */ + if (errno == EINTR) return 0; return -1; } -/* for UDP, if the data chunk can't be written at one go, it's actually a failure */ - if (x != *len) return -1; /* TODO: can i hava an indicator for this in stio? */ +/***************/ +{ +static int x = 0; +if (x <= 2) { x++; return 0; } +} +/***************/ *len = x; -#endif return 1; } - static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; @@ -166,15 +161,10 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) stio_dev_tcp_bind_t* bnd = (stio_dev_tcp_bind_t*)arg; struct sockaddr* sa = (struct sockaddr*)&bnd->addr; stio_scklen_t sl; + stio_sckfam_t fam; int x; - if (sa->sa_family == AF_INET) sl = STIO_SIZEOF(struct sockaddr_in); - else if (sa->sa_family == AF_INET6) sl = STIO_SIZEOF(struct sockaddr_in6); - else - { - dev->stio->errnum = STIO_EINVAL; - return -1; - } + if (stio_getsckadrinfo (dev->stio, &bnd->addr, &sl, &fam) <= -1) return -1; #if defined(_WIN32) /* TODO */ @@ -257,7 +247,7 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) } tcp->state |= STIO_DEV_TCP_LISTENING; - tcp->on_accepted = lstn->on_accepted; + tcp->on_connected = lstn->on_connected; tcp->on_disconnected = lstn->on_disconnected; return 0; #endif @@ -267,21 +257,6 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) return 0; } -int stio_dev_tcp_bind (stio_dev_tcp_t* tcp, stio_dev_tcp_bind_t* bind) -{ - return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_BIND, bind); -} - -int stio_dev_tcp_connect (stio_dev_tcp_t* tcp, stio_dev_tcp_connect_t* conn) -{ - return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_CONNECT, conn); -} - -int stio_dev_tcp_listen (stio_dev_tcp_t* tcp, stio_dev_tcp_listen_t* lstn) -{ - return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_LISTEN, lstn); -} - static stio_dev_mth_t tcp_mth = { @@ -304,7 +279,6 @@ static stio_dev_mth_t tcp_acc_mth = tcp_send }; - /* ------------------------------------------------------------------------ */ static int tcp_ready (stio_dev_t* dev, int events) @@ -325,7 +299,6 @@ printf ("TCP READY...%p\n", dev); printf ("CANNOT CONNECT ERRORCODE - %s\n", strerror(errcode)); } -printf ("Cannot connect....\n"); return -1; } else if (events & STIO_DEV_EVENT_OUT) @@ -339,6 +312,8 @@ printf ("Cannot connect....\n"); len = STIO_SIZEOF(errcode); if (getsockopt (tcp->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) { + printf ("CANNOT GET SOCKET CONNECTION STATE....\n"); + return -1; } else if (errcode == 0) { @@ -347,11 +322,15 @@ printf ("Cannot connect....\n"); if (stio_dev_event ((stio_dev_t*)tcp, STIO_DEV_EVENT_MOD, STIO_DEV_EVENT_IN) <= -1) { - printf ("CAANOT MANIPULTE EVENT ... KILL DEVICE...\n"); + printf ("CAANOT MANIPULTE EVENT ...\n"); return -1; } - if (tcp->on_connected) tcp->on_connected (tcp); + if (tcp->on_connected (tcp) <= -1) + { + printf ("ON_CONNECTE HANDLER RETURNEF FAILURE...\n"); + return -1; + } } else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK) { @@ -371,6 +350,7 @@ printf ("Cannot connect....\n"); stio_sckhnd_t clisck; stio_sckadr_t peer; stio_scklen_t addrlen; + stio_dev_tcp_t* clitcp; /* this is a server(lisening) socket */ @@ -379,53 +359,43 @@ printf ("Cannot connect....\n"); if (clisck == -1) { if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; + if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */ /* TODO: set tcp->stio->errnum from errno */ return -1; } - if (tcp->on_accepted) + + /* addr is the address of the peer */ + /* local addresss is inherited from the server */ + clitcp = (stio_dev_tcp_t*)stio_makedev (tcp->stio, STIO_SIZEOF(*tcp), &tcp_acc_mth, tcp->evcb, &clisck); + if (!clitcp) { - stio_dev_tcp_t* clitcp; - - /* addr is the address of the peer */ - /* local addresss is inherited from the server */ - - clitcp = (stio_dev_tcp_t*)stio_makedev (tcp->stio, STIO_SIZEOF(*tcp), &tcp_acc_mth, tcp->evcb, &clisck); - if (!clitcp) - { - close (clisck); - return -1; - } - - clitcp->state |= STIO_DEV_TCP_ACCEPTED; - clitcp->peer = peer; - clitcp->parent = tcp; - - /* inherit the parent's on_disconnected() handler. - * you can still change it inside the on_accepted handler */ - clitcp->on_disconnected = tcp->on_disconnected; - - tcp->on_accepted (tcp, clitcp); - } - else - { - /* no on_accepted callback is set. close the client socket - * without doing anything meaningful */ close (clisck); + return -1; } + clitcp->state |= STIO_DEV_TCP_ACCEPTED; + clitcp->peer = peer; + clitcp->parent = tcp; + + /* inherit some event handlers from the parent. + * you can still change them inside the on_connected handler */ + clitcp->on_connected = tcp->on_connected; + clitcp->on_disconnected = tcp->on_disconnected; + clitcp->on_sent = tcp->on_sent; + clitcp->on_recv = tcp->on_recv; + + if (clitcp->on_connected (clitcp) <= -1) stio_dev_tcp_kill (clitcp); return 0; /* success but don't invoke on_recv() */ } printf ("READY WITH %d\n", events); - if (events & (STIO_DEV_EVENT_ERR | STIO_DEV_EVENT_HUP)) { printf ("DISCONNECTED or ERROR \n"); - stio_killdev (dev->stio, dev); - return 0; + return -1; /* the caller must kill the device */ } return 1; /* the device is ok. carry on reading or writing */ @@ -434,21 +404,13 @@ printf ("DISCONNECTED or ERROR \n"); static int tcp_on_recv (stio_dev_t* dev, const void* data, stio_len_t len) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; - -printf ("TCP dATA received %d bytes\n", (int)len); - - return 0; - + return tcp->on_recv (tcp, data, len); } -static int tcp_on_sent (stio_dev_t* dev, const void* data, stio_len_t len) +static int tcp_on_sent (stio_dev_t* dev, void* sendctx) { stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; - - /* TODO: do something */ -printf ("TCP dATA sent %d bytes\n", (int)len); - - return 0; + return tcp->on_sent (tcp, sendctx); } static stio_dev_evcb_t tcp_evcb = @@ -458,18 +420,32 @@ static stio_dev_evcb_t tcp_evcb = tcp_on_sent }; - -stio_dev_tcp_t* stio_dev_tcp_make (stio_t* stio, stio_sckadr_t* addr) +stio_dev_tcp_t* stio_dev_tcp_make (stio_t* stio, stio_size_t xtnsize, const stio_dev_tcp_make_t* arg) { - stio_dev_tcp_t* tcp; - - tcp = (stio_dev_tcp_t*)stio_makedev (stio, STIO_SIZEOF(*tcp), &tcp_mth, &tcp_evcb, addr); - - return tcp; + return (stio_dev_tcp_t*)stio_makedev (stio, STIO_SIZEOF(stio_dev_tcp_t) + xtnsize, &tcp_mth, &tcp_evcb, (void*)arg); } - void stio_dev_tcp_kill (stio_dev_tcp_t* tcp) { stio_killdev (tcp->stio, (stio_dev_t*)tcp); } + +int stio_dev_tcp_bind (stio_dev_tcp_t* tcp, stio_dev_tcp_bind_t* bind) +{ + return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_BIND, bind); +} + +int stio_dev_tcp_connect (stio_dev_tcp_t* tcp, stio_dev_tcp_connect_t* conn) +{ + return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_CONNECT, conn); +} + +int stio_dev_tcp_listen (stio_dev_tcp_t* tcp, stio_dev_tcp_listen_t* lstn) +{ + return stio_dev_ioctl ((stio_dev_t*)tcp, STIO_DEV_TCP_LISTEN, lstn); +} + +int stio_dev_tcp_send (stio_dev_tcp_t* tcp, const void* data, stio_len_t len, void* sendctx) +{ + return stio_dev_send ((stio_dev_t*)tcp, data, len, sendctx); +} diff --git a/stio/lib/stio-tcp.h b/stio/lib/stio-tcp.h new file mode 100644 index 0000000..c8268ae --- /dev/null +++ b/stio/lib/stio-tcp.h @@ -0,0 +1,168 @@ +/* + * $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. + */ + +#ifndef _STIO_TCP_H_ +#define _STIO_TCP_H_ + +#include + +enum stio_dev_tcp_ioctl_cmd_t +{ + STIO_DEV_TCP_BIND, + STIO_DEV_TCP_CONNECT, + STIO_DEV_TCP_LISTEN +}; +typedef enum stio_dev_tcp_ioctl_cmd_t stio_dev_tcp_ioctl_cmd_t; + +enum stio_dev_tcp_state_t +{ + STIO_DEV_TCP_CONNECTING = (1 << 0), + STIO_DEV_TCP_CONNECTED = (1 << 1), + STIO_DEV_TCP_LISTENING = (1 << 2), + STIO_DEV_TCP_ACCEPTED = (1 << 3) +}; +typedef enum stio_dev_tcp_state_t stio_dev_tcp_state_t; + +typedef struct stio_dev_tcp_t stio_dev_tcp_t; + +typedef int (*stio_dev_tcp_on_connected_t) (stio_dev_tcp_t* dev); +typedef void (*stio_dev_tcp_on_accepted_t) (stio_dev_tcp_t* dev, stio_dev_tcp_t* clidev); +typedef void (*stio_dev_tcp_on_disconnected_t) (stio_dev_tcp_t* dev); + +typedef int (*stio_dev_tcp_on_recv_t) (stio_dev_tcp_t* dev, const void* data, stio_len_t len); +typedef int (*stio_dev_tcp_on_sent_t) (stio_dev_tcp_t* dev, void* sendctx); + +struct stio_dev_tcp_t +{ + STIO_DEV_HEADERS; + + stio_sckhnd_t sck; + + unsigned int state; + + /* peer address - valid if one of the followings is set: + * STIO_DEV_TCP_ACCEPTED + * STIO_DEV_TCP_CONNECTED + * STIO_DEV_TCP_CONNECTING */ + stio_sckadr_t peer; + + /* parent tcp device. valid if STIO_DEV_TCP_ACCEPTED is set */ + stio_dev_tcp_t* parent; + + /** 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 */ + stio_dev_tcp_on_connected_t on_connected; + + stio_dev_tcp_on_disconnected_t on_disconnected; + stio_dev_tcp_on_recv_t on_recv; + stio_dev_tcp_on_sent_t on_sent; +}; + +typedef struct stio_dev_tcp_make_t stio_dev_tcp_make_t; +struct stio_dev_tcp_make_t +{ + /* TODO: options: REUSEADDR for binding?? */ + stio_sckadr_t addr; /* binding address. */ + stio_dev_tcp_on_sent_t on_sent; + stio_dev_tcp_on_recv_t on_recv; +}; + +typedef struct stio_dev_tcp_bind_t stio_dev_tcp_bind_t; +struct stio_dev_tcp_bind_t +{ + int options; /* TODO: REUSEADDR , TRANSPARENT, etc or someting?? */ + stio_sckadr_t addr; + /* TODO: add device name for BIND_TO_DEVICE */ +}; + +typedef struct stio_dev_tcp_connect_t stio_dev_tcp_connect_t; +struct stio_dev_tcp_connect_t +{ + stio_sckadr_t addr; +/* TODO: add timeout */ + stio_dev_tcp_on_connected_t on_connected; + stio_dev_tcp_on_disconnected_t on_disconnected; + /* stio_dev_tcp_on_timeout_t on_timeout; should the timeout handler be here? what about write timeout? or accept timeout? */ +}; + +typedef struct stio_dev_tcp_listen_t stio_dev_tcp_listen_t; +struct stio_dev_tcp_listen_t +{ + int backlogs; + stio_dev_tcp_on_connected_t on_connected; /* optional, but new connections are dropped immediately without this */ + stio_dev_tcp_on_disconnected_t on_disconnected; /* should on_discconneted be part of on_accept_t??? */ +}; + +typedef struct stio_dev_tcp_accept_t stio_dev_tcp_accept_t; +struct stio_dev_tcp_accept_t +{ + stio_syshnd_t sck; +/* TODO: add timeout */ + stio_dev_tcp_t* parent; /* TODO: is this really needed? */ + stio_sckadr_t peer; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +stio_dev_tcp_t* stio_dev_tcp_make ( + stio_t* stio, + stio_size_t xtnsize, + const stio_dev_tcp_make_t* data +); + +void stio_dev_tcp_kill ( + stio_dev_tcp_t* tcp +); + +int stio_dev_tcp_bind ( + stio_dev_tcp_t* tcp, + stio_dev_tcp_bind_t* bind +); + +int stio_dev_tcp_connect ( + stio_dev_tcp_t* tcp, + stio_dev_tcp_connect_t* conn); + +int stio_dev_tcp_listen ( + stio_dev_tcp_t* tcp, + stio_dev_tcp_listen_t* lstn +); + +int stio_dev_tcp_send ( + stio_dev_tcp_t* tcp, + const void* data, + stio_len_t len, + void* sendctx +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/stio/lib/stio-udp.c b/stio/lib/stio-udp.c index 9ba51dd..226b54c 100644 --- a/stio/lib/stio-udp.c +++ b/stio/lib/stio-udp.c @@ -26,6 +26,7 @@ #include "stio-prv.h" +#include "stio-udp.h" #include #include @@ -172,7 +173,7 @@ printf ("dATA received %d bytes\n", (int)len); } -static int udp_on_sent (stio_dev_t* dev, const void* data, stio_len_t len) +static int udp_on_sent (stio_dev_t* dev, void* msgid) { return 0; @@ -186,12 +187,11 @@ static stio_dev_evcb_t udp_evcb = }; - -stio_dev_udp_t* stio_dev_udp_make (stio_t* stio, stio_sckadr_t* addr) +stio_dev_udp_t* stio_dev_udp_make (stio_t* stio, stio_size_t xtnsize, stio_sckadr_t* addr) { stio_dev_udp_t* udp; - udp = (stio_dev_udp_t*)stio_makedev (stio, STIO_SIZEOF(*udp), &udp_mth, &udp_evcb, addr); + udp = (stio_dev_udp_t*)stio_makedev (stio, STIO_SIZEOF(*udp) + xtnsize, &udp_mth, &udp_evcb, addr); return udp; } diff --git a/stio/lib/stio-udp.h b/stio/lib/stio-udp.h new file mode 100644 index 0000000..d219513 --- /dev/null +++ b/stio/lib/stio-udp.h @@ -0,0 +1,62 @@ +/* + * $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. + */ + + +#ifndef _STIO_UDP_H_ +#define _STIO_UDP_H_ + +#include + +typedef struct stio_dev_udp_t stio_dev_udp_t; + +struct stio_dev_udp_t +{ + STIO_DEV_HEADERS; + stio_sckhnd_t sck; + stio_sckadr_t peer; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +stio_dev_udp_t* stio_dev_udp_make ( + stio_t* stio, + stio_size_t xtnsize, + stio_sckadr_t* addr +); + +void stio_dev_udp_kill ( + stio_dev_udp_t* udp +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/stio/lib/stio.c b/stio/lib/stio.c index ec90e77..097ccb9 100644 --- a/stio/lib/stio.c +++ b/stio/lib/stio.c @@ -68,7 +68,6 @@ void stio_close (stio_t* stio) STIO_MMGR_FREE (stio->mmgr, stio); } - stio_dev_t* stio_makedev (stio_t* stio, stio_size_t dev_size, stio_dev_mth_t* dev_mth, stio_dev_evcb_t* dev_evcb, void* make_ctx) { stio_dev_t* dev; @@ -90,6 +89,7 @@ stio_dev_t* stio_makedev (stio_t* stio, stio_size_t dev_size, stio_dev_mth_t* de dev->stio = stio; dev->mth = dev_mth; dev->evcb = dev_evcb; + STIO_WQ_INIT(&dev->wq); /* call the callback function first */ stio->errnum = STIO_ENOERR; @@ -133,7 +133,19 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev) { STIO_ASSERT (stio == dev->stio); - /* delink the dev object first */ + /* clear pending send requests */ + while (!STIO_WQ_ISEMPTY(&dev->wq)) + { + stio_wq_t* wq; + + wq = STIO_WQ_HEAD(&dev->wq); +printf ("DELETING UNSENT REQUETS...%p\n", wq); + STIO_WQ_DEQ (&dev->wq); + + STIO_MMGR_FREE (stio->mmgr, wq); + } + + /* delink the dev object */ if (dev->prev) dev->prev->next = dev->next; else @@ -165,12 +177,13 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev) int stio_prologue (stio_t* stio) { - + /* TODO: */ return 0; } void stio_epilogue (stio_t* stio) { + /* TODO: */ } int stio_exec (stio_t* stio) @@ -202,8 +215,6 @@ int stio_exec (stio_t* stio) #else - - nentries = epoll_wait (stio->mux, stio->revs, STIO_COUNTOF(stio->revs), timeout); if (nentries <= -1) { @@ -227,23 +238,29 @@ int stio_exec (stio_t* stio) /* return value of ready() * <= -1 - failure. kill the device. - * == 0 - ok. but don't invoke recv() or send(). if you want to kill the device within the ready callback, return 0. + * == 0 - ok. but don't invoke recv() or send(). * >= 1 - everything is ok. */ /* TODO: can the revs array contain the same file descriptor again??? */ if ((x = dev->evcb->ready (dev, events)) <= -1) + { stio_killdev (stio, dev); - else if (x >= 1) goto invoke_evcb; + dev = STIO_NULL; + } + else if (x >= 1) + { + goto invoke_evcb; + } } else { invoke_evcb: - if (stio->revs[i].events & EPOLLPRI) + if (dev && stio->revs[i].events & EPOLLPRI) { /* urgent data */ printf ("has urgent data...\n"); } - if (stio->revs[i].events & EPOLLIN) + if (dev && stio->revs[i].events & EPOLLIN) { stio_len_t len; int x; @@ -254,30 +271,93 @@ int stio_exec (stio_t* stio) printf ("DATA...recv %d length %d\n", (int)x, len); if (x <= -1) { + /*TODO: waht to do? killdev? how to indicate an error? call on_recv? with erro rindicator?? */ + stio_killdev (stio, dev); + dev = STIO_NULL; } else if (x == 0) { + /* EOF received. kill the device. */ stio_killdev (stio, dev); + dev = STIO_NULL; } else if (x >= 1) { /* data available??? */ - dev->evcb->on_recv (dev, stio->bigbuf, len); + if (dev->evcb->on_recv (dev, stio->bigbuf, len) <= -1) + { + stio_killdev (stio, dev); + dev = STIO_NULL; + } } } - if (stio->revs[i].events & EPOLLOUT) + if (dev && stio->revs[i].events & EPOLLOUT) { - /* - if (there is data to write) + while (!STIO_WQ_ISEMPTY(&dev->wq)) { - x = dev->mth->send (dev, stio->bigbuf, &len); + stio_wq_t* q; + const stio_uint8_t* uptr; + stio_len_t urem, ulen; + int x; + + q = STIO_WQ_HEAD(&dev->wq); + + uptr = q->ptr; + urem = q->len; + + send_leftover: + ulen = urem; + x = dev->mth->send (dev, uptr, &ulen); if (x <= -1) { + /* TODO: error handling? call callback? or what? */ + stio_killdev (stio, dev); + dev = STIO_NULL; + break; } + else if (x == 0) + { + /* keep the left-over */ + STIO_MEMMOVE (q->ptr, uptr, urem); + q->len = urem; + break; + } + else + { + uptr += ulen; + urem -= ulen; - dev->evcb->on_sent (dv, stio->bigbuf, x); - }*/ + if (urem <= 0) + { + int y; + + STIO_WQ_UNLINK (q); /* STIO_WQ_DEQ(&dev->wq); */ + y = dev->evcb->on_sent (dev, q->ctx); + STIO_MMGR_FREE (dev->stio->mmgr, q); + + if (y <= -1) + { + stio_killdev (stio, dev); + dev = STIO_NULL; + break; + } + } + else goto send_leftover; + } + } + + if (dev && STIO_WQ_ISEMPTY(&dev->wq)) + { + /* no pending request to write. + * watch input only. disable output watching */ + if (stio_dev_event (dev, STIO_DEV_EVENT_MOD, STIO_DEV_EVENT_IN) <= -1) + { + /* TODO: call an error handler??? */ + stio_killdev (stio, dev); + dev = STIO_NULL; + } + } } } } @@ -301,7 +381,6 @@ int stio_loop (stio_t* stio) while (!stio->stopreq && stio->dev.head) { -printf ("executing stio_exec...%p \n", stio->dev.head); if (stio_exec (stio) <= -1) break; /* you can do other things here */ } @@ -322,6 +401,7 @@ int stio_dev_event (stio_dev_t* dev, stio_dev_event_cmd_t cmd, int flags) { #if defined(_WIN32) + /* TODO */ #else struct epoll_event ev; int epoll_op; @@ -330,6 +410,7 @@ int stio_dev_event (stio_dev_t* dev, stio_dev_event_cmd_t cmd, int flags) #if defined(EPOLLRDHUP) ev.events |= EPOLLRDHUP; #endif + if (flags & STIO_DEV_EVENT_IN) ev.events |= EPOLLIN; if (flags & STIO_DEV_EVENT_OUT) ev.events |= EPOLLOUT; if (flags & STIO_DEV_EVENT_PRI) ev.events |= EPOLLPRI; @@ -363,3 +444,64 @@ int stio_dev_event (stio_dev_t* dev, stio_dev_event_cmd_t cmd, int flags) return 0; #endif } + +int stio_dev_send (stio_dev_t* dev, const void* data, stio_len_t len, void* sendctx) +{ + const stio_uint8_t* uptr; + stio_len_t urem, ulen; + int x; + + uptr = data; + urem = len; + + while (urem > 0) + { + ulen = urem; + x = dev->mth->send (dev, data, &ulen); + if (x <= -1) + { + return -1; + } + else if (x == 0) + { + stio_wq_t* q; + int wq_empty; + + /* queue the uremaining data*/ + wq_empty = STIO_WQ_ISEMPTY(&dev->wq); + + q = (stio_wq_t*)STIO_MMGR_ALLOC (dev->stio->mmgr, STIO_SIZEOF(*q) + urem); + if (!q) + { + dev->stio->errnum = STIO_ENOMEM; + return -1; + } + + q->ctx = sendctx; + q->ptr = (stio_uint8_t*)(q + 1); + q->len = urem; + STIO_MEMCPY (q->ptr, uptr, urem); + + STIO_WQ_ENQ (&dev->wq, q); + if (wq_empty) + { + if (stio_dev_event (dev, STIO_DEV_EVENT_MOD, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) <= -1) + { + STIO_WQ_UNLINK (q); /* unlink the ENQed item */ + STIO_MMGR_FREE (dev->stio->mmgr, q); + return -1; + } + } + + return 0; + } + else + { + urem -= ulen; + uptr += ulen; + } + } + + dev->evcb->on_sent (dev, sendctx); + return 0; +} diff --git a/stio/lib/stio.h b/stio/lib/stio.h index 167ffd0..c210f40 100644 --- a/stio/lib/stio.h +++ b/stio/lib/stio.h @@ -38,6 +38,8 @@ typedef signed char stio_int8_t; typedef unsigned char stio_uint8_t; typedef unsigned long stio_size_t; #define STIO_MEMSET(dst,byte,count) memset(dst,byte,count) +#define STIO_MEMCPY(dst,src,count) memcpy(dst,src,count) +#define STIO_MEMMOVE(dst,src,count) memmove(dst,src,count) #define STIO_ASSERT assert @@ -84,6 +86,7 @@ typedef struct stio_sckadr_t stio_sckadr_t; typedef int stio_syshnd_t; #endif +typedef int stio_sckfam_t; /* ------------------------------------------------------------------------- */ @@ -91,6 +94,8 @@ typedef struct stio_t stio_t; typedef struct stio_dev_t stio_dev_t; typedef struct stio_dev_mth_t stio_dev_mth_t; typedef struct stio_dev_evcb_t stio_dev_evcb_t; + +typedef struct stio_wq_t stio_wq_t; typedef unsigned int stio_len_t; /* TODO: remove it? */ @@ -109,35 +114,102 @@ typedef enum stio_errnum_t stio_errnum_t; struct stio_dev_mth_t { - /* --------------------------------------------------------------------------------------------- */ - int (*make) (stio_dev_t* dev, void* ctx); /* mandatory. called in stix_makedev() */ - void (*kill) (stio_dev_t* dev); /* mandatory. called in stix_killdev(). called in stix_makedev() upon failure after make() success */ - stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stix_makedev() after successful make() */ + /* ------------------------------------------------------------------ */ + int (*make) (stio_dev_t* dev, void* ctx); /* mandatory. called in stix_makedev() */ + /* ------------------------------------------------------------------ */ + void (*kill) (stio_dev_t* dev); /* mandatory. called in stix_killdev(). called in stix_makedev() upon failure after make() success */ - int (*ioctl) (stio_dev_t* dev, int cmd, void* arg); + /* ------------------------------------------------------------------ */ +#if 0 +/* TODO: countsyshnds() if the device has multiple handles. + * getsyshnd() to accept the handle id between 0 and countsysnhnds() - 1 + */ + int (*countsyshnds) (stio_dev_t* dev); /* optional */ +#endif + stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stix_makedev() after successful make() */ - /* --------------------------------------------------------------------------------------------- */ - int (*recv) (stio_dev_t* dev, void* data, stio_len_t* len); - /* --------------------------------------------------------------------------------------------- */ - int (*send) (stio_dev_t* dev, const void* data, stio_len_t* len); - /* --------------------------------------------------------------------------------------------- */ + /* ------------------------------------------------------------------ */ + int (*ioctl) (stio_dev_t* dev, int cmd, void* arg); + + /* ------------------------------------------------------------------ */ + int (*recv) (stio_dev_t* dev, void* data, stio_len_t* len); + + /* ------------------------------------------------------------------ */ + int (*send) (stio_dev_t* dev, const void* data, stio_len_t* len); }; struct stio_dev_evcb_t { - int (*ready) (stio_dev_t* dev, int events); - /*int (*on_error) (stio_dev_t* dev); - int (*on_hangup) (stio_dev_t* dev);*/ - int (*on_recv) (stio_dev_t* dev, const void* data, stio_len_t len); - int (*on_sent) (stio_dev_t* dev, const void* data, stio_len_t len); - + /* 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. + * it must not kill the device */ + int (*ready) (stio_dev_t* dev, int events); + + /* return -1 on failure, 0 on success + * it must not kill the device */ + int (*on_recv) (stio_dev_t* dev, const void* data, stio_len_t len); + + /* return -1 on failure, 0 on success. + * it must not kill the device */ + int (*on_sent) (stio_dev_t* dev, void* sendctx); }; +struct stio_wq_t +{ + stio_wq_t* next; + stio_wq_t* prev; + + stio_uint8_t* ptr; + stio_len_t len; + void* ctx; +}; + +#define STIO_WQ_INIT(wq) ((wq)->next = (wq)->prev = (wq)) +#define STIO_WQ_TAIL(wq) ((wq)->prev) +#define STIO_WQ_HEAD(wq) ((wq)->next) +#define STIO_WQ_ISEMPTY(wq) (STIO_WQ_HEAD(wq) == (wq)) +#define STIO_WQ_ISNODE(wq,x) ((wq) != (x)) +#define STIO_WQ_ISHEAD(wq,x) (STIO_WQ_HEAD(wq) == (x)) +#define STIO_WQ_ISTAIL(wq,x) (STIO_WQ_TAIL(wq) == (x)) + +#define STIO_WQ_NEXT(x) ((x)->next) +#define STIO_WQ_PREV(x) ((x)->prev) + +#define STIO_WQ_LINK(p,x,n) do { \ + stio_wq_t* pp = (p), * nn = (n); \ + (x)->prev = (p); \ + (x)->next = (n); \ + nn->prev = (x); \ + pp->next = (x); \ +} while (0) + +#define STIO_WQ_UNLINK(x) do { \ + stio_wq_t* pp = (x)->prev, * nn = (x)->next; \ + nn->prev = pp; pp->next = nn; \ +} while (0) + +#define STIO_WQ_REPL(o,n) do { \ + stio_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 STIO_WQ_ENQ(wq,x) STIO_WQ_LINK(STIO_WQ_TAIL(wq), x, STIO_WQ_TAIL(wq)->next)*/ +#define STIO_WQ_ENQ(wq,x) STIO_WQ_LINK(STIO_WQ_TAIL(wq), x, wq) + +/* remove an item in the front from the queue */ +#define STIO_WQ_DEQ(wq) STIO_WQ_UNLINK(STIO_WQ_HEAD(wq)) + #define STIO_DEV_HEADERS \ stio_t* stio; \ stio_dev_mth_t* mth; \ stio_dev_evcb_t* evcb; \ + stio_wq_t wq; \ stio_dev_t* prev; \ stio_dev_t* next @@ -161,114 +233,10 @@ enum stio_dev_event_flag_t STIO_DEV_EVENT_PRI = (1 << 2), STIO_DEV_EVENT_HUP = (1 << 3), STIO_DEV_EVENT_ERR = (1 << 4) - }; typedef enum stio_dev_event_flag_t stio_dev_event_flag_t; - -/* -------------------------------------------------------------------------- */ - - -enum stio_dev_tcp_ioctl_cmd_t -{ - STIO_DEV_TCP_BIND, - STIO_DEV_TCP_CONNECT, - STIO_DEV_TCP_LISTEN -}; -typedef enum stio_dev_tcp_ioctl_cmd_t stio_dev_tcp_ioctl_cmd_t; - -enum stio_dev_tcp_state_t -{ - STIO_DEV_TCP_CONNECTING = (1 << 0), - STIO_DEV_TCP_CONNECTED = (1 << 1), - STIO_DEV_TCP_LISTENING = (1 << 2), - STIO_DEV_TCP_ACCEPTED = (1 << 3) -}; -typedef enum stio_dev_tcp_state_t stio_dev_tcp_state_t; - -typedef struct stio_dev_tcp_t stio_dev_tcp_t; - -typedef void (*stio_dev_tcp_on_connected_t) (stio_dev_tcp_t* dev); -typedef void (*stio_dev_tcp_on_accepted_t) (stio_dev_tcp_t* dev, stio_dev_tcp_t* clidev); -typedef void (*stio_dev_tcp_on_disconnected_t) (stio_dev_tcp_t* dev); - -struct stio_dev_tcp_t -{ - STIO_DEV_HEADERS; - - stio_sckhnd_t sck; - - unsigned int state; - - /* peer address - valid if one of the followings is set: - * STIO_DEV_TCP_ACCEPTED - * STIO_DEV_TCP_CONNECTED - * STIO_DEV_TCP_CONNECTING */ - stio_sckadr_t peer; - - /* parent tcp device. valid if STIO_DEV_TCP_ACCEPTED is set */ - stio_dev_tcp_t* parent; - - stio_dev_tcp_on_connected_t on_connected; - stio_dev_tcp_on_disconnected_t on_disconnected; - stio_dev_tcp_on_accepted_t on_accepted; -}; - -typedef struct stio_dev_tcp_bind_t stio_dev_tcp_bind_t; -struct stio_dev_tcp_bind_t -{ - int options; /* TODO: REUSEADDR , TRANSPARENT, etc or someting?? */ - stio_sckadr_t addr; - /* TODO: add device name for BIND_TO_DEVICE */ -}; - -#if 0 -struct stio_dev_tcp_make_t -{ - set io callbacks.. -}; -#endif - -typedef struct stio_dev_tcp_connect_t stio_dev_tcp_connect_t; -struct stio_dev_tcp_connect_t -{ - stio_sckadr_t addr; - stio_dev_tcp_on_connected_t on_connected; - stio_dev_tcp_on_disconnected_t on_disconnected; -}; - -typedef struct stio_dev_tcp_listen_t stio_dev_tcp_listen_t; -struct stio_dev_tcp_listen_t -{ - int backlogs; - stio_dev_tcp_on_accepted_t on_accepted; /* optional, but new connections are dropped immediately without this */ - stio_dev_tcp_on_disconnected_t on_disconnected; -}; - -typedef struct stio_dev_tcp_accept_t stio_dev_tcp_accept_t; -struct stio_dev_tcp_accept_t -{ - stio_syshnd_t sck; - stio_dev_tcp_t* parent; - stio_sckadr_t peer; -}; - -/* -------------------------------------------------------------------------- */ - -typedef struct stio_dev_udp_t stio_dev_udp_t; - -struct stio_dev_udp_t -{ - STIO_DEV_HEADERS; - stio_sckhnd_t sck; - - stio_sckadr_t peer; -}; - -/* -------------------------------------------------------------------------- */ - - #ifdef __cplusplus extern "C" { #endif @@ -283,6 +251,18 @@ void stio_close ( stio_t* stio ); +int stio_exec ( + stio_t* stio +); + +int stio_loop ( + stio_t* stio +); + +void stio_stop ( + stio_t* stio +); + stio_dev_t* stio_makedev ( stio_t* stio, stio_size_t dev_size, @@ -296,24 +276,23 @@ void stio_killdev ( stio_dev_t* dev ); - -stio_dev_tcp_t* stio_dev_tcp_make ( - stio_t* stio, - stio_sckadr_t* addr +int stio_dev_ioctl ( + stio_dev_t* dev, + int cmd, + void* arg ); -void stio_dev_tcp_kill ( - stio_dev_tcp_t* tcp +int stio_dev_event ( + stio_dev_t* dev, + stio_dev_event_cmd_t cmd, + int flags ); - -stio_dev_udp_t* stio_dev_udp_make ( - stio_t* stio, - stio_sckadr_t* addr -); - -void stio_dev_udp_kill ( - stio_dev_udp_t* udp +int stio_dev_send ( + stio_dev_t* dev, + const void* data, + stio_len_t len, + void* sendctx ); #ifdef __cplusplus