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:
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 <stdio.h>
#include <sys/socket.h>
@ -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)
{

View File

@ -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

View File

@ -28,7 +28,10 @@
#include "stio-prv.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* ------------------------------------------------------------------------ */
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;
}

View File

@ -26,7 +26,9 @@
#include "stio-prv.h"
#include "stio-tcp.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.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. */
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);
}

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-udp.h"
#include <sys/socket.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;
@ -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;
}

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_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;
}

View File

@ -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