enhanced qse_upxd_t
This commit is contained in:
parent
ba24a28f16
commit
c60ca301c4
@ -298,7 +298,7 @@ qse_wchar_t* qse_mbsatowcsalldup (
|
|||||||
* n = qse_wcstombs (wcs, &wcslen, mbs, &mbslen);
|
* n = qse_wcstombs (wcs, &wcslen, mbs, &mbslen);
|
||||||
* if (n <= -1)
|
* if (n <= -1)
|
||||||
* {
|
* {
|
||||||
* // wcs fully scanned and mbs null-terminated
|
* // conversion error
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
|
@ -229,7 +229,7 @@ target_alias = @target_alias@
|
|||||||
top_build_prefix = @top_build_prefix@
|
top_build_prefix = @top_build_prefix@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
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
|
all: all-am
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
This file is part of QSE.
|
This file is part of QSE.
|
||||||
|
|
||||||
QSE is free software: you can redistribute it and/or modify
|
QSE is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as
|
it under the terms of the GNU Lesser General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
QSE is distributed in the hope that it will be useful,
|
QSE is distributed in the hope that it will be useful,
|
||||||
@ -14,7 +14,7 @@
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Lesser General Public License for more details.
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -23,65 +23,193 @@
|
|||||||
|
|
||||||
#include <qse/types.h>
|
#include <qse/types.h>
|
||||||
#include <qse/macros.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_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
|
enum qse_upxd_errnum_t
|
||||||
{
|
{
|
||||||
QSE_UPXD_ENOERR,
|
QSE_UPXD_ENOERR,
|
||||||
QSE_UPXD_ENOMEM,
|
QSE_UPXD_ENOMEM,
|
||||||
QSE_UPXD_EINVAL,
|
QSE_UPXD_EINVAL,
|
||||||
QSE_UPXD_EACCES,
|
QSE_UPXD_EACCES,
|
||||||
QSE_UPXD_ENOENT,
|
QSE_UPXD_ENOENT,
|
||||||
QSE_UPXD_EEXIST,
|
QSE_UPXD_EEXIST,
|
||||||
QSE_UPXD_EINTR,
|
QSE_UPXD_EINTR,
|
||||||
QSE_UPXD_EAGAIN,
|
QSE_UPXD_EAGAIN,
|
||||||
|
|
||||||
|
QSE_UPXD_EINTERN,
|
||||||
|
QSE_UPXD_ESYSERR,
|
||||||
QSE_UPXD_ENOIMPL,
|
QSE_UPXD_ENOIMPL,
|
||||||
QSE_UPXD_EOTHER
|
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_ubi_t handle;
|
||||||
/* ------------------------------ */
|
qse_nwad_t bind;
|
||||||
qse_nwad_t nwad;
|
const qse_char_t* dev;
|
||||||
qse_ubi_t handle;
|
qse_nwad_t from;
|
||||||
|
qse_nwad_t to;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qse_upxd_client_t
|
struct qse_upxd_session_t
|
||||||
{
|
{
|
||||||
qse_nwad_t remote_addr;
|
/** the server that this session belongs to */
|
||||||
qse_nwad_t local_addr;
|
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 qse_upxd_cbs_t
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int (*open) (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_server_t* server);
|
void (*close) (qse_upxd_t* upxd, qse_upxd_sock_t* server);
|
||||||
|
|
||||||
qse_ssize_t (*recv) (
|
qse_ssize_t (*recv) (
|
||||||
qse_upxd_t* upxd,
|
qse_upxd_t* upxd, qse_upxd_sock_t* server,
|
||||||
qse_upxd_client_t* client,
|
void* buf, qse_size_t bufsize);
|
||||||
qse_mchar_t* buf, qse_size_t bufsize);
|
|
||||||
|
|
||||||
qse_ssize_t (*send) (
|
qse_ssize_t (*send) (
|
||||||
qse_upxd_t* upxd,
|
qse_upxd_t* upxd, qse_upxd_sock_t* sock,
|
||||||
qse_upxd_client_t* client,
|
const void* buf, qse_size_t bufsize);
|
||||||
const qse_mchar_t* buf, qse_size_t bufsize);
|
} sock;
|
||||||
} server;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1753,7 +1753,7 @@ static qse_lda_walk_t walk_cands_for_match (
|
|||||||
{
|
{
|
||||||
int equal;
|
int equal;
|
||||||
|
|
||||||
equal =(e->rex->option & QSE_REX_IGNORECASE)?
|
equal = (e->rex->option & QSE_REX_IGNORECASE)?
|
||||||
(QSE_TOUPPER(node->u.c) == QSE_TOUPPER(*cand->mptr)):
|
(QSE_TOUPPER(node->u.c) == QSE_TOUPPER(*cand->mptr)):
|
||||||
(node->u.c == *cand->mptr) ;
|
(node->u.c == *cand->mptr) ;
|
||||||
|
|
||||||
|
@ -7,10 +7,11 @@ AM_CPPFLAGS = \
|
|||||||
|
|
||||||
lib_LTLIBRARIES = libqsenet.la
|
lib_LTLIBRARIES = libqsenet.la
|
||||||
libqsenet_la_SOURCES = \
|
libqsenet_la_SOURCES = \
|
||||||
|
httpd.h \
|
||||||
|
upxd.h \
|
||||||
http.c \
|
http.c \
|
||||||
htre.c \
|
htre.c \
|
||||||
htrd.c \
|
htrd.c \
|
||||||
httpd.h \
|
|
||||||
httpd.c \
|
httpd.c \
|
||||||
httpd-cgi.c \
|
httpd-cgi.c \
|
||||||
httpd-proxy.c \
|
httpd-proxy.c \
|
||||||
|
@ -79,7 +79,8 @@ am__installdirs = "$(DESTDIR)$(libdir)"
|
|||||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||||
libqsenet_la_DEPENDENCIES =
|
libqsenet_la_DEPENDENCIES =
|
||||||
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \
|
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_OBJECTS = $(am_libqsenet_la_OBJECTS)
|
||||||
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||||
@ -256,15 +257,17 @@ AM_CPPFLAGS = \
|
|||||||
|
|
||||||
lib_LTLIBRARIES = libqsenet.la
|
lib_LTLIBRARIES = libqsenet.la
|
||||||
libqsenet_la_SOURCES = \
|
libqsenet_la_SOURCES = \
|
||||||
|
httpd.h \
|
||||||
|
upxd.h \
|
||||||
http.c \
|
http.c \
|
||||||
htre.c \
|
htre.c \
|
||||||
htrd.c \
|
htrd.c \
|
||||||
httpd.h \
|
|
||||||
httpd.c \
|
httpd.c \
|
||||||
httpd-cgi.c \
|
httpd-cgi.c \
|
||||||
httpd-proxy.c \
|
httpd-proxy.c \
|
||||||
httpd-resol.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_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
||||||
libqsenet_la_LIBADD = -lqsecmn
|
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-resol.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-task.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)/httpd.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd.Plo@am__quote@
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
This file is part of QSE.
|
This file is part of QSE.
|
||||||
|
|
||||||
QSE is free software: you can redistribute it and/or modify
|
QSE is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as
|
it under the terms of the GNU Lesser General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
QSE is distributed in the hope that it will be useful,
|
QSE is distributed in the hope that it will be useful,
|
||||||
@ -14,11 +14,21 @@
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Lesser General Public License for more details.
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "upxd.h"
|
#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)
|
qse_upxd_t* qse_upxd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||||
{
|
{
|
||||||
@ -53,16 +63,11 @@ int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr)
|
|||||||
|
|
||||||
void qse_upxd_fini (qse_upxd_t* upxd)
|
void qse_upxd_fini (qse_upxd_t* upxd)
|
||||||
{
|
{
|
||||||
free_server_list (upxd, upxd->server.list);
|
QSE_ASSERTX (upxd->server.nactive == 0,
|
||||||
QSE_ASSERT (upxd->server.navail == 0);
|
"Deactivate all servers before destroying me");
|
||||||
upxd->server.list = QSE_NULL;
|
free_all_servers (upxd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qse_upxd_stop (qse_upxd_t* upxd)
|
|
||||||
{
|
|
||||||
upxd->stopreq = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qse_upxd_errnum_t qse_upxd_geterrnum (qse_upxd_t* upxd)
|
qse_upxd_errnum_t qse_upxd_geterrnum (qse_upxd_t* upxd)
|
||||||
{
|
{
|
||||||
return upxd->errnum;
|
return upxd->errnum;
|
||||||
@ -73,37 +78,461 @@ void qse_upxd_seterrnum (qse_upxd_t* upxd, qse_upxd_errnum_t errnum)
|
|||||||
upxd->errnum = 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_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));
|
server = QSE_MMGR_ALLOC (upxd->mmgr, QSE_SIZEOF(*server));
|
||||||
if (server == QSE_NULL)
|
if (server == QSE_NULL)
|
||||||
{
|
{
|
||||||
upxd->errnum = QSE_UPXD_ENOMEM;
|
upxd->errnum = QSE_UPXD_ENOMEM;
|
||||||
return -1;
|
return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSE_MEMSET (server, 0, QSE_SIZEOF(*server));
|
QSE_MEMSET (server, 0, QSE_SIZEOF(*server));
|
||||||
server->nwad = *nwad;
|
if (dev)
|
||||||
|
|
||||||
if (upxd->cbs->server.open (upxd, server) <= -1)
|
|
||||||
{
|
{
|
||||||
QSE_MMGR_FREE (upxd->mmgr, server);
|
qse_strxcpy (server->dev, QSE_COUNTOF(server->dev), dev);
|
||||||
return -1;
|
server->local.dev = server->dev;
|
||||||
}
|
}
|
||||||
|
server->local.bind = *nwad;
|
||||||
|
|
||||||
server->next = upxd->server.list;
|
upxd->cbs->lock.acquire (upxd);
|
||||||
|
server->next = upxd->server.list;
|
||||||
upxd->server.list = server;
|
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->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)
|
while (!upxd->stopreq)
|
||||||
{
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
count = upxd->cbs->mux.poll (upxd, upxd->mux, timeout);
|
||||||
|
if (count <= -1)
|
||||||
|
{
|
||||||
|
/* TODO: anything? */
|
||||||
|
}
|
||||||
|
|
||||||
|
upxd->cbs->lock.acquire (upxd);
|
||||||
|
purge_idle_sessions (upxd);
|
||||||
|
purge_deleted_servers (upxd);
|
||||||
|
activate_all_servers (upxd);
|
||||||
|
upxd->cbs->lock.release (upxd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
retv = 0;
|
||||||
|
|
||||||
|
oops:
|
||||||
|
if (upxd->server.nactive > 0) deactivate_all_servers (upxd);
|
||||||
|
if (upxd->mux) upxd->cbs->mux.close (upxd, upxd->mux);
|
||||||
|
return retv;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
This file is part of QSE.
|
This file is part of QSE.
|
||||||
|
|
||||||
QSE is free software: you can redistribute it and/or modify
|
QSE is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as
|
it under the terms of the GNU Lesser General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
QSE is distributed in the hope that it will be useful,
|
QSE is distributed in the hope that it will be useful,
|
||||||
@ -14,7 +14,7 @@
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Lesser General Public License for more details.
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
License along with QSE. If not, see <htrd://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -22,15 +22,80 @@
|
|||||||
#define _QSE_LIB_NET_UPXD_H_
|
#define _QSE_LIB_NET_UPXD_H_
|
||||||
|
|
||||||
#include <qse/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
|
struct qse_upxd_t
|
||||||
{
|
{
|
||||||
|
QSE_DEFINE_COMMON_FIELDS (upxd)
|
||||||
|
qse_upxd_errnum_t errnum;
|
||||||
|
|
||||||
int stopreq;
|
int stopreq;
|
||||||
|
qse_upxd_cbs_t* cbs;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_upxd_server_t* list;
|
qse_upxd_server_t* list;
|
||||||
|
qse_size_t nactive;
|
||||||
} server;
|
} 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
|
#endif
|
||||||
|
@ -5,7 +5,7 @@ AM_CPPFLAGS = \
|
|||||||
-I$(top_srcdir)/include \
|
-I$(top_srcdir)/include \
|
||||||
-I$(includedir)
|
-I$(includedir)
|
||||||
|
|
||||||
bin_PROGRAMS = http01
|
bin_PROGRAMS = http01 upxd01
|
||||||
|
|
||||||
LDFLAGS += -L../../lib/cmn -L../../lib/net
|
LDFLAGS += -L../../lib/cmn -L../../lib/net
|
||||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) -lssl
|
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) $(SENDFILE_LIBS) -lssl
|
||||||
@ -15,4 +15,5 @@ LDADD += $(UNICOWS_LIBS)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
http01_SOURCES = http01.c
|
http01_SOURCES = http01.c
|
||||||
|
upxd01_SOURCES = upxd01.c
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ PRE_UNINSTALL = :
|
|||||||
POST_UNINSTALL = :
|
POST_UNINSTALL = :
|
||||||
build_triplet = @build@
|
build_triplet = @build@
|
||||||
host_triplet = @host@
|
host_triplet = @host@
|
||||||
bin_PROGRAMS = http01$(EXEEXT)
|
bin_PROGRAMS = http01$(EXEEXT) upxd01$(EXEEXT)
|
||||||
@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
|
||||||
subdir = samples/net
|
subdir = samples/net
|
||||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||||
@ -59,6 +59,11 @@ am__DEPENDENCIES_1 =
|
|||||||
@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
@WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
||||||
http01_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
http01_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
|
$(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 =
|
DEFAULT_INCLUDES =
|
||||||
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
|
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
|
||||||
am__depfiles_maybe = depfiles
|
am__depfiles_maybe = depfiles
|
||||||
@ -72,8 +77,8 @@ CCLD = $(CC)
|
|||||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||||
$(LDFLAGS) -o $@
|
$(LDFLAGS) -o $@
|
||||||
SOURCES = $(http01_SOURCES)
|
SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
||||||
DIST_SOURCES = $(http01_SOURCES)
|
DIST_SOURCES = $(http01_SOURCES) $(upxd01_SOURCES)
|
||||||
ETAGS = etags
|
ETAGS = etags
|
||||||
CTAGS = ctags
|
CTAGS = ctags
|
||||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||||
@ -232,6 +237,7 @@ AM_CPPFLAGS = \
|
|||||||
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
|
LDADD = -lqsenet -lqsecmn $(PTHREAD_LIBS) $(SOCKET_LIBS) \
|
||||||
$(SENDFILE_LIBS) -lssl $(am__append_1)
|
$(SENDFILE_LIBS) -lssl $(am__append_1)
|
||||||
http01_SOURCES = http01.c
|
http01_SOURCES = http01.c
|
||||||
|
upxd01_SOURCES = upxd01.c
|
||||||
all: all-am
|
all: all-am
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
@ -312,6 +318,9 @@ clean-binPROGRAMS:
|
|||||||
http01$(EXEEXT): $(http01_OBJECTS) $(http01_DEPENDENCIES) $(EXTRA_http01_DEPENDENCIES)
|
http01$(EXEEXT): $(http01_OBJECTS) $(http01_DEPENDENCIES) $(EXTRA_http01_DEPENDENCIES)
|
||||||
@rm -f http01$(EXEEXT)
|
@rm -f http01$(EXEEXT)
|
||||||
$(LINK) $(http01_OBJECTS) $(http01_LDADD) $(LIBS)
|
$(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:
|
mostlyclean-compile:
|
||||||
-rm -f *.$(OBJEXT)
|
-rm -f *.$(OBJEXT)
|
||||||
@ -320,6 +329,7 @@ distclean-compile:
|
|||||||
-rm -f *.tab.c
|
-rm -f *.tab.c
|
||||||
|
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http01.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http01.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd01.Po@am__quote@
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#if defined(_WIN32)
|
|
||||||
|
#if defined(_WIN32)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#else
|
#else
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
@ -71,7 +72,7 @@ static qse_ssize_t xsendfile (
|
|||||||
vec.sfv_flag = 0;
|
vec.sfv_flag = 0;
|
||||||
if (offset)
|
if (offset)
|
||||||
{
|
{
|
||||||
vec.sfv_off = *offset;
|
vec.sfv_off = *offset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -154,7 +155,7 @@ static qse_httpd_errnum_t syserr_to_errnum (int e)
|
|||||||
|
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
return QSE_HTTPD_EEXIST;
|
return QSE_HTTPD_EEXIST;
|
||||||
|
|
||||||
case EINTR:
|
case EINTR:
|
||||||
return QSE_HTTPD_EINTR;
|
return QSE_HTTPD_EINTR;
|
||||||
|
|
||||||
@ -177,8 +178,8 @@ struct httpd_xtn_t
|
|||||||
/* ------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int init_xtn_ssl (
|
static int init_xtn_ssl (
|
||||||
httpd_xtn_t* xtn,
|
httpd_xtn_t* xtn,
|
||||||
const qse_mchar_t* pemfile,
|
const qse_mchar_t* pemfile,
|
||||||
const qse_mchar_t* keyfile/*,
|
const qse_mchar_t* keyfile/*,
|
||||||
const qse_mchar_t* chainfile*/)
|
const qse_mchar_t* chainfile*/)
|
||||||
{
|
{
|
||||||
@ -195,7 +196,7 @@ static int init_xtn_ssl (
|
|||||||
|
|
||||||
if (SSL_CTX_use_certificate_file (ctx, pemfile, SSL_FILETYPE_PEM) == 0 ||
|
if (SSL_CTX_use_certificate_file (ctx, pemfile, SSL_FILETYPE_PEM) == 0 ||
|
||||||
SSL_CTX_use_PrivateKey_file (ctx, keyfile, SSL_FILETYPE_PEM) == 0 ||
|
SSL_CTX_use_PrivateKey_file (ctx, keyfile, SSL_FILETYPE_PEM) == 0 ||
|
||||||
SSL_CTX_check_private_key (ctx) == 0 /*||
|
SSL_CTX_check_private_key (ctx) == 0 /*||
|
||||||
SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/)
|
SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/)
|
||||||
{
|
{
|
||||||
qse_mchar_t buf[128];
|
qse_mchar_t buf[128];
|
||||||
@ -240,7 +241,7 @@ static int sockaddr_to_nwad (
|
|||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
{
|
{
|
||||||
struct sockaddr_in* in;
|
struct sockaddr_in* in;
|
||||||
in = (struct sockaddr_in*)addr;
|
in = (struct sockaddr_in*)addr;
|
||||||
addrsize = QSE_SIZEOF(*in);
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ static int sockaddr_to_nwad (
|
|||||||
#if defined(AF_INET6)
|
#if defined(AF_INET6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
{
|
{
|
||||||
struct sockaddr_in6* in;
|
struct sockaddr_in6* in;
|
||||||
in = (struct sockaddr_in6*)addr;
|
in = (struct sockaddr_in6*)addr;
|
||||||
addrsize = QSE_SIZEOF(*in);
|
addrsize = QSE_SIZEOF(*in);
|
||||||
|
|
||||||
@ -280,7 +281,7 @@ static int nwad_to_sockaddr (
|
|||||||
{
|
{
|
||||||
case QSE_NWAD_IN4:
|
case QSE_NWAD_IN4:
|
||||||
{
|
{
|
||||||
struct sockaddr_in* in;
|
struct sockaddr_in* in;
|
||||||
|
|
||||||
in = (struct sockaddr_in*)addr;
|
in = (struct sockaddr_in*)addr;
|
||||||
addrsize = QSE_SIZEOF(*in);
|
addrsize = QSE_SIZEOF(*in);
|
||||||
@ -295,7 +296,7 @@ static int nwad_to_sockaddr (
|
|||||||
case QSE_NWAD_IN6:
|
case QSE_NWAD_IN6:
|
||||||
{
|
{
|
||||||
#if defined(AF_INET6)
|
#if defined(AF_INET6)
|
||||||
struct sockaddr_in6* in;
|
struct sockaddr_in6* in;
|
||||||
|
|
||||||
in = (struct sockaddr_in6*)addr;
|
in = (struct sockaddr_in6*)addr;
|
||||||
addrsize = QSE_SIZEOF(*in);
|
addrsize = QSE_SIZEOF(*in);
|
||||||
@ -345,10 +346,10 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
|||||||
setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag));
|
setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the
|
/* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the
|
||||||
* address size for AF_INET. */
|
* address size for AF_INET. */
|
||||||
/*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/
|
/*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/
|
||||||
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)
|
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)
|
||||||
{
|
{
|
||||||
#if defined(IPV6_V6ONLY)
|
#if defined(IPV6_V6ONLY)
|
||||||
if (errno == EADDRINUSE && addr.ss_family == AF_INET6)
|
if (errno == EADDRINUSE && addr.ss_family == AF_INET6)
|
||||||
@ -382,7 +383,7 @@ static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int server_accept (
|
static int server_accept (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_server_t* server, qse_httpd_client_t* client)
|
qse_httpd_server_t* server, qse_httpd_client_t* client)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
@ -396,7 +397,7 @@ static int server_accept (
|
|||||||
|
|
||||||
addrlen = QSE_SIZEOF(addr);
|
addrlen = QSE_SIZEOF(addr);
|
||||||
fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen);
|
fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen);
|
||||||
if (fd <= -1)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum (errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum (errno));
|
||||||
return -1;
|
return -1;
|
||||||
@ -472,7 +473,7 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
|||||||
flag = fcntl (fd, F_GETFL);
|
flag = fcntl (fd, F_GETFL);
|
||||||
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
|
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
|
||||||
|
|
||||||
if (connect (fd, (struct sockaddr*)&addr, addrsize) <= -1)
|
if (connect (fd, (struct sockaddr*)&addr, addrsize) <= -1)
|
||||||
{
|
{
|
||||||
if (errno != EINPROGRESS) goto oops;
|
if (errno != EINPROGRESS) goto oops;
|
||||||
connected = 0;
|
connected = 0;
|
||||||
@ -508,7 +509,7 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
|||||||
if (getsockopt (peer->handle.i, SOL_SOCKET, SO_ERROR, &ret, &len) <= -1) return -1;
|
if (getsockopt (peer->handle.i, SOL_SOCKET, SO_ERROR, &ret, &len) <= -1) return -1;
|
||||||
|
|
||||||
if (ret == EINPROGRESS) return 0;
|
if (ret == EINPROGRESS) return 0;
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum (ret));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum (ret));
|
||||||
return -1;
|
return -1;
|
||||||
@ -552,7 +553,7 @@ struct mux_t
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
struct epoll_event* ptr;
|
struct epoll_event* ptr;
|
||||||
qse_size_t len;
|
qse_size_t len;
|
||||||
qse_size_t capa;
|
qse_size_t capa;
|
||||||
} ee;
|
} ee;
|
||||||
|
|
||||||
@ -579,7 +580,7 @@ static void* mux_open (qse_httpd_t* httpd)
|
|||||||
#else
|
#else
|
||||||
mux->fd = epoll_create (100);
|
mux->fd = epoll_create (100);
|
||||||
#endif
|
#endif
|
||||||
if (mux->fd <= -1)
|
if (mux->fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_freemem (httpd, mux);
|
qse_httpd_freemem (httpd, mux);
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
@ -602,7 +603,7 @@ static void mux_close (qse_httpd_t* httpd, void* vmux)
|
|||||||
{
|
{
|
||||||
struct mux_t* mux = (struct mux_t*)vmux;
|
struct mux_t* mux = (struct mux_t*)vmux;
|
||||||
if (mux->ee.ptr) qse_httpd_freemem (httpd, mux->ee.ptr);
|
if (mux->ee.ptr) qse_httpd_freemem (httpd, mux->ee.ptr);
|
||||||
if (mux->mev.ptr)
|
if (mux->mev.ptr)
|
||||||
{
|
{
|
||||||
qse_size_t i;
|
qse_size_t i;
|
||||||
for (i = 0; i < mux->mev.capa; i++)
|
for (i = 0; i < mux->mev.capa; i++)
|
||||||
@ -614,7 +615,7 @@ static void mux_close (qse_httpd_t* httpd, void* vmux)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int mux_addhnd (
|
static int mux_addhnd (
|
||||||
qse_httpd_t* httpd, void* vmux, qse_ubi_t handle,
|
qse_httpd_t* httpd, void* vmux, qse_ubi_t handle,
|
||||||
int mask, qse_httpd_muxcb_t cbfun, void* cbarg)
|
int mask, qse_httpd_muxcb_t cbfun, void* cbarg)
|
||||||
{
|
{
|
||||||
struct mux_t* mux = (struct mux_t*)vmux;
|
struct mux_t* mux = (struct mux_t*)vmux;
|
||||||
@ -635,12 +636,12 @@ static int mux_addhnd (
|
|||||||
{
|
{
|
||||||
struct mux_ev_t** tmp;
|
struct mux_ev_t** tmp;
|
||||||
qse_size_t tmpcapa, i;
|
qse_size_t tmpcapa, i;
|
||||||
|
|
||||||
tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN);
|
tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN);
|
||||||
|
|
||||||
tmp = (struct mux_ev_t**) qse_httpd_reallocmem (
|
tmp = (struct mux_ev_t**) qse_httpd_reallocmem (
|
||||||
httpd, mux->mev.ptr,
|
httpd, mux->mev.ptr,
|
||||||
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa);
|
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa);
|
||||||
if (tmp == QSE_NULL) return -1;
|
if (tmp == QSE_NULL) return -1;
|
||||||
|
|
||||||
for (i = mux->mev.capa; i < tmpcapa; i++) tmp[i] = QSE_NULL;
|
for (i = mux->mev.capa; i < tmpcapa; i++) tmp[i] = QSE_NULL;
|
||||||
@ -648,7 +649,7 @@ static int mux_addhnd (
|
|||||||
mux->mev.capa = tmpcapa;
|
mux->mev.capa = tmpcapa;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mux->mev.ptr[handle.i] == QSE_NULL)
|
if (mux->mev.ptr[handle.i] == QSE_NULL)
|
||||||
{
|
{
|
||||||
/* the location of the data passed to epoll_ctl()
|
/* the location of the data passed to epoll_ctl()
|
||||||
* must not change unless i update the info with epoll()
|
* must not change unless i update the info with epoll()
|
||||||
@ -658,14 +659,14 @@ static int mux_addhnd (
|
|||||||
mux->mev.ptr[handle.i] = qse_httpd_allocmem (
|
mux->mev.ptr[handle.i] = qse_httpd_allocmem (
|
||||||
httpd, QSE_SIZEOF(*mux->mev.ptr[handle.i]));
|
httpd, QSE_SIZEOF(*mux->mev.ptr[handle.i]));
|
||||||
if (mux->mev.ptr[handle.i] == QSE_NULL) return -1;
|
if (mux->mev.ptr[handle.i] == QSE_NULL) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mux->ee.len >= mux->ee.capa)
|
if (mux->ee.len >= mux->ee.capa)
|
||||||
{
|
{
|
||||||
struct epoll_event* tmp;
|
struct epoll_event* tmp;
|
||||||
|
|
||||||
tmp = qse_httpd_reallocmem (
|
tmp = qse_httpd_reallocmem (
|
||||||
httpd, mux->ee.ptr,
|
httpd, mux->ee.ptr,
|
||||||
QSE_SIZEOF(*mux->ee.ptr) * (mux->ee.capa + 1) * 2);
|
QSE_SIZEOF(*mux->ee.ptr) * (mux->ee.capa + 1) * 2);
|
||||||
if (tmp == QSE_NULL) return -1;
|
if (tmp == QSE_NULL) return -1;
|
||||||
|
|
||||||
@ -725,14 +726,14 @@ static int mux_poll (qse_httpd_t* httpd, void* vmux, qse_ntime_t timeout)
|
|||||||
|
|
||||||
mask = 0;
|
mask = 0;
|
||||||
|
|
||||||
if (mux->ee.ptr[i].events & EPOLLIN)
|
if (mux->ee.ptr[i].events & EPOLLIN)
|
||||||
mask |= QSE_HTTPD_MUX_READ;
|
mask |= QSE_HTTPD_MUX_READ;
|
||||||
if (mux->ee.ptr[i].events & EPOLLOUT)
|
if (mux->ee.ptr[i].events & EPOLLOUT)
|
||||||
mask |= QSE_HTTPD_MUX_WRITE;
|
mask |= QSE_HTTPD_MUX_WRITE;
|
||||||
|
|
||||||
if (mux->ee.ptr[i].events & EPOLLHUP)
|
if (mux->ee.ptr[i].events & EPOLLHUP)
|
||||||
{
|
{
|
||||||
if (mev->reqmask & QSE_HTTPD_MUX_READ)
|
if (mev->reqmask & QSE_HTTPD_MUX_READ)
|
||||||
mask |= QSE_HTTPD_MUX_READ;
|
mask |= QSE_HTTPD_MUX_READ;
|
||||||
if (mev->reqmask & QSE_HTTPD_MUX_WRITE)
|
if (mev->reqmask & QSE_HTTPD_MUX_WRITE)
|
||||||
mask |= QSE_HTTPD_MUX_WRITE;
|
mask |= QSE_HTTPD_MUX_WRITE;
|
||||||
@ -759,7 +760,7 @@ static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
|||||||
FD_ZERO (&r);
|
FD_ZERO (&r);
|
||||||
FD_SET (handle.i, &r);
|
FD_SET (handle.i, &r);
|
||||||
|
|
||||||
return select (handle.i + 1, &r, QSE_NULL, QSE_NULL, tvp);
|
return select (handle.i + 1, &r, QSE_NULL, QSE_NULL, tvp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
|
||||||
@ -800,9 +801,9 @@ static int file_stat (
|
|||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stating for a file. it should be a regular file.
|
/* stating for a file. it should be a regular file.
|
||||||
* i don't allow other file types. */
|
* i don't allow other file types. */
|
||||||
if (!S_ISREG(st.st_mode))
|
if (!S_ISREG(st.st_mode))
|
||||||
{
|
{
|
||||||
@ -842,7 +843,7 @@ static int file_ropen (
|
|||||||
|
|
||||||
qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
|
qse_printf (QSE_T("opening file [%hs] for reading\n"), path);
|
||||||
fd = open (path, flags, 0);
|
fd = open (path, flags, 0);
|
||||||
if (fd <= -1)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@ -857,7 +858,7 @@ qse_printf (QSE_T("opened file %hs\n"), path);
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int file_wopen (
|
static int file_wopen (
|
||||||
qse_httpd_t* httpd, const qse_mchar_t* path,
|
qse_httpd_t* httpd, const qse_mchar_t* path,
|
||||||
qse_ubi_t* handle)
|
qse_ubi_t* handle)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
@ -870,7 +871,7 @@ static int file_wopen (
|
|||||||
|
|
||||||
qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
qse_printf (QSE_T("opening file [%hs] for writing\n"), path);
|
||||||
fd = open (path, flags, 0644);
|
fd = open (path, flags, 0644);
|
||||||
if (fd <= -1)
|
if (fd <= -1)
|
||||||
{
|
{
|
||||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@ -887,14 +888,14 @@ qse_printf (QSE_T("closing file %d\n"), handle.i);
|
|||||||
}
|
}
|
||||||
|
|
||||||
static qse_ssize_t file_read (
|
static qse_ssize_t file_read (
|
||||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||||
qse_mchar_t* buf, qse_size_t len)
|
qse_mchar_t* buf, qse_size_t len)
|
||||||
{
|
{
|
||||||
return read (handle.i, buf, len);
|
return read (handle.i, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_ssize_t file_write (
|
static qse_ssize_t file_write (
|
||||||
qse_httpd_t* httpd, qse_ubi_t handle,
|
qse_httpd_t* httpd, qse_ubi_t handle,
|
||||||
const qse_mchar_t* buf, qse_size_t len)
|
const qse_mchar_t* buf, qse_size_t len)
|
||||||
{
|
{
|
||||||
return write (handle.i, buf, len);
|
return write (handle.i, buf, len);
|
||||||
@ -916,7 +917,7 @@ static void client_shutdown (
|
|||||||
shutdown (client->handle.i, 2);
|
shutdown (client->handle.i, 2);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static qse_ssize_t client_recv (
|
static qse_ssize_t client_recv (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_mchar_t* buf, qse_size_t bufsize)
|
qse_mchar_t* buf, qse_size_t bufsize)
|
||||||
@ -926,7 +927,7 @@ static qse_ssize_t client_recv (
|
|||||||
int ret = SSL_read (client->handle2.ptr, buf, bufsize);
|
int ret = SSL_read (client->handle2.ptr, buf, bufsize);
|
||||||
if (ret <= -1)
|
if (ret <= -1)
|
||||||
{
|
{
|
||||||
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_READ)
|
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_READ)
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
||||||
else
|
else
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||||
@ -950,7 +951,7 @@ static qse_ssize_t client_send (
|
|||||||
int ret = SSL_write (client->handle2.ptr, buf, bufsize);
|
int ret = SSL_write (client->handle2.ptr, buf, bufsize);
|
||||||
if (ret <= -1)
|
if (ret <= -1)
|
||||||
{
|
{
|
||||||
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_WRITE)
|
if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_WRITE)
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN);
|
||||||
else
|
else
|
||||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||||
@ -1003,7 +1004,7 @@ qse_printf (QSE_T("SSL ACCEPTING %d\n"), client->handle.i);
|
|||||||
qse_fflush (QSE_STDOUT);
|
qse_fflush (QSE_STDOUT);
|
||||||
if (SSL_set_fd (ssl, client->handle.i) == 0)
|
if (SSL_set_fd (ssl, client->handle.i) == 0)
|
||||||
{
|
{
|
||||||
/* don't free ssl here since client_closed()
|
/* don't free ssl here since client_closed()
|
||||||
* will be closed */
|
* will be closed */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1012,7 +1013,7 @@ qse_fflush (QSE_STDOUT);
|
|||||||
ret = SSL_accept (ssl);
|
ret = SSL_accept (ssl);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
if (SSL_get_error(ssl,ret) == SSL_ERROR_WANT_READ)
|
if (SSL_get_error(ssl,ret) == SSL_ERROR_WANT_READ)
|
||||||
{
|
{
|
||||||
/* handshaking isn't complete. */
|
/* handshaking isn't complete. */
|
||||||
return 0;
|
return 0;
|
||||||
@ -1054,7 +1055,7 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int process_request (
|
static int process_request (
|
||||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||||
qse_htre_t* req, int peek)
|
qse_htre_t* req, int peek)
|
||||||
{
|
{
|
||||||
int method;
|
int method;
|
||||||
@ -1065,12 +1066,12 @@ static int process_request (
|
|||||||
content_received = (qse_htre_getcontentlen(req) > 0);
|
content_received = (qse_htre_getcontentlen(req) > 0);
|
||||||
|
|
||||||
/* percent-decode the query path to the original buffer
|
/* percent-decode the query path to the original buffer
|
||||||
* since i'm not gonna need it in the original form
|
* since i'm not gonna need it in the original form
|
||||||
* any more */
|
* any more */
|
||||||
qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req));
|
||||||
|
|
||||||
qse_printf (QSE_T("================================\n"));
|
qse_printf (QSE_T("================================\n"));
|
||||||
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
|
qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"),
|
||||||
(unsigned long)time(NULL),
|
(unsigned long)time(NULL),
|
||||||
(peek? QSE_MT("PEEK"): QSE_MT("HANDLE")),
|
(peek? QSE_MT("PEEK"): QSE_MT("HANDLE")),
|
||||||
qse_htre_getqpath(req),
|
qse_htre_getqpath(req),
|
||||||
@ -1079,11 +1080,11 @@ qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"
|
|||||||
qse_htre_getverstr(req),
|
qse_htre_getverstr(req),
|
||||||
qse_htre_getqmethodname(req)
|
qse_htre_getqmethodname(req)
|
||||||
);
|
);
|
||||||
if (qse_htre_getqparam(req))
|
if (qse_htre_getqparam(req))
|
||||||
qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparam(req));
|
qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparam(req));
|
||||||
|
|
||||||
qse_htb_walk (&req->hdrtab, walk, QSE_NULL);
|
qse_htb_walk (&req->hdrtab, walk, QSE_NULL);
|
||||||
if (qse_htre_getcontentlen(req) > 0)
|
if (qse_htre_getcontentlen(req) > 0)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("CONTENT before discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
|
qse_printf (QSE_T("CONTENT before discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
|
||||||
}
|
}
|
||||||
@ -1091,21 +1092,21 @@ if (qse_htre_getcontentlen(req) > 0)
|
|||||||
if (peek)
|
if (peek)
|
||||||
{
|
{
|
||||||
if (method != QSE_HTTP_POST && method != QSE_HTTP_PUT)
|
if (method != QSE_HTTP_POST && method != QSE_HTTP_PUT)
|
||||||
{
|
{
|
||||||
/* i'll discard request contents if the method is none of
|
/* i'll discard request contents if the method is none of
|
||||||
* post and put */
|
* post and put */
|
||||||
qse_httpd_discardcontent (httpd, req);
|
qse_httpd_discardcontent (httpd, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
|
if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
|
||||||
(req->version.major > 1 ||
|
(req->version.major > 1 ||
|
||||||
(req->version.major == 1 && req->version.minor >= 1)) &&
|
(req->version.major == 1 && req->version.minor >= 1)) &&
|
||||||
!content_received)
|
!content_received)
|
||||||
{
|
{
|
||||||
/* TODO: check method.... */
|
/* TODO: check method.... */
|
||||||
/* "expect" in the header, version 1.1 or higher,
|
/* "expect" in the header, version 1.1 or higher,
|
||||||
* and no content received yet */
|
* and no content received yet */
|
||||||
|
|
||||||
/* TODO: determine if to return 100-continue or other errors */
|
/* TODO: determine if to return 100-continue or other errors */
|
||||||
{
|
{
|
||||||
qse_ntime_t now;
|
qse_ntime_t now;
|
||||||
@ -1117,7 +1118,7 @@ qse_printf (QSE_T("entasking continue at %lld\n"), (long long)now);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qse_htre_getcontentlen(req) > 0)
|
if (qse_htre_getcontentlen(req) > 0)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("CONTENT after discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
|
qse_printf (QSE_T("CONTENT after discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
|
||||||
}
|
}
|
||||||
@ -1144,11 +1145,11 @@ qse_printf (QSE_T("chunked cgi... delaying until contents are received\n"));
|
|||||||
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))*/
|
/*if (method == QSE_HTTP_POST && !(req->attr.flags & QSE_HTRE_ATTR_LENGTH))*/
|
||||||
if (method == QSE_HTTP_POST &&
|
if (method == QSE_HTTP_POST &&
|
||||||
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
!(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
||||||
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
!(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
|
||||||
{
|
{
|
||||||
@ -1191,7 +1192,7 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
|
|||||||
auth = qse_htre_getheaderval (req, QSE_MT("Authorization"));
|
auth = qse_htre_getheaderval (req, QSE_MT("Authorization"));
|
||||||
if (auth)
|
if (auth)
|
||||||
{
|
{
|
||||||
/* TODO: PERFORM authorization... */
|
/* TODO: PERFORM authorization... */
|
||||||
/* BASE64 decode... */
|
/* BASE64 decode... */
|
||||||
while (auth->next) auth = auth->next;
|
while (auth->next) auth = auth->next;
|
||||||
authorized = 1;
|
authorized = 1;
|
||||||
@ -1276,7 +1277,7 @@ qse_printf (QSE_T("Host not included....\n"));
|
|||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const qse_mchar_t* host;
|
const qse_mchar_t* host;
|
||||||
qse_parseuri ();
|
qse_parseuri ();
|
||||||
@ -1287,15 +1288,15 @@ qse_printf (QSE_T("Host not included....\n"));
|
|||||||
#if 0
|
#if 0
|
||||||
if (peek)
|
if (peek)
|
||||||
{
|
{
|
||||||
if (req->attr.expect &&
|
if (req->attr.expect &&
|
||||||
(req->version.major > 1 ||
|
(req->version.major > 1 ||
|
||||||
(req->version.major == 1 && req->version.minor >= 1)) &&
|
(req->version.major == 1 && req->version.minor >= 1)) &&
|
||||||
!content_received)
|
!content_received)
|
||||||
{
|
{
|
||||||
/* TODO: check method.... */
|
/* TODO: check method.... */
|
||||||
/* "expect" in the header, version 1.1 or higher,
|
/* "expect" in the header, version 1.1 or higher,
|
||||||
* and no content received yet */
|
* and no content received yet */
|
||||||
|
|
||||||
if (qse_mbscasecmp(req->attr.expect, QSE_MT("100-continue")) != 0)
|
if (qse_mbscasecmp(req->attr.expect, QSE_MT("100-continue")) != 0)
|
||||||
{
|
{
|
||||||
if (qse_httpd_entaskerror (
|
if (qse_httpd_entaskerror (
|
||||||
@ -1385,7 +1386,7 @@ static qse_httpd_cbs_t httpd_cbs =
|
|||||||
/* server */
|
/* server */
|
||||||
{ server_open, server_close, server_accept },
|
{ server_open, server_close, server_accept },
|
||||||
|
|
||||||
{ peer_open,
|
{ peer_open,
|
||||||
peer_close,
|
peer_close,
|
||||||
peer_connected,
|
peer_connected,
|
||||||
peer_recv,
|
peer_recv,
|
||||||
@ -1397,9 +1398,9 @@ static qse_httpd_cbs_t httpd_cbs =
|
|||||||
mux_addhnd,
|
mux_addhnd,
|
||||||
mux_delhnd,
|
mux_delhnd,
|
||||||
mux_poll,
|
mux_poll,
|
||||||
|
|
||||||
mux_readable,
|
mux_readable,
|
||||||
mux_writable
|
mux_writable
|
||||||
},
|
},
|
||||||
|
|
||||||
/* file operation */
|
/* file operation */
|
||||||
@ -1414,11 +1415,11 @@ static qse_httpd_cbs_t httpd_cbs =
|
|||||||
|
|
||||||
/* client connection */
|
/* client connection */
|
||||||
{ client_close,
|
{ client_close,
|
||||||
client_shutdown,
|
client_shutdown,
|
||||||
client_recv,
|
client_recv,
|
||||||
client_send,
|
client_send,
|
||||||
client_sendfile,
|
client_sendfile,
|
||||||
client_accepted,
|
client_accepted,
|
||||||
client_closed },
|
client_closed },
|
||||||
|
|
||||||
/* http request */
|
/* http request */
|
||||||
@ -1468,7 +1469,7 @@ int httpd_main (int argc, qse_char_t* argv[])
|
|||||||
{
|
{
|
||||||
if (qse_httpd_addserver (httpd, argv[i]) <= -1)
|
if (qse_httpd_addserver (httpd, argv[i]) <= -1)
|
||||||
{
|
{
|
||||||
qse_fprintf (QSE_STDERR,
|
qse_fprintf (QSE_STDERR,
|
||||||
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
QSE_T("Failed to add httpd listener - %s\n"), argv[i]);
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
@ -1497,7 +1498,7 @@ int qse_main (int argc, qse_achar_t* argv[])
|
|||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
char locale[100];
|
char locale[100];
|
||||||
UINT codepage = GetConsoleOutputCP();
|
UINT codepage = GetConsoleOutputCP();
|
||||||
if (codepage == CP_UTF8)
|
if (codepage == CP_UTF8)
|
||||||
{
|
{
|
||||||
/*SetConsoleOUtputCP (CP_UTF8);*/
|
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||||
|
598
qse/samples/net/upxd01.c
Normal file
598
qse/samples/net/upxd01.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user