enhanced qse_upxd_t

This commit is contained in:
hyung-hwan 2012-06-20 15:12:18 +00:00
parent ba24a28f16
commit c60ca301c4
12 changed files with 1375 additions and 138 deletions

View File

@ -298,7 +298,7 @@ qse_wchar_t* qse_mbsatowcsalldup (
* n = qse_wcstombs (wcs, &wcslen, mbs, &mbslen);
* if (n <= -1)
* {
* // wcs fully scanned and mbs null-terminated
* // conversion error
* }
* @endcode
*/

View File

@ -229,7 +229,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h upxd.h
all: all-am
.SUFFIXES:

View File

@ -23,10 +23,10 @@
#include <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/nwad.h>
#include <qse/cmn/time.h>
typedef struct qse_upxd_t qse_upxd_t;
typedef struct qse_upxd_client_t qse_upxd_client_t;
typedef struct qse_upxd_server_t qse_upxd_server_t;
enum qse_upxd_errnum_t
{
@ -39,49 +39,177 @@ enum qse_upxd_errnum_t
QSE_UPXD_EINTR,
QSE_UPXD_EAGAIN,
QSE_UPXD_EINTERN,
QSE_UPXD_ESYSERR,
QSE_UPXD_ENOIMPL,
QSE_UPXD_EOTHER
};
typedef qse_upxd_errnum_t qse_upxd_errnum_t;
typedef enum qse_upxd_errnum_t qse_upxd_errnum_t;
struct qse_upxd_server_t
typedef struct qse_upxd_server_t qse_upxd_server_t;
typedef struct qse_upxd_session_t qse_upxd_session_t;
typedef struct qse_upxd_sock_t qse_upxd_sock_t;
struct qse_upxd_sock_t
{
qse_upxd_server_t* next;
/* ------------------------------ */
qse_nwad_t nwad;
qse_ubi_t handle;
qse_nwad_t bind;
const qse_char_t* dev;
qse_nwad_t from;
qse_nwad_t to;
};
struct qse_upxd_client_t
struct qse_upxd_session_t
{
qse_nwad_t remote_addr;
qse_nwad_t local_addr;
/** the server that this session belongs to */
qse_upxd_server_t* server;
/** client's address that initiated this session */
qse_nwad_t client;
/* session configuration to be filled in upxd->cbs->config(). */
struct
{
/** peer's address that the client wants to talk with */
qse_nwad_t peer;
/** binding address for peer socket */
qse_nwad_t bind;
#define QSE_UPXD_SESSION_DEV_LEN (31)
/** binding device for peer socket */
qse_char_t dev[QSE_UPXD_SESSION_DEV_LEN + 1];
#define QSE_UPXD_SESSION_DORMANCY (30000)
/** session's idle-timeout */
qse_ntime_t dormancy;
} config;
};
typedef int (*qse_upxd_muxcb_t) (
qse_upxd_t* upxd,
void* mux,
qse_ubi_t handle,
void* cbarg
);
struct qse_upxd_cbs_t
{
struct
{
int (*open) (qse_upxd_t* upxd, qse_upxd_server_t* server);
void (*close) (qse_upxd_t* upxd, qse_upxd_server_t* server);
int (*open) (qse_upxd_t* upxd, qse_upxd_sock_t* server);
void (*close) (qse_upxd_t* upxd, qse_upxd_sock_t* server);
qse_ssize_t (*recv) (
qse_upxd_t* upxd,
qse_upxd_client_t* client,
qse_mchar_t* buf, qse_size_t bufsize);
qse_upxd_t* upxd, qse_upxd_sock_t* server,
void* buf, qse_size_t bufsize);
qse_ssize_t (*send) (
qse_upxd_t* upxd,
qse_upxd_client_t* client,
const qse_mchar_t* buf, qse_size_t bufsize);
} server;
};
qse_upxd_t* upxd, qse_upxd_sock_t* sock,
const void* buf, qse_size_t bufsize);
} sock;
struct
{
int (*config) (qse_upxd_t* upxd, qse_upxd_session_t* session);
void (*error) (qse_upxd_t* upxd, qse_upxd_session_t* session);
} session;
struct
{
void* (*open) (qse_upxd_t* upxd);
void (*close) (qse_upxd_t* upxd, void* mux);
int (*addhnd) (
qse_upxd_t* upxd, void* mux, qse_ubi_t handle,
qse_upxd_muxcb_t cbfun, void* cbarg);
int (*delhnd) (qse_upxd_t* upxd, void* mux, qse_ubi_t handle);
int (*poll) (qse_upxd_t* upxd, void* mux, qse_ntime_t timeout);
} mux;
struct
{
void (*acquire) (qse_upxd_t* upxd);
void (*release) (qse_upxd_t* upxd);
} lock;
};
typedef struct qse_upxd_cbs_t qse_upxd_cbs_t;
#ifdef __cplusplus
extern "C" {
#endif
QSE_DEFINE_COMMON_FUNCTIONS (upxd)
qse_upxd_t* qse_upxd_open (
qse_mmgr_t* mmgr, /**< memory manager */
qse_size_t xtnsize /**< extension size in bytes */
);
void qse_upxd_close (
qse_upxd_t* upxd
);
qse_upxd_errnum_t qse_upxd_geterrnum (
qse_upxd_t* upxd
);
void qse_upxd_seterrnum (
qse_upxd_t* upxd,
qse_upxd_errnum_t errnum
);
qse_upxd_cbs_t* qse_upxd_getcbs (
qse_upxd_t* upxd
);
void qse_upxd_setcbs (
qse_upxd_t* upxd,
qse_upxd_cbs_t* cbs
);
void* qse_upxd_allocmem (
qse_upxd_t* upxd,
qse_size_t size
);
void* qse_upxd_reallocmem (
qse_upxd_t* upxd,
void* ptr,
qse_size_t size
);
void qse_upxd_freemem (
qse_upxd_t* upxd,
void* ptr
);
qse_upxd_server_t* qse_upxd_addserver (
qse_upxd_t* upxd,
const qse_nwad_t* nwad,
const qse_char_t* dev
);
void* qse_upxd_getserverctx (
qse_upxd_t* upxd,
qse_upxd_server_t* server
);
void qse_upxd_setserverctx (
qse_upxd_t* upxd,
qse_upxd_server_t* server,
void* ctx
);
void qse_upxd_stop (
qse_upxd_t* upxd
);
int qse_upxd_loop (
qse_upxd_t* upxd,
qse_ntime_t timeout
);
#ifdef __cplusplus
}
#endif

View File

@ -7,10 +7,11 @@ AM_CPPFLAGS = \
lib_LTLIBRARIES = libqsenet.la
libqsenet_la_SOURCES = \
httpd.h \
upxd.h \
http.c \
htre.c \
htrd.c \
httpd.h \
httpd.c \
httpd-cgi.c \
httpd-proxy.c \

View File

@ -79,7 +79,8 @@ am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libqsenet_la_DEPENDENCIES =
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
httpd-cgi.lo httpd-proxy.lo httpd-resol.lo httpd-task.lo
httpd-cgi.lo httpd-proxy.lo httpd-resol.lo httpd-task.lo \
upxd.lo
libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS)
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@ -256,15 +257,17 @@ AM_CPPFLAGS = \
lib_LTLIBRARIES = libqsenet.la
libqsenet_la_SOURCES = \
httpd.h \
upxd.h \
http.c \
htre.c \
htrd.c \
httpd.h \
httpd.c \
httpd-cgi.c \
httpd-proxy.c \
httpd-resol.c \
httpd-task.c
httpd-task.c \
upxd.c
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
libqsenet_la_LIBADD = -lqsecmn
@ -350,6 +353,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-resol.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -19,6 +19,16 @@
*/
#include "upxd.h"
#include <qse/cmn/str.h>
QSE_IMPLEMENT_COMMON_FUNCTIONS (upxd)
static void free_all_servers (qse_upxd_t* upxd);
static qse_upxd_server_session_t* find_server_session (
qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from);
static void release_session (
qse_upxd_t* upxd, qse_upxd_server_session_t* session);
qse_upxd_t* qse_upxd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{
@ -53,14 +63,9 @@ int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr)
void qse_upxd_fini (qse_upxd_t* upxd)
{
free_server_list (upxd, upxd->server.list);
QSE_ASSERT (upxd->server.navail == 0);
upxd->server.list = QSE_NULL;
}
void qse_upxd_stop (qse_upxd_t* upxd)
{
upxd->stopreq = 1;
QSE_ASSERTX (upxd->server.nactive == 0,
"Deactivate all servers before destroying me");
free_all_servers (upxd);
}
qse_upxd_errnum_t qse_upxd_geterrnum (qse_upxd_t* upxd)
@ -73,37 +78,461 @@ void qse_upxd_seterrnum (qse_upxd_t* upxd, qse_upxd_errnum_t errnum)
upxd->errnum = errnum;
}
int qse_upxd_addserver (qse_upxd_t* upxd, const qse_nwad_t* nwad)
QSE_INLINE void* qse_upxd_allocmem (qse_upxd_t* upxd, qse_size_t size)
{
void* ptr = QSE_MMGR_ALLOC (upxd->mmgr, size);
if (ptr == QSE_NULL) upxd->errnum = QSE_UPXD_ENOMEM;
return ptr;
}
QSE_INLINE void* qse_upxd_reallocmem (
qse_upxd_t* upxd, void* ptr, qse_size_t size)
{
void* nptr = QSE_MMGR_REALLOC (upxd->mmgr, ptr, size);
if (nptr == QSE_NULL) upxd->errnum = QSE_UPXD_ENOMEM;
return nptr;
}
QSE_INLINE void qse_upxd_freemem (qse_upxd_t* upxd, void* ptr)
{
QSE_MMGR_FREE (upxd->mmgr, ptr);
}
void qse_upxd_stop (qse_upxd_t* upxd)
{
upxd->stopreq = 1;
}
static int perform_session_task (
qse_upxd_t* upxd, void* mux, qse_ubi_t handle, void* cbarg)
{
qse_upxd_server_session_t* session;
qse_upxd_server_t* server;
qse_ssize_t n;
session = (qse_upxd_server_session_t*)cbarg;
server = session->inner.server;
qse_gettime (&session->modified);
/* this handler should set the 'from' field of server->scok */
n = upxd->cbs->sock.recv (
upxd, &session->peer, upxd->rbuf, QSE_SIZEOF(upxd->rbuf));
if (n <= -1)
{
upxd->cbs->session.error (upxd, &session->inner);
release_session (upxd, session);
return -1;
}
/* TODO: inspect if session->inner.to matches session->sock.from.
drop it if they don't match if a certain option (QSE_UPXD_STRICT)
is set??? */
/* send the peer's packet back to the client */
server->local.to = session->inner.client;
n = upxd->cbs->sock.send (upxd, &server->local, upxd->rbuf, n);
if (n <= -1)
{
upxd->cbs->session.error (upxd, &session->inner);
release_session (upxd, session);
return -1;
}
return 0;
}
static int perform_server_task (
qse_upxd_t* upxd, void* mux, qse_ubi_t handle, void* cbarg)
{
qse_upxd_server_t* server;
qse_upxd_server_session_t* session;
qse_ssize_t n;
server = (qse_upxd_server_t*)cbarg;
/* this handler should set the 'from' field of server->scok */
n = upxd->cbs->sock.recv (
upxd, &server->local, upxd->rbuf, QSE_SIZEOF(upxd->rbuf));
if (n <= -1) return -1;
/* get the existing session or create a new session based on
* server->local->from */
session = find_server_session (upxd, server, &server->local.from);
if (session == QSE_NULL)
{
qse_upxd_session_t interim;
QSE_MEMSET (&interim, 0, QSE_SIZEOF(interim));
interim.client = server->local.from;
upxd->cbs->session.error (upxd, &interim);
return -1;
}
n = upxd->cbs->sock.send (upxd, &session->peer, upxd->rbuf, n);
if (n <= -1)
{
upxd->cbs->session.error (upxd, &session->inner);
release_session (upxd, session);
return -1;
}
return 0;
}
static qse_upxd_server_session_t* find_server_session (
qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from)
{
qse_upxd_server_session_t* session;
/* TODO: make it indexable or hashable with 'from'
* don't perform linear search */
/* find an existing session made for the source address 'from' */
for (session = server->session.list; session; session = session->next)
{
if (QSE_MEMCMP (&session->inner.client, from, QSE_SIZEOF(*from)) == 0)
{
qse_gettime (&session->modified);
return session;
}
}
/* there is no session found for the source address 'from'.
* let's create a new session. */
session = qse_upxd_allocmem (upxd, QSE_SIZEOF(*session));
if (session == QSE_NULL) return QSE_NULL;
QSE_MEMSET (session, 0, QSE_SIZEOF(*session));
if (qse_gettime (&session->created) <= -1)
{
qse_upxd_freemem (upxd, session);
upxd->errnum = QSE_UPXD_ESYSERR;
return QSE_NULL;
}
session->modified = session->created;
session->inner.server = server;
session->inner.client = *from;
/* set the default dormancy */
session->inner.config.dormancy = QSE_UPXD_SESSION_DORMANCY;
/* call the configurationc callback for configuration data */
if (upxd->cbs->session.config (upxd, &session->inner) <= -1)
{
qse_upxd_freemem (upxd, session);
return QSE_NULL;
}
/* set up the peer socket with the configuration data */
session->peer.bind = session->inner.config.bind;
session->peer.to = session->inner.config.peer;
if (session->inner.config.dev[0] != QSE_T('\0'))
session->peer.dev = session->inner.config.dev;
if (upxd->cbs->sock.open (upxd, &session->peer) <= -1)
{
qse_upxd_freemem (upxd, session);
return QSE_NULL;
}
if (upxd->cbs->mux.addhnd (
upxd, upxd->mux, session->peer.handle,
perform_session_task, session) <= -1)
{
upxd->cbs->sock.close (upxd, &session->peer);
qse_upxd_freemem (upxd, session);
return QSE_NULL;
}
/* insert the session into the head of the session list */
if (server->session.list)
server->session.list->prev = session;
session->next = server->session.list;
server->session.list = session;
return session;
}
static void release_session (
qse_upxd_t* upxd, qse_upxd_server_session_t* session)
{
qse_upxd_server_t* server;
server = session->inner.server;
QSE_ASSERT (server != QSE_NULL);
upxd->cbs->mux.delhnd (upxd, upxd->mux, session->peer.handle);
upxd->cbs->sock.close (upxd, &session->peer);
/* remove the session from the session list */
if (session->next) session->next->prev = session->prev;
if (session->prev) session->prev->next = session->next;
else server->session.list = session->next;
/* destroy the session */
qse_upxd_freemem (upxd, session);
}
static int activate_server (qse_upxd_t* upxd, qse_upxd_server_t* server)
{
QSE_ASSERT (upxd->cbs != QSE_NULL);
QSE_ASSERT (!(server->flags & QSE_UPXD_SERVER_ACTIVE));
if (upxd->cbs->sock.open (upxd, &server->local) <= -1)
{
return -1;
}
if (upxd->cbs->mux.addhnd (
upxd, upxd->mux, server->local.handle,
perform_server_task, server) <= -1)
{
upxd->cbs->sock.close (upxd, &server->local);
return -1;
}
server->flags |= QSE_UPXD_SERVER_ACTIVE;
upxd->server.nactive++;
return 0;
}
static void deactivate_server (qse_upxd_t* upxd, qse_upxd_server_t* server)
{
qse_upxd_server_session_t* session;
QSE_ASSERT (upxd->cbs != QSE_NULL);
QSE_ASSERT (server->flags & QSE_UPXD_SERVER_ACTIVE);
session = server->session.list;
while (session)
{
qse_upxd_server_session_t* next = session->next;
release_session (upxd, session);
session = next;
}
upxd->cbs->mux.delhnd (upxd, upxd->mux, server->local.handle);
upxd->cbs->sock.close (upxd, &server->local);
server->flags &= ~QSE_UPXD_SERVER_ACTIVE;
upxd->server.nactive--;
}
static void activate_all_servers (qse_upxd_t* upxd)
{
qse_upxd_server_t* server;
for (server = upxd->server.list; server; server = server->next)
{
if (!(server->flags & QSE_UPXD_SERVER_ACTIVE))
{
activate_server (upxd, server);
}
}
}
static void deactivate_all_servers (qse_upxd_t* upxd)
{
qse_upxd_server_t* server;
server = upxd->server.list;
while (server)
{
if (server->flags & QSE_UPXD_SERVER_ACTIVE)
deactivate_server (upxd, server);
server = server->next;
}
}
static void free_all_servers (qse_upxd_t* upxd)
{
qse_upxd_server_t* server;
qse_upxd_server_t* next;
server = upxd->server.list;
while (server)
{
next = server->next;
QSE_MMGR_FREE (upxd->mmgr, server);
server = next;
}
upxd->server.list = QSE_NULL;
}
static void purge_deleted_servers (qse_upxd_t* upxd)
{
qse_upxd_server_t* server;
qse_upxd_server_t* next;
server = upxd->server.list;
while (server)
{
next = server->next;
if (server->flags & QSE_UPXD_SERVER_DELETED)
{
if (server->flags & QSE_UPXD_SERVER_ACTIVE)
deactivate_server (upxd, server);
if (server == upxd->server.list) upxd->server.list = next;
QSE_MMGR_FREE (upxd->mmgr, server);
}
server = next;
}
}
qse_upxd_server_t* qse_upxd_addserver (
qse_upxd_t* upxd, const qse_nwad_t* nwad, const qse_char_t* dev)
{
qse_upxd_server_t* server;
if (dev && qse_strlen(dev) >= QSE_COUNTOF(server->dev))
{
upxd->errnum = QSE_UPXD_EINVAL;
return QSE_NULL;
}
server = QSE_MMGR_ALLOC (upxd->mmgr, QSE_SIZEOF(*server));
if (server == QSE_NULL)
{
upxd->errnum = QSE_UPXD_ENOMEM;
return -1;
return QSE_NULL;
}
QSE_MEMSET (server, 0, QSE_SIZEOF(*server));
server->nwad = *nwad;
if (upxd->cbs->server.open (upxd, server) <= -1)
if (dev)
{
QSE_MMGR_FREE (upxd->mmgr, server);
return -1;
qse_strxcpy (server->dev, QSE_COUNTOF(server->dev), dev);
server->local.dev = server->dev;
}
server->local.bind = *nwad;
upxd->cbs->lock.acquire (upxd);
server->next = upxd->server.list;
upxd->server.list = server;
upxd->cbs->lock.release (upxd);
return server;
}
int qse_upxd_loop (qse_upxd_t* upxd, qse_upxd_cbls_t* cbs)
void qse_upxd_delserver (
qse_upxd_t* upxd, qse_upxd_server_t* server)
{
server->flags |= QSE_UPXD_SERVER_DELETED;
}
void* qse_upxd_getserverctx (
qse_upxd_t* upxd, qse_upxd_server_t* server)
{
return server->ctx;
}
void qse_upxd_setserverctx (
qse_upxd_t* upxd, qse_upxd_server_t* server, void* ctx)
{
server->ctx = ctx;
}
qse_upxd_cbs_t* qse_upxd_getcbs (qse_upxd_t* upxd)
{
return upxd->cbs;
}
void qse_upxd_setcbs (qse_upxd_t* upxd, qse_upxd_cbs_t* cbs)
{
upxd->cbs = cbs;
}
static QSE_INLINE void purge_idle_sessions_in_server (
qse_upxd_t* upxd, qse_upxd_server_t* server)
{
qse_upxd_server_session_t* session;
qse_upxd_server_session_t* next;
qse_ntime_t now;
qse_gettime (&now);
session = server->session.list;
while (session)
{
next = session->next;
if (session->inner.config.dormancy > 0 &&
now > session->modified &&
now - session->modified > session->inner.config.dormancy)
{
release_session (upxd, session);
}
session = next;
}
}
static void purge_idle_sessions (qse_upxd_t* upxd)
{
qse_upxd_server_t* server;
for (server = upxd->server.list; server; server = server->next)
{
if (server->flags & QSE_UPXD_SERVER_ACTIVE)
{
purge_idle_sessions_in_server (upxd, server);
}
}
}
int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout)
{
int retv = -1;
QSE_ASSERTX (upxd->cbs != QSE_NULL,
"Call qse_upxd_setcbs() before calling qse_upxd_loop()");
QSE_ASSERT (upxd->mux == QSE_NULL);
if (upxd->cbs == QSE_NULL || upxd->mux /*||
upxd->server.list == QSE_NULL*/)
{
upxd->errnum = QSE_UPXD_EINVAL;
goto oops;
}
upxd->stopreq = 0;
upxd->mux = upxd->cbs-> mux.open (upxd);
if (upxd->mux == QSE_NULL) goto oops;
activate_all_servers (upxd);
if (upxd->server.nactive == 0)
{
/* at least 1 server must be activated here */
upxd->errnum = QSE_UPXD_EINVAL;
goto oops;
}
while (!upxd->stopreq)
{
int count;
count = upxd->cbs->mux.poll (upxd, upxd->mux, timeout);
if (count <= -1)
{
/* TODO: anything? */
}
return 0;
upxd->cbs->lock.acquire (upxd);
purge_idle_sessions (upxd);
purge_deleted_servers (upxd);
activate_all_servers (upxd);
upxd->cbs->lock.release (upxd);
}
retv = 0;
oops:
if (upxd->server.nactive > 0) deactivate_all_servers (upxd);
if (upxd->mux) upxd->cbs->mux.close (upxd, upxd->mux);
return retv;
}

View File

@ -22,15 +22,80 @@
#define _QSE_LIB_NET_UPXD_H_
#include <qse/net/upxd.h>
#include "../cmn/mem.h"
typedef struct qse_upxd_server_session_t qse_upxd_server_session_t;
struct qse_upxd_server_t
{
qse_upxd_server_t* next;
#define QSE_UPXD_SERVER_ACTIVE (1 << 0)
#define QSE_UPXD_SERVER_DELETED (1 << 1)
int flags;
/* the socket can be bound to this interface.
* sock->dev points to this buffer when necessary. */
qse_char_t dev[QSE_UPXD_SESSION_DEV_LEN + 1];
/* list of sessions beloning to this server */
struct
{
qse_upxd_server_session_t* list;
qse_size_t count;
} session;
qse_upxd_sock_t local;
/* user-defined context data that can be set
* with qse_upxd_setserverctx() */
void* ctx;
};
struct qse_upxd_server_session_t
{
/* internal fields */
qse_upxd_server_session_t* next;
qse_upxd_server_session_t* prev;
/* timestamps for housekeeping */
qse_ntime_t created;
qse_ntime_t modified;
/* socket used to talk with a peer */
qse_upxd_sock_t peer;
/* exposed to a caller via callbacks */
qse_upxd_session_t inner;
};
struct qse_upxd_t
{
QSE_DEFINE_COMMON_FIELDS (upxd)
qse_upxd_errnum_t errnum;
int stopreq;
qse_upxd_cbs_t* cbs;
struct
{
qse_upxd_server_t* list;
qse_size_t nactive;
} server;
void* mux;
qse_uint8_t rbuf[65535];
};
#ifdef __cplusplus
extern "C" {
#endif
int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr);
void qse_upxd_fini (qse_upxd_t* upxd);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -5,7 +5,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(includedir)
bin_PROGRAMS = http01
bin_PROGRAMS = http01 upxd01
LDFLAGS += -L../../lib/cmn -L../../lib/net
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) -lssl
@ -15,4 +15,5 @@ LDADD += $(UNICOWS_LIBS)
endif
http01_SOURCES = http01.c
upxd01_SOURCES = upxd01.c

View File

@ -34,7 +34,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = http01$(EXEEXT)
bin_PROGRAMS = http01$(EXEEXT) upxd01$(EXEEXT)
@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
subdir = samples/net
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
@ -59,6 +59,11 @@ am__DEPENDENCIES_1 =
@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
http01_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_upxd01_OBJECTS = upxd01.$(OBJEXT)
upxd01_OBJECTS = $(am_upxd01_OBJECTS)
upxd01_LDADD = $(LDADD)
upxd01_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
DEFAULT_INCLUDES =
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
am__depfiles_maybe = depfiles
@ -72,8 +77,8 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(http01_SOURCES)
DIST_SOURCES = $(http01_SOURCES)
SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
DIST_SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -232,6 +237,7 @@ AM_CPPFLAGS = \
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
$(SENDFILE_LIBS) -lssl $(am__append_1)
http01_SOURCES = http01.c
upxd01_SOURCES = upxd01.c
all: all-am
.SUFFIXES:
@ -312,6 +318,9 @@ clean-binPROGRAMS:
http01$(EXEEXT): $(http01_OBJECTS) $(http01_DEPENDENCIES) $(EXTRA_http01_DEPENDENCIES)
@rm -f http01$(EXEEXT)
$(LINK) $(http01_OBJECTS) $(http01_LDADD) $(LIBS)
upxd01$(EXEEXT): $(upxd01_OBJECTS) $(upxd01_DEPENDENCIES) $(EXTRA_upxd01_DEPENDENCIES)
@rm -f upxd01$(EXEEXT)
$(LINK) $(upxd01_OBJECTS) $(upxd01_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -320,6 +329,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http01.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd01.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -10,6 +10,7 @@
#include <signal.h>
#include <locale.h>
#include <string.h>
#if defined(_WIN32)
# include <windows.h>
#else

598
qse/samples/net/upxd01.c Normal file
View File

@ -0,0 +1,598 @@
#include <qse/net/upxd.h>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mem.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/time.h>
#include <signal.h>
#include <locale.h>
#include <string.h>
#if defined(_WIN32)
# include <windows.h>
#else
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <net/if.h>
#endif
#if defined(HAVE_EPOLL)
# if defined(HAVE_SYS_EPOLL_H)
# include <sys/epoll.h>
# endif
#endif
/* ------------------------------------------------------------------- */
static qse_upxd_errnum_t syserr_to_errnum (int e)
{
switch (e)
{
case ENOMEM:
return QSE_UPXD_ENOMEM;
case EINVAL:
return QSE_UPXD_EINVAL;
case EACCES:
case ECONNREFUSED:
return QSE_UPXD_EACCES;
case ENOENT:
return QSE_UPXD_ENOENT;
case EEXIST:
return QSE_UPXD_EEXIST;
case EINTR:
return QSE_UPXD_EINTR;
case EAGAIN:
/*case EWOULDBLOCK:*/
return QSE_UPXD_EAGAIN;
default:
return QSE_UPXD_ESYSERR;
}
}
/* ------------------------------------------------------------------- */
static int sockaddr_to_nwad (
const struct sockaddr_storage* addr, qse_nwad_t* nwad)
{
int addrsize = -1;
switch (addr->ss_family)
{
case AF_INET:
{
struct sockaddr_in* in;
in = (struct sockaddr_in*)addr;
addrsize = QSE_SIZEOF(*in);
memset (nwad, 0, QSE_SIZEOF(*nwad));
nwad->type = QSE_NWAD_IN4;
nwad->u.in4.addr.value = in->sin_addr.s_addr;
nwad->u.in4.port = in->sin_port;
break;
}
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* in;
in = (struct sockaddr_in6*)addr;
addrsize = QSE_SIZEOF(*in);
memset (nwad, 0, QSE_SIZEOF(*nwad));
nwad->type = QSE_NWAD_IN6;
memcpy (&nwad->u.in6.addr, &in->sin6_addr, QSE_SIZEOF(nwad->u.in6.addr));
nwad->u.in6.scope = in->sin6_scope_id;
nwad->u.in6.port = in->sin6_port;
break;
}
#endif
}
return addrsize;
}
static int nwad_to_sockaddr (
const qse_nwad_t* nwad, struct sockaddr_storage* addr)
{
int addrsize = -1;
switch (nwad->type)
{
case QSE_NWAD_IN4:
{
struct sockaddr_in* in;
in = (struct sockaddr_in*)addr;
addrsize = QSE_SIZEOF(*in);
memset (in, 0, addrsize);
in->sin_family = AF_INET;
in->sin_addr.s_addr = nwad->u.in4.addr.value;
in->sin_port = nwad->u.in4.port;
break;
}
case QSE_NWAD_IN6:
{
#if defined(AF_INET6)
struct sockaddr_in6* in;
in = (struct sockaddr_in6*)addr;
addrsize = QSE_SIZEOF(*in);
memset (in, 0, addrsize);
in->sin6_family = AF_INET6;
memcpy (&in->sin6_addr, &nwad->u.in6.addr, QSE_SIZEOF(nwad->u.in6.addr));
in->sin6_scope_id = nwad->u.in6.scope;
in->sin6_port = nwad->u.in6.port;
#endif
break;
}
}
return addrsize;
}
/* ------------------------------------------------------------------- */
static int sock_open (qse_upxd_t* upxd, qse_upxd_sock_t* sock)
{
int fd = -1, flag;
int syserr = 1;
struct sockaddr_storage addr;
int addrsize;
addrsize = nwad_to_sockaddr (&sock->bind, &addr);
if (addrsize <= -1)
{
qse_upxd_seterrnum (upxd, QSE_UPXD_ENOIMPL);
syserr = 0;
goto oops;
}
/* TODO: if AF_INET6 is not defined sockaddr_storage is not available...
* create your own union or somehting similar... */
fd = socket (addr.ss_family, SOCK_DGRAM, IPPROTO_UDP);
if (fd <= -1) goto oops;
flag = fcntl (fd, F_GETFD);
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)
{
#if defined(IPV6_V6ONLY)
if (errno == EADDRINUSE && addr.ss_family == AF_INET6)
{
int on = 1;
setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1) goto oops;
}
else goto oops;
#else
goto oops;
#endif
}
if (sock->dev)
{
#if defined(SO_BINDTODEVICE)
struct ifreq ifr;
qse_size_t wsz, msz;
memset (&ifr, 0, sizeof(ifr));
#if defined(QSE_CHAR_IS_MCHAR)
qse_mbscpy (ifr.ifr_name, sock->dev, QSE_COUNTOF(ifr.ifr_name));
#else
msz = QSE_COUNTOF(ifr.ifr_name);
if (qse_wcstombs (sock->dev, &wsz, ifr.ifr_name, &msz) <= -1)
{
qse_upxd_seterrnum (upxd, QSE_UPXD_EINVAL);
syserr = 0;
goto oops;
}
#endif
if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, QSE_SIZEOF(ifr)) <= -1) goto oops;
#endif
}
flag = fcntl (fd, F_GETFL);
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
sock->handle.i = fd;
return 0;
oops:
if (syserr) qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
if (fd >= 0) close (fd);
return -1;
}
static void sock_close (qse_upxd_t* upxd, qse_upxd_sock_t* sock)
{
close (sock->handle.i);
}
static qse_ssize_t sock_recv (
qse_upxd_t* upxd, qse_upxd_sock_t* sock, void* buf, qse_size_t bufsize)
{
ssize_t ret;
struct sockaddr_storage addr;
socklen_t addrsize;
addrsize = QSE_SIZEOF(addr);
ret = recvfrom (sock->handle.i, buf, bufsize, 0, (struct sockaddr*)&addr, &addrsize);
if (ret <= -1) qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
else
{
if (sockaddr_to_nwad (&addr, &sock->from) <= -1)
{
qse_upxd_seterrnum (upxd, QSE_UPXD_ENOIMPL);
ret = -1;
}
}
return ret;
}
static qse_ssize_t sock_send (
qse_upxd_t* upxd, qse_upxd_sock_t* sock, const void* buf, qse_size_t bufsize)
{
struct sockaddr_storage addr;
int addrsize;
ssize_t ret;
addrsize = nwad_to_sockaddr (&sock->to, &addr);
if (addrsize <= -1)
{
qse_upxd_seterrnum (upxd, QSE_UPXD_ENOIMPL);
return -1;
}
ret = sendto (sock->handle.i, buf, bufsize,
0, (struct sockaddr*)&addr, addrsize);
if (ret <= -1) qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
return ret;
}
/* ------------------------------------------------------------------- */
static int session_config (
qse_upxd_t* upxd, qse_upxd_session_t* session)
{
/* you can check the source address (session->from).
* you can set the destination address.
* you can set the binding address.
* you can set the binding interface.
*/
qse_strtonwad (QSE_T("127.0.0.1:9991"), &session->config.peer);
qse_strtonwad (QSE_T("0.0.0.0:0"), &session->config.bind);
/*qse_strxcpy (session->config.dev, QSE_COUNTOF(session->config.dev), QSE_T("eth1"));*/
session->config.dormancy = 10000;
return 0;
}
static void session_error (
qse_upxd_t* upxd, qse_upxd_session_t* session)
{
if (session->server)
{
}
else
{
/* session->local.nwad is not associated with a session. */
}
qse_printf (QSE_T("ERROR IN SESSION COMMUNICATION\n"));
}
/* ------------------------------------------------------------------- */
struct mux_ev_t
{
qse_ubi_t handle;
int reqmask;
qse_upxd_muxcb_t cbfun;
void* cbarg;
};
struct mux_t
{
int fd;
struct
{
struct epoll_event* ptr;
qse_size_t len;
qse_size_t capa;
} ee;
struct
{
struct mux_ev_t** ptr;
qse_size_t capa;
} mev;
};
#define MUX_EV_ALIGN 64
static void* mux_open (qse_upxd_t* upxd)
{
struct mux_t* mux;
mux = qse_upxd_allocmem (upxd, QSE_SIZEOF(*mux));
if (mux == QSE_NULL) return QSE_NULL;
memset (mux, 0, QSE_SIZEOF(*mux));
#if defined(HAVE_EPOLL_CREATE1) && defined(O_CLOEXEC)
mux->fd = epoll_create1 (O_CLOEXEC);
#else
mux->fd = epoll_create (100);
#endif
if (mux->fd <= -1)
{
qse_upxd_freemem (upxd, mux);
qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
return QSE_NULL;
}
#if defined(HAVE_EPOLL_CREATE1) && defined(O_CLOEXEC)
/* nothing else to do */
#else
{
int flag = fcntl (mux->fd, F_GETFD);
if (flag >= 0) fcntl (mux->fd, F_SETFD, flag | FD_CLOEXEC);
}
#endif
return mux;
}
static void mux_close (qse_upxd_t* upxd, void* vmux)
{
struct mux_t* mux = (struct mux_t*)vmux;
if (mux->ee.ptr) qse_upxd_freemem (upxd, mux->ee.ptr);
if (mux->mev.ptr)
{
qse_size_t i;
for (i = 0; i < mux->mev.capa; i++)
if (mux->mev.ptr[i]) qse_upxd_freemem (upxd, mux->mev.ptr[i]);
qse_upxd_freemem (upxd, mux->mev.ptr);
}
close (mux->fd);
qse_upxd_freemem (upxd, mux);
}
static int mux_addhnd (
qse_upxd_t* upxd, void* vmux, qse_ubi_t handle,
qse_upxd_muxcb_t cbfun, void* cbarg)
{
struct mux_t* mux = (struct mux_t*)vmux;
struct epoll_event ev;
struct mux_ev_t* mev;
ev.events = EPOLLIN; /* inspect IN and HUP only */
if (handle.i >= mux->mev.capa)
{
struct mux_ev_t** tmp;
qse_size_t tmpcapa, i;
tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN);
tmp = (struct mux_ev_t**) qse_upxd_reallocmem (
upxd, mux->mev.ptr,
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa);
if (tmp == QSE_NULL) return -1;
for (i = mux->mev.capa; i < tmpcapa; i++) tmp[i] = QSE_NULL;
mux->mev.ptr = tmp;
mux->mev.capa = tmpcapa;
}
if (mux->mev.ptr[handle.i] == QSE_NULL)
{
/* the location of the data passed to epoll_ctl()
* must not change unless i update the info with epoll()
* whenever there is reallocation. so i simply
* make mux-mev.ptr reallocatable but auctual
* data fixed once allocated. */
mux->mev.ptr[handle.i] = qse_upxd_allocmem (
upxd, QSE_SIZEOF(*mux->mev.ptr[handle.i]));
if (mux->mev.ptr[handle.i] == QSE_NULL) return -1;
}
if (mux->ee.len >= mux->ee.capa)
{
struct epoll_event* tmp;
tmp = qse_upxd_reallocmem (
upxd, mux->ee.ptr,
QSE_SIZEOF(*mux->ee.ptr) * (mux->ee.capa + 1) * 2);
if (tmp == QSE_NULL) return -1;
mux->ee.ptr = tmp;
mux->ee.capa = (mux->ee.capa + 1) * 2;
}
mev = mux->mev.ptr[handle.i];
mev->handle = handle;
mev->cbfun = cbfun;
mev->cbarg = cbarg;
ev.data.ptr = mev;
if (epoll_ctl (mux->fd, EPOLL_CTL_ADD, handle.i, &ev) <= -1)
{
/* don't rollback ee.ptr */
qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
return -1;
}
mux->ee.len++;
return 0;
}
static int mux_delhnd (qse_upxd_t* upxd, void* vmux, qse_ubi_t handle)
{
struct mux_t* mux = (struct mux_t*)vmux;
if (epoll_ctl (mux->fd, EPOLL_CTL_DEL, handle.i, QSE_NULL) <= -1)
{
qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
return -1;
}
mux->ee.len--;
return 0;
}
static int mux_poll (qse_upxd_t* upxd, void* vmux, qse_ntime_t timeout)
{
struct mux_t* mux = (struct mux_t*)vmux;
struct mux_ev_t* mev;
int nfds, i;
nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout);
if (nfds <= -1)
{
qse_upxd_seterrnum (upxd, syserr_to_errnum(errno));
return -1;
}
for (i = 0; i < nfds; i++)
{
mev = mux->ee.ptr[i].data.ptr;
if (mux->ee.ptr[i].events & (EPOLLIN | EPOLLHUP))
mev->cbfun (upxd, mux, mev->handle, mev->cbarg);
}
return 0;
}
/* ------------------------------------------------------------------- */
void lock_acquire (qse_upxd_t* upxd)
{
}
void lock_release (qse_upxd_t* upxd)
{
}
/* ------------------------------------------------------------------- */
static qse_upxd_cbs_t upxd_cbs =
{
/* socket */
{ sock_open, sock_close, sock_recv, sock_send },
/* session */
{ session_config, session_error },
/* multiplexer */
{ mux_open, mux_close, mux_addhnd, mux_delhnd, mux_poll },
/* lock */
{ lock_acquire, lock_release }
};
static qse_upxd_t* g_upxd = QSE_NULL;
static void sigint (int sig)
{
if (g_upxd) qse_upxd_stop (g_upxd);
}
int upxd_main (int argc, qse_char_t* argv[])
{
qse_upxd_t* upxd = QSE_NULL;
int ret = -1, i;
if (argc <= 1)
{
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <server-address> ...\n"), argv[0]);
goto oops;
}
upxd = qse_upxd_open (QSE_MMGR_GETDFL(), 0);
if (upxd == QSE_NULL)
{
qse_fprintf (QSE_STDERR, QSE_T("Cannot open upxd\n"));
goto oops;
}
for (i = 1; i < argc; i++)
{
qse_nwad_t nwad;
if (qse_strtonwad (argv[i], &nwad) <= -1)
{
qse_fprintf (QSE_STDERR,
QSE_T("Wrong server - %s\n"), argv[i]);
goto oops;
}
if (qse_upxd_addserver (upxd, &nwad, QSE_NULL) == QSE_NULL)
{
qse_fprintf (QSE_STDERR,
QSE_T("Failed to add server - %s\n"), argv[i]);
goto oops;
}
}
g_upxd = upxd;
signal (SIGINT, sigint);
signal (SIGPIPE, SIG_IGN);
qse_upxd_setcbs (upxd, &upxd_cbs);
ret = qse_upxd_loop (upxd, 5000);
signal (SIGINT, SIG_DFL);
signal (SIGPIPE, SIG_DFL);
g_upxd = QSE_NULL;
if (ret <= -1)
qse_fprintf (QSE_STDERR, QSE_T("Error - %d\n"), (int)qse_upxd_geterrnum(upxd));
oops:
if (upxd) qse_upxd_close (upxd);
return ret;
}
int qse_main (int argc, qse_achar_t* argv[])
{
#if defined(_WIN32)
char locale[100];
UINT codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP (CP_UTF8);*/
qse_setdflcmgr (qse_utf8cmgr);
}
else
{
sprintf (locale, ".%u", (unsigned int)codepage);
setlocale (LC_ALL, locale);
qse_setdflcmgr (qse_slmbcmgr);
}
#else
setlocale (LC_ALL, "");
qse_setdflcmgr (qse_slmbcmgr);
#endif
return qse_runmain (argc, argv, upxd_main);
}