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
This commit is contained in:
hyung-hwan 2016-01-28 16:44:47 +00:00
parent 26ef795828
commit 946a17f457
10 changed files with 656 additions and 280 deletions

View File

@ -1,2 +1,2 @@
all: 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

View File

@ -25,7 +25,10 @@
*/ */
#include "stio.h" #include <stio.h>
#include <stio-tcp.h>
#include <stio-udp.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -50,13 +53,6 @@ static stio_mmgr_t mmgr =
STIO_NULL 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) static void tcp_on_disconnected (stio_dev_tcp_t* tcp)
{ {
if (tcp->state & STIO_DEV_TCP_LISTENING) 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); 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 stio_t* g_stio;
static void handle_signal (int sig) static void handle_signal (int sig)
@ -99,6 +116,7 @@ int main ()
struct sigaction sigact; struct sigaction sigact;
stio_dev_tcp_connect_t tcp_conn; stio_dev_tcp_connect_t tcp_conn;
stio_dev_tcp_listen_t tcp_lstn; stio_dev_tcp_listen_t tcp_lstn;
stio_dev_tcp_make_t tcp_make;
stio = stio_open (&mmgr, 0, STIO_NULL); stio = stio_open (&mmgr, 0, STIO_NULL);
@ -169,7 +187,13 @@ int main ()
} }
#else #else
sin.sin_port = htons(1234); 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) if (!tcp)
{ {
printf ("Cannot make tcp\n"); printf ("Cannot make tcp\n");
@ -177,7 +201,7 @@ int main ()
} }
tcp_lstn.backlogs = 100; 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; tcp_lstn.on_disconnected = tcp_on_disconnected;
if (stio_dev_tcp_listen (tcp, &tcp_lstn) <= -1) if (stio_dev_tcp_listen (tcp, &tcp_lstn) <= -1)
{ {

View File

@ -62,6 +62,8 @@ stio_sckhnd_t stio_openasyncsck (int domain, int type);
void stio_closeasyncsck (stio_sckhnd_t sck); void stio_closeasyncsck (stio_sckhnd_t sck);
int stio_makesckasync (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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -28,7 +28,10 @@
#include "stio-prv.h" #include "stio-prv.h"
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
void stio_closeasyncsck (stio_sckhnd_t sck) void stio_closeasyncsck (stio_sckhnd_t sck)
@ -83,3 +86,23 @@ stio_sckhnd_t stio_openasyncsck (int domain, int type)
return sck; 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;
}

View File

@ -26,7 +26,9 @@
#include "stio-prv.h" #include "stio-prv.h"
#include "stio-tcp.h"
#include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -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. */ /* 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; 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;
tcp->sck = stio_openasyncsck (AF_INET, SOCK_STREAM);
if (tcp->sck == STIO_SCKHND_INVALID) goto oops;
if (saddr)
{
stio_scklen_t len; stio_scklen_t len;
stio_sckfam_t family;
int iv; int iv;
if (saddr->sa_family == AF_INET) if (stio_getsckadrinfo(dev->stio, &arg->addr, &len, &family) <= -1) return -1;
len = STIO_SIZEOF(struct sockaddr_in);
else if (saddr->sa_family == AF_INET6) tcp->sck = stio_openasyncsck (family, SOCK_STREAM);
len = STIO_SIZEOF(struct sockaddr_in6); if (tcp->sck == STIO_SCKHND_INVALID) goto oops;
else
{
dev->stio->errnum = STIO_EINVAL;
goto oops;
}
//setsockopt (udp->sck, SOL_SOCKET, SO_REUSEADDR, ...); //setsockopt (udp->sck, SOL_SOCKET, SO_REUSEADDR, ...);
// TRANSPARENT, ETC. // TRANSPARENT, ETC.
iv = 1; iv = 1;
if (setsockopt (tcp->sck, SOL_SOCKET, SO_REUSEADDR, &iv, STIO_SIZEOF(iv)) == -1 || if (setsockopt (tcp->sck, SOL_SOCKET, SO_REUSEADDR, &iv, STIO_SIZEOF(iv)) == -1 ||
bind (tcp->sck, saddr, len) == -1) bind (tcp->sck, (struct sockaddr*)&arg->addr, len) == -1)
{ {
//dev->stio->errnum = STIO_EINVAL; TODO: // TODO: set errnum from errno ...
//dev->stio->errnum = STIO_EINVAL;
goto oops; goto oops;
} }
}
tcp->on_sent = arg->on_sent;
tcp->on_recv = arg->on_recv;
return 0; return 0;
oops: oops:
@ -92,7 +85,6 @@ static int tcp_make_accepted (stio_dev_t* dev, void* ctx)
return 0; return 0;
} }
static void tcp_kill (stio_dev_t* dev) static void tcp_kill (stio_dev_t* dev)
{ {
stio_dev_tcp_t* tcp = (stio_dev_tcp_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) static int tcp_recv (stio_dev_t* dev, void* buf, stio_len_t* len)
{ {
stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; 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); x = recv (tcp->sck, buf, *len, 0);
if (x <= -1) if (x <= -1)
{ {
if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data available */ if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data available */
if (errno == EINTR) return 0;
return -1; 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) 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; ssize_t x;
#if 0 /* flags MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB, MSG_NOSIGNAL */
x = sendto (tcp->sck, data, *len, skad, stio_getskadlen(skad)); x = sendto (tcp->sck, data, *len, 0, STIO_NULL, 0);
if (x <= -1) if (x <= -1)
{ {
if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data can be written */ if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; /* no data can be written */
if (errno == EINTR) return 0;
return -1; 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; *len = x;
#endif
return 1; return 1;
} }
static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg) static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg)
{ {
stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev; 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; stio_dev_tcp_bind_t* bnd = (stio_dev_tcp_bind_t*)arg;
struct sockaddr* sa = (struct sockaddr*)&bnd->addr; struct sockaddr* sa = (struct sockaddr*)&bnd->addr;
stio_scklen_t sl; stio_scklen_t sl;
stio_sckfam_t fam;
int x; int x;
if (sa->sa_family == AF_INET) sl = STIO_SIZEOF(struct sockaddr_in); if (stio_getsckadrinfo (dev->stio, &bnd->addr, &sl, &fam) <= -1) return -1;
else if (sa->sa_family == AF_INET6) sl = STIO_SIZEOF(struct sockaddr_in6);
else
{
dev->stio->errnum = STIO_EINVAL;
return -1;
}
#if defined(_WIN32) #if defined(_WIN32)
/* TODO */ /* TODO */
@ -257,7 +247,7 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg)
} }
tcp->state |= STIO_DEV_TCP_LISTENING; tcp->state |= STIO_DEV_TCP_LISTENING;
tcp->on_accepted = lstn->on_accepted; tcp->on_connected = lstn->on_connected;
tcp->on_disconnected = lstn->on_disconnected; tcp->on_disconnected = lstn->on_disconnected;
return 0; return 0;
#endif #endif
@ -267,21 +257,6 @@ static int tcp_ioctl (stio_dev_t* dev, int cmd, void* arg)
return 0; 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 = static stio_dev_mth_t tcp_mth =
{ {
@ -304,7 +279,6 @@ static stio_dev_mth_t tcp_acc_mth =
tcp_send tcp_send
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static int tcp_ready (stio_dev_t* dev, int events) 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 ERRORCODE - %s\n", strerror(errcode));
} }
printf ("Cannot connect....\n");
return -1; return -1;
} }
else if (events & STIO_DEV_EVENT_OUT) else if (events & STIO_DEV_EVENT_OUT)
@ -339,6 +312,8 @@ printf ("Cannot connect....\n");
len = STIO_SIZEOF(errcode); len = STIO_SIZEOF(errcode);
if (getsockopt (tcp->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) 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) 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) 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; 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) else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK)
{ {
@ -371,6 +350,7 @@ printf ("Cannot connect....\n");
stio_sckhnd_t clisck; stio_sckhnd_t clisck;
stio_sckadr_t peer; stio_sckadr_t peer;
stio_scklen_t addrlen; stio_scklen_t addrlen;
stio_dev_tcp_t* clitcp;
/* this is a server(lisening) socket */ /* this is a server(lisening) socket */
@ -379,18 +359,15 @@ printf ("Cannot connect....\n");
if (clisck == -1) if (clisck == -1)
{ {
if (errno == EINPROGRESS || errno == EWOULDBLOCK) return 0; 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 */ /* TODO: set tcp->stio->errnum from errno */
return -1; return -1;
} }
if (tcp->on_accepted)
{
stio_dev_tcp_t* clitcp;
/* addr is the address of the peer */ /* addr is the address of the peer */
/* local addresss is inherited from the server */ /* 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); clitcp = (stio_dev_tcp_t*)stio_makedev (tcp->stio, STIO_SIZEOF(*tcp), &tcp_acc_mth, tcp->evcb, &clisck);
if (!clitcp) if (!clitcp)
{ {
@ -402,30 +379,23 @@ printf ("Cannot connect....\n");
clitcp->peer = peer; clitcp->peer = peer;
clitcp->parent = tcp; clitcp->parent = tcp;
/* inherit the parent's on_disconnected() handler. /* inherit some event handlers from the parent.
* you can still change it inside the on_accepted handler */ * you can still change them inside the on_connected handler */
clitcp->on_connected = tcp->on_connected;
clitcp->on_disconnected = tcp->on_disconnected; clitcp->on_disconnected = tcp->on_disconnected;
clitcp->on_sent = tcp->on_sent;
clitcp->on_recv = tcp->on_recv;
tcp->on_accepted (tcp, clitcp); if (clitcp->on_connected (clitcp) <= -1) stio_dev_tcp_kill (clitcp);
}
else
{
/* no on_accepted callback is set. close the client socket
* without doing anything meaningful */
close (clisck);
}
return 0; /* success but don't invoke on_recv() */ return 0; /* success but don't invoke on_recv() */
} }
printf ("READY WITH %d\n", events); printf ("READY WITH %d\n", events);
if (events & (STIO_DEV_EVENT_ERR | STIO_DEV_EVENT_HUP)) if (events & (STIO_DEV_EVENT_ERR | STIO_DEV_EVENT_HUP))
{ {
printf ("DISCONNECTED or ERROR \n"); printf ("DISCONNECTED or ERROR \n");
stio_killdev (dev->stio, dev); return -1; /* the caller must kill the device */
return 0;
} }
return 1; /* the device is ok. carry on reading or writing */ 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) 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; stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev;
return tcp->on_recv (tcp, data, len);
printf ("TCP dATA received %d bytes\n", (int)len);
return 0;
} }
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; stio_dev_tcp_t* tcp = (stio_dev_tcp_t*)dev;
return tcp->on_sent (tcp, sendctx);
/* TODO: do something */
printf ("TCP dATA sent %d bytes\n", (int)len);
return 0;
} }
static stio_dev_evcb_t tcp_evcb = static stio_dev_evcb_t tcp_evcb =
@ -458,18 +420,32 @@ static stio_dev_evcb_t tcp_evcb =
tcp_on_sent tcp_on_sent
}; };
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* stio_dev_tcp_make (stio_t* stio, stio_sckadr_t* addr)
{ {
stio_dev_tcp_t* tcp; return (stio_dev_tcp_t*)stio_makedev (stio, STIO_SIZEOF(stio_dev_tcp_t) + xtnsize, &tcp_mth, &tcp_evcb, (void*)arg);
tcp = (stio_dev_tcp_t*)stio_makedev (stio, STIO_SIZEOF(*tcp), &tcp_mth, &tcp_evcb, addr);
return tcp;
} }
void stio_dev_tcp_kill (stio_dev_tcp_t* tcp) void stio_dev_tcp_kill (stio_dev_tcp_t* tcp)
{ {
stio_killdev (tcp->stio, (stio_dev_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);
}

168
stio/lib/stio-tcp.h Normal file
View File

@ -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 <stio.h>
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

View File

@ -26,6 +26,7 @@
#include "stio-prv.h" #include "stio-prv.h"
#include "stio-udp.h"
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -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; 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_size_t xtnsize, stio_sckadr_t* addr)
stio_dev_udp_t* stio_dev_udp_make (stio_t* stio, stio_sckadr_t* addr)
{ {
stio_dev_udp_t* udp; 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; return udp;
} }

62
stio/lib/stio-udp.h Normal file
View File

@ -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 <stio.h>
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

View File

@ -68,7 +68,6 @@ void stio_close (stio_t* stio)
STIO_MMGR_FREE (stio->mmgr, 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* 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; 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->stio = stio;
dev->mth = dev_mth; dev->mth = dev_mth;
dev->evcb = dev_evcb; dev->evcb = dev_evcb;
STIO_WQ_INIT(&dev->wq);
/* call the callback function first */ /* call the callback function first */
stio->errnum = STIO_ENOERR; stio->errnum = STIO_ENOERR;
@ -133,7 +133,19 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev)
{ {
STIO_ASSERT (stio == dev->stio); 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) if (dev->prev)
dev->prev->next = dev->next; dev->prev->next = dev->next;
else else
@ -165,12 +177,13 @@ void stio_killdev (stio_t* stio, stio_dev_t* dev)
int stio_prologue (stio_t* stio) int stio_prologue (stio_t* stio)
{ {
/* TODO: */
return 0; return 0;
} }
void stio_epilogue (stio_t* stio) void stio_epilogue (stio_t* stio)
{ {
/* TODO: */
} }
int stio_exec (stio_t* stio) int stio_exec (stio_t* stio)
@ -202,8 +215,6 @@ int stio_exec (stio_t* stio)
#else #else
nentries = epoll_wait (stio->mux, stio->revs, STIO_COUNTOF(stio->revs), timeout); nentries = epoll_wait (stio->mux, stio->revs, STIO_COUNTOF(stio->revs), timeout);
if (nentries <= -1) if (nentries <= -1)
{ {
@ -227,23 +238,29 @@ int stio_exec (stio_t* stio)
/* return value of ready() /* return value of ready()
* <= -1 - failure. kill the device. * <= -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. */ * >= 1 - everything is ok. */
/* TODO: can the revs array contain the same file descriptor again??? */ /* TODO: can the revs array contain the same file descriptor again??? */
if ((x = dev->evcb->ready (dev, events)) <= -1) if ((x = dev->evcb->ready (dev, events)) <= -1)
{
stio_killdev (stio, dev); stio_killdev (stio, dev);
else if (x >= 1) goto invoke_evcb; dev = STIO_NULL;
}
else if (x >= 1)
{
goto invoke_evcb;
}
} }
else else
{ {
invoke_evcb: invoke_evcb:
if (stio->revs[i].events & EPOLLPRI) if (dev && stio->revs[i].events & EPOLLPRI)
{ {
/* urgent data */ /* urgent data */
printf ("has urgent data...\n"); printf ("has urgent data...\n");
} }
if (stio->revs[i].events & EPOLLIN) if (dev && stio->revs[i].events & EPOLLIN)
{ {
stio_len_t len; stio_len_t len;
int x; int x;
@ -254,30 +271,93 @@ int stio_exec (stio_t* stio)
printf ("DATA...recv %d length %d\n", (int)x, len); printf ("DATA...recv %d length %d\n", (int)x, len);
if (x <= -1) 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) else if (x == 0)
{ {
/* EOF received. kill the device. */
stio_killdev (stio, dev); stio_killdev (stio, dev);
dev = STIO_NULL;
} }
else if (x >= 1) else if (x >= 1)
{ {
/* data available??? */ /* 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)
{ {
/* while (!STIO_WQ_ISEMPTY(&dev->wq))
if (there is data to write)
{ {
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) 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;
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;
}
} }
dev->evcb->on_sent (dv, stio->bigbuf, x); 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) while (!stio->stopreq && stio->dev.head)
{ {
printf ("executing stio_exec...%p \n", stio->dev.head);
if (stio_exec (stio) <= -1) break; if (stio_exec (stio) <= -1) break;
/* you can do other things here */ /* 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) #if defined(_WIN32)
/* TODO */
#else #else
struct epoll_event ev; struct epoll_event ev;
int epoll_op; 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) #if defined(EPOLLRDHUP)
ev.events |= EPOLLRDHUP; ev.events |= EPOLLRDHUP;
#endif #endif
if (flags & STIO_DEV_EVENT_IN) ev.events |= EPOLLIN; if (flags & STIO_DEV_EVENT_IN) ev.events |= EPOLLIN;
if (flags & STIO_DEV_EVENT_OUT) ev.events |= EPOLLOUT; if (flags & STIO_DEV_EVENT_OUT) ev.events |= EPOLLOUT;
if (flags & STIO_DEV_EVENT_PRI) ev.events |= EPOLLPRI; 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; return 0;
#endif #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;
}

View File

@ -38,6 +38,8 @@ typedef signed char stio_int8_t;
typedef unsigned char stio_uint8_t; typedef unsigned char stio_uint8_t;
typedef unsigned long stio_size_t; typedef unsigned long stio_size_t;
#define STIO_MEMSET(dst,byte,count) memset(dst,byte,count) #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 #define STIO_ASSERT assert
@ -84,6 +86,7 @@ typedef struct stio_sckadr_t stio_sckadr_t;
typedef int stio_syshnd_t; typedef int stio_syshnd_t;
#endif #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_t stio_dev_t;
typedef struct stio_dev_mth_t stio_dev_mth_t; typedef struct stio_dev_mth_t stio_dev_mth_t;
typedef struct stio_dev_evcb_t stio_dev_evcb_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? */ 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 struct stio_dev_mth_t
{ {
/* --------------------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------ */
int (*make) (stio_dev_t* dev, void* ctx); /* mandatory. called in stix_makedev() */ 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 */ void (*kill) (stio_dev_t* dev); /* mandatory. called in stix_killdev(). called in stix_makedev() upon failure after make() success */
/* ------------------------------------------------------------------ */
#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() */ stio_syshnd_t (*getsyshnd) (stio_dev_t* dev); /* mandatory. called in stix_makedev() after successful make() */
/* ------------------------------------------------------------------ */
int (*ioctl) (stio_dev_t* dev, int cmd, void* arg); int (*ioctl) (stio_dev_t* dev, int cmd, void* arg);
/* --------------------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------ */
int (*recv) (stio_dev_t* dev, void* data, stio_len_t* len); 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 (*send) (stio_dev_t* dev, const void* data, stio_len_t* len);
/* --------------------------------------------------------------------------------------------- */
}; };
struct stio_dev_evcb_t struct stio_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.
* it must not kill the device */
int (*ready) (stio_dev_t* dev, int events); 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 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 \ #define STIO_DEV_HEADERS \
stio_t* stio; \ stio_t* stio; \
stio_dev_mth_t* mth; \ stio_dev_mth_t* mth; \
stio_dev_evcb_t* evcb; \ stio_dev_evcb_t* evcb; \
stio_wq_t wq; \
stio_dev_t* prev; \ stio_dev_t* prev; \
stio_dev_t* next stio_dev_t* next
@ -161,114 +233,10 @@ enum stio_dev_event_flag_t
STIO_DEV_EVENT_PRI = (1 << 2), STIO_DEV_EVENT_PRI = (1 << 2),
STIO_DEV_EVENT_HUP = (1 << 3), STIO_DEV_EVENT_HUP = (1 << 3),
STIO_DEV_EVENT_ERR = (1 << 4) STIO_DEV_EVENT_ERR = (1 << 4)
}; };
typedef enum stio_dev_event_flag_t stio_dev_event_flag_t; 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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -283,6 +251,18 @@ void stio_close (
stio_t* stio 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_dev_t* stio_makedev (
stio_t* stio, stio_t* stio,
stio_size_t dev_size, stio_size_t dev_size,
@ -296,24 +276,23 @@ void stio_killdev (
stio_dev_t* dev stio_dev_t* dev
); );
int stio_dev_ioctl (
stio_dev_tcp_t* stio_dev_tcp_make ( stio_dev_t* dev,
stio_t* stio, int cmd,
stio_sckadr_t* addr void* arg
); );
void stio_dev_tcp_kill ( int stio_dev_event (
stio_dev_tcp_t* tcp stio_dev_t* dev,
stio_dev_event_cmd_t cmd,
int flags
); );
int stio_dev_send (
stio_dev_udp_t* stio_dev_udp_make ( stio_dev_t* dev,
stio_t* stio, const void* data,
stio_sckadr_t* addr stio_len_t len,
); void* sendctx
void stio_dev_udp_kill (
stio_dev_udp_t* udp
); );
#ifdef __cplusplus #ifdef __cplusplus