From b330d2c350fdc60874c755fddcf05b0c330177c7 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 13 Feb 2012 14:43:50 +0000 Subject: [PATCH] added hton,ntoh renamed qse_getcmgrbyname() to qse_findcmgr() added qse_setcmgrfinder()/qse_getcmgrfinder() started adding ipad,nwad --- qse/cmd/awk/awk.c | 4 +- qse/include/qse/cmn/Makefile.am | 3 + qse/include/qse/cmn/Makefile.in | 15 +- qse/include/qse/cmn/hton.h | 75 +++++ qse/include/qse/cmn/ipad.h | 66 ++++ qse/include/qse/cmn/mbwc.h | 14 +- qse/include/qse/cmn/nwad.h | 52 +++ qse/include/qse/net/httpd.h | 29 +- qse/lib/awk/StdAwk.cpp | 2 +- qse/lib/awk/std.c | 8 +- qse/lib/cmn/Makefile.am | 3 + qse/lib/cmn/Makefile.in | 30 +- qse/lib/cmn/hton.c | 203 +++++++++++ qse/lib/cmn/ipad.c | 573 ++++++++++++++++++++++++++++++++ qse/lib/cmn/mbwc.c | 27 +- qse/lib/cmn/nwad.c | 37 +++ qse/lib/cmn/pio.c | 168 ++++++---- qse/lib/net/httpd_task.c | 343 +++---------------- qse/samples/net/http01.c | 88 ++--- 19 files changed, 1309 insertions(+), 431 deletions(-) create mode 100644 qse/include/qse/cmn/hton.h create mode 100644 qse/include/qse/cmn/ipad.h create mode 100644 qse/include/qse/cmn/nwad.h create mode 100644 qse/lib/cmn/hton.c create mode 100644 qse/lib/cmn/ipad.c create mode 100644 qse/lib/cmn/nwad.c diff --git a/qse/cmd/awk/awk.c b/qse/cmd/awk/awk.c index b8650450..72a42fb7 100644 --- a/qse/cmd/awk/awk.c +++ b/qse/cmd/awk/awk.c @@ -651,7 +651,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg) if (qse_strcmp(opt.lngopt, QSE_T("script-encoding")) == 0) { - arg->script_cmgr = qse_getcmgrbyname (opt.arg); + arg->script_cmgr = qse_findcmgr (opt.arg); if (arg->script_cmgr == QSE_NULL) { print_err (QSE_T("unknown script encoding - %s\n"), opt.arg); @@ -660,7 +660,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg) } else if (qse_strcmp(opt.lngopt, QSE_T("console-encoding")) == 0) { - arg->console_cmgr = qse_getcmgrbyname (opt.arg); + arg->console_cmgr = qse_findcmgr (opt.arg); if (arg->console_cmgr == QSE_NULL) { print_err (QSE_T("unknown console encoding - %s\n"), opt.arg); diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index a4b1112e..38754dbe 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -11,11 +11,14 @@ pkginclude_HEADERS = \ fs.h \ gdl.h \ htb.h \ + hton.h \ + ipad.h \ lda.h \ main.h \ map.h \ mbwc.h \ mem.h \ + nwad.h \ oht.h \ opt.h \ path.h \ diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 5c00051d..de425273 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -52,10 +52,10 @@ CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__pkginclude_HEADERS_DIST = alg.h chr.h dll.h env.h fio.h fma.h \ - fmt.h fs.h gdl.h htb.h lda.h main.h map.h mbwc.h mem.h oht.h \ - opt.h path.h pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h \ - stdio.h str.h time.h tio.h tre.h utf8.h xma.h Mmgr.hpp \ - StdMmgr.hpp Mmged.hpp + fmt.h fs.h gdl.h htb.h hton.h ipad.h lda.h main.h map.h mbwc.h \ + mem.h nwad.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sio.h \ + sll.h slmb.h stdio.h str.h time.h tio.h tre.h utf8.h xma.h \ + Mmgr.hpp StdMmgr.hpp Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -229,9 +229,10 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkginclude_HEADERS = alg.h chr.h dll.h env.h fio.h fma.h fmt.h fs.h \ - gdl.h htb.h lda.h main.h map.h mbwc.h mem.h oht.h opt.h path.h \ - pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h \ - time.h tio.h tre.h utf8.h xma.h $(am__append_1) + gdl.h htb.h hton.h ipad.h lda.h main.h map.h mbwc.h mem.h \ + nwad.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sio.h sll.h \ + slmb.h stdio.h str.h time.h tio.h tre.h utf8.h xma.h \ + $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/hton.h b/qse/include/qse/cmn/hton.h new file mode 100644 index 00000000..46db5a90 --- /dev/null +++ b/qse/include/qse/cmn/hton.h @@ -0,0 +1,75 @@ +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_CMN_HTON_H_ +#define _QSE_CMN_HTON_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(QSE_HAVE_UINT16_T) +qse_uint16_t qse_ntoh16 ( + qse_uint16_t x +); + +qse_uint16_t qse_hton16 ( + qse_uint16_t x +); +#endif + +#if defined(QSE_HAVE_UINT32_T) +qse_uint32_t qse_ntoh32 ( + qse_uint32_t x +); + +qse_uint32_t qse_hton32 ( + qse_uint32_t x +); +#endif + +#if defined(QSE_HAVE_UINT64_T) +qse_uint64_t qse_ntoh64 ( + qse_uint64_t x +); + +qse_uint64_t qse_hton64 ( + qse_uint64_t x +); +#endif + +#if defined(QSE_HAVE_UINT128_T) +qse_uint128_t qse_ntoh128 ( + qse_uint128_t x +); + +qse_uint128_t qse_hton128 ( + qse_uint128_t x +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/ipad.h b/qse/include/qse/cmn/ipad.h new file mode 100644 index 00000000..6246c4ef --- /dev/null +++ b/qse/include/qse/cmn/ipad.h @@ -0,0 +1,66 @@ + +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_CMN_IPAD_H_ +#define _QSE_CMN_IPAD_H_ + +#include +#include + +typedef struct qse_ipad_t qse_ipad_t; +typedef struct qse_ipad4_t qse_ipad4_t; +typedef struct qse_ipad6_t qse_ipad6_t; + +#include +struct qse_ipad4_t +{ + qse_uint32_t value; +}; +struct qse_ipad6_t +{ + qse_uint8_t value[16]; +}; +#include + +struct qse_ipad_t +{ + enum + { + QSE_IPAD_IP4, + QSE_IPAD_IP6 + } type; + + union + { + qse_ipad4_t ip4; + qse_ipad4_t ip6; + } u; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/mbwc.h b/qse/include/qse/cmn/mbwc.h index f3ba9618..24ec511b 100644 --- a/qse/include/qse/cmn/mbwc.h +++ b/qse/include/qse/cmn/mbwc.h @@ -28,6 +28,8 @@ #include #include +typedef qse_cmgr_t* (*qse_cmgr_finder_t) (const qse_char_t* name); + #ifdef __cplusplus extern "C" { #endif @@ -39,15 +41,23 @@ extern qse_cmgr_t* qse_utf8cmgr; extern qse_cmgr_t* qse_slmbcmgr; /** - * The qse_getcmgrbyname() function find a builtin cmgr matching a given + * The qse_getfindcmgr() function find a builtin cmgr matching a given * @a name and returns it. It returns #QSE_NULL if no match is found. * The @a name can be one of "utf8", "slmb", and an empty string. Calling this * function with an empty string is the same as calling qse_getdflcmgr(). */ -qse_cmgr_t* qse_getcmgrbyname ( +qse_cmgr_t* qse_findcmgr ( const qse_char_t* name ); +void qse_setcmgrfinder ( + qse_cmgr_finder_t finder +); + +qse_cmgr_finder_t qse_getcmgrfinder ( + void +); + /* --------------------------------------------------- */ /* DEFAULT GLOBAL CMGR */ /* --------------------------------------------------- */ diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h new file mode 100644 index 00000000..2f64336c --- /dev/null +++ b/qse/include/qse/cmn/nwad.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_CMN_NWAD_H_ +#define _QSE_CMN_NWAD_H_ + +#include +#include +#include + +struct qse_nwad_t +{ + enum + { + QSE_NWAD_IP4, + QSE_NWAD_IP6 + } type; + + union + { + struct + { + qse_ipad4_t addr; + qse_uint16_t port; + } ip4; + + struct + { + qse_ipad6_t addr; + qse_uint16_t port; + } ip6; + } u; +}; + +#endif diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index 566e68a9..7fe092de 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -52,6 +52,14 @@ enum qse_httpd_option_t QSE_HTTPD_CGINOCLOEXEC = (1 << 1) }; +typedef struct qse_httpd_stat_t qse_httpd_stat_t; +struct qse_httpd_stat_t +{ + qse_foff_t size; + qse_ntime_t mtime; + const qse_mchar_t* mime; +}; + typedef struct qse_httpd_cbs_t qse_httpd_cbs_t; struct qse_httpd_cbs_t { @@ -65,14 +73,16 @@ struct qse_httpd_cbs_t struct { - int (*executable) (qse_httpd_t* httpd, const qse_mchar_t* path); - } path; + int (*executable) ( + qse_httpd_t* httpd, const qse_mchar_t* path); - struct - { + int (*stat) ( + qse_httpd_t* httpd, const qse_mchar_t* path, + qse_httpd_stat_t* stat); + int (*ropen) ( qse_httpd_t* httpd, const qse_mchar_t* path, - qse_ubi_t* handle, qse_foff_t* size); + qse_ubi_t* handle); int (*wopen) ( qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle); @@ -115,7 +125,6 @@ struct qse_httpd_cbs_t int (*handle_request) ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); - const qse_mchar_t* (*getmimetype) (qse_httpd_t* httpd, const qse_mchar_t* path); int (*listdir) (qse_httpd_t* httpd, const qse_mchar_t* path); }; @@ -313,6 +322,14 @@ qse_httpd_task_t* qse_httpd_entaskcontinue ( qse_htre_t* req ); +qse_httpd_task_t* qse_httpd_entaskauth ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_httpd_task_t* task, + const qse_mchar_t* realm, + qse_htre_t* req +); + qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_t* httpd, qse_httpd_client_t* client, diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp index 3c2da892..9c2fd112 100644 --- a/qse/lib/awk/StdAwk.cpp +++ b/qse/lib/awk/StdAwk.cpp @@ -238,7 +238,7 @@ int StdAwk::setenc (Run& run, Value& ret, const Value* args, size_t nargs, return ret.setInt ((long_t)-1); } - qse_cmgr_t* cmgr = qse_getcmgrbyname (ptr[1]); + qse_cmgr_t* cmgr = qse_findcmgr (ptr[1]); if (cmgr == QSE_NULL) { return ret.setInt ((long_t)-1); diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 276a441b..cacfc5eb 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -124,7 +124,8 @@ typedef struct rxtn_t } rxtn_t; #if defined(QSE_CHAR_IS_WCHAR) -static qse_cmgr_t* getcmgr_from_cmgrtab (qse_awk_rtx_t* rtx, const qse_char_t* ioname); +static qse_cmgr_t* getcmgr_from_cmgrtab ( + qse_awk_rtx_t* rtx, const qse_char_t* ioname); #endif static qse_flt_t custom_awk_pow (qse_awk_t* awk, qse_flt_t x, qse_flt_t y) @@ -1562,7 +1563,8 @@ skip_system: } #if defined(QSE_CHAR_IS_WCHAR) -static qse_cmgr_t* getcmgr_from_cmgrtab (qse_awk_rtx_t* rtx, const qse_char_t* ioname) +static qse_cmgr_t* getcmgr_from_cmgrtab ( + qse_awk_rtx_t* rtx, const qse_char_t* ioname) { rxtn_t* rxtn; qse_htb_pair_t* pair; @@ -1617,7 +1619,7 @@ static int fnc_setenc (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) } } - cmgr = qse_getcmgrbyname (ptr[1]); + cmgr = qse_findcmgr (ptr[1]); if (cmgr == QSE_NULL) fret = -1; else { diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index d388e09a..4db96187 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -36,10 +36,13 @@ libqsecmn_la_SOURCES = \ fs.c \ fs-err.c \ fs-move.c \ + hton.c \ + ipad.c \ main.c \ mbwc.c \ mbwc-str.c \ mem.c \ + nwad.c \ oht.c \ opt.c \ path-basename.c \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 48d3d743..f8adab80 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -77,18 +77,18 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libqsecmn_la_DEPENDENCIES = am_libqsecmn_la_OBJECTS = alg-rand.lo alg-search.lo alg-sort.lo \ assert.lo chr.lo dll.lo env.lo gdl.lo htb.lo lda.lo fio.lo \ - fma.lo fmt.lo fs.lo fs-err.lo fs-move.lo main.lo mbwc.lo \ - mbwc-str.lo mem.lo oht.lo opt.lo path-basename.lo \ - path-canon.lo pio.lo pma.lo rbt.lo rex.lo sio.lo sll.lo \ - slmb.lo stdio.lo str-beg.lo str-cat.lo str-chr.lo str-cnv.lo \ - str-cmp.lo str-cpy.lo str-del.lo str-dup.lo str-dynm.lo \ - str-dynw.lo str-end.lo str-excl.lo str-fcpy.lo str-fnmat.lo \ - str-incl.lo str-len.lo str-pac.lo str-pbrk.lo str-put.lo \ - str-rev.lo str-rot.lo str-set.lo str-spl.lo str-spn.lo \ - str-str.lo str-subst.lo str-tok.lo str-trm.lo str-word.lo \ - time.lo tio.lo tio-get.lo tio-put.lo tre.lo tre-ast.lo \ - tre-compile.lo tre-match-backtrack.lo tre-match-parallel.lo \ - tre-parse.lo tre-stack.lo utf8.lo xma.lo + fma.lo fmt.lo fs.lo fs-err.lo fs-move.lo hton.lo ipad.lo \ + main.lo mbwc.lo mbwc-str.lo mem.lo nwad.lo oht.lo opt.lo \ + path-basename.lo path-canon.lo pio.lo pma.lo rbt.lo rex.lo \ + sio.lo sll.lo slmb.lo stdio.lo str-beg.lo str-cat.lo \ + str-chr.lo str-cnv.lo str-cmp.lo str-cpy.lo str-del.lo \ + str-dup.lo str-dynm.lo str-dynw.lo str-end.lo str-excl.lo \ + str-fcpy.lo str-fnmat.lo str-incl.lo str-len.lo str-pac.lo \ + str-pbrk.lo str-put.lo str-rev.lo str-rot.lo str-set.lo \ + str-spl.lo str-spn.lo str-str.lo str-subst.lo str-tok.lo \ + str-trm.lo str-word.lo time.lo tio.lo tio-get.lo tio-put.lo \ + tre.lo tre-ast.lo tre-compile.lo tre-match-backtrack.lo \ + tre-match-parallel.lo tre-parse.lo tre-stack.lo utf8.lo xma.lo libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -310,10 +310,13 @@ libqsecmn_la_SOURCES = \ fs.c \ fs-err.c \ fs-move.c \ + hton.c \ + ipad.c \ main.c \ mbwc.c \ mbwc-str.c \ mem.c \ + nwad.c \ oht.c \ opt.c \ path-basename.c \ @@ -468,11 +471,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hton.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc-str.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwad.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-basename.Plo@am__quote@ diff --git a/qse/lib/cmn/hton.c b/qse/lib/cmn/hton.c new file mode 100644 index 00000000..616b30ba --- /dev/null +++ b/qse/lib/cmn/hton.c @@ -0,0 +1,203 @@ +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include + + +/* --------------------------------------------------------------- */ + +#if defined(QSE_HAVE_UINT16_T) + +qse_uint16_t qse_ntoh16 (qse_uint16_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint16_t)( + ((qse_uint16_t)c[0] << 8) | + ((qse_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +qse_uint16_t qse_hton16 (qse_uint16_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint16_t)( + ((qse_uint16_t)c[0] << 8) | + ((qse_uint16_t)c[1] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* --------------------------------------------------------------- */ + +#if defined(QSE_HAVE_UINT32_T) + +qse_uint32_t qse_ntoh32 (qse_uint32_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint32_t)( + ((qse_uint32_t)c[0] << 24) | + ((qse_uint32_t)c[1] << 16) | + ((qse_uint32_t)c[2] << 8) | + ((qse_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} + +qse_uint32_t qse_hton32 (qse_uint32_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint32_t)( + ((qse_uint32_t)c[0] << 24) | + ((qse_uint32_t)c[1] << 16) | + ((qse_uint32_t)c[2] << 8) | + ((qse_uint32_t)c[3] << 0)); +#else +# error Unknown endian +#endif +} +#endif + +/* --------------------------------------------------------------- */ + +#if defined(QSE_HAVE_UINT64_T) + +qse_uint64_t qse_ntoh64 (qse_uint64_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint64_t)( + ((qse_uint64_t)c[0] << 56) | + ((qse_uint64_t)c[1] << 48) | + ((qse_uint64_t)c[2] << 40) | + ((qse_uint64_t)c[3] << 32) | + ((qse_uint64_t)c[4] << 24) | + ((qse_uint64_t)c[5] << 16) | + ((qse_uint64_t)c[6] << 8) | + ((qse_uint64_t)c[7] << 0)); +#else +# error Unknown endian +#endif +} + +qse_uint64_t qse_hton64 (qse_uint64_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint64_t)( + ((qse_uint64_t)c[0] << 56) | + ((qse_uint64_t)c[1] << 48) | + ((qse_uint64_t)c[2] << 40) | + ((qse_uint64_t)c[3] << 32) | + ((qse_uint64_t)c[4] << 24) | + ((qse_uint64_t)c[5] << 16) | + ((qse_uint64_t)c[6] << 8) | + ((qse_uint64_t)c[7] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* --------------------------------------------------------------- */ + +#if defined(QSE_HAVE_UINT128_T) + +qse_uint128_t qse_ntoh128 (qse_uint128_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint128_t)( + ((qse_uint128_t)c[0] << 120) | + ((qse_uint128_t)c[1] << 112) | + ((qse_uint128_t)c[2] << 104) | + ((qse_uint128_t)c[3] << 96) | + ((qse_uint128_t)c[4] << 88) | + ((qse_uint128_t)c[5] << 80) | + ((qse_uint128_t)c[6] << 72) | + ((qse_uint128_t)c[7] << 64) | + ((qse_uint128_t)c[8] << 56) | + ((qse_uint128_t)c[9] << 48) | + ((qse_uint128_t)c[10] << 40) | + ((qse_uint128_t)c[11] << 32) | + ((qse_uint128_t)c[12] << 24) | + ((qse_uint128_t)c[13] << 16) | + ((qse_uint128_t)c[14] << 8) | + ((qse_uint128_t)c[15] << 0)); +#else +# error Unknown endian +#endif +} + +qse_uint128_t qse_hton128 (qse_uint128_t x) +{ +#if defined(QSE_ENDIAN_BIG) + return x; +#elif defined(QSE_ENDIAN_LITTLE) + qse_uint8_t* c = (qse_uint8_t*)&x; + return (qse_uint128_t)( + ((qse_uint128_t)c[0] << 120) | + ((qse_uint128_t)c[1] << 112) | + ((qse_uint128_t)c[2] << 104) | + ((qse_uint128_t)c[3] << 96) | + ((qse_uint128_t)c[4] << 88) | + ((qse_uint128_t)c[5] << 80) | + ((qse_uint128_t)c[6] << 72) | + ((qse_uint128_t)c[7] << 64) | + ((qse_uint128_t)c[8] << 56) | + ((qse_uint128_t)c[9] << 48) | + ((qse_uint128_t)c[10] << 40) | + ((qse_uint128_t)c[11] << 32) | + ((qse_uint128_t)c[12] << 24) | + ((qse_uint128_t)c[13] << 16) | + ((qse_uint128_t)c[14] << 8) | + ((qse_uint128_t)c[15] << 0)); +#else +# error Unknown endian +#endif +} + +#endif + +/* --------------------------------------------------------------- */ diff --git a/qse/lib/cmn/ipad.c b/qse/lib/cmn/ipad.c new file mode 100644 index 00000000..abd7c464 --- /dev/null +++ b/qse/lib/cmn/ipad.c @@ -0,0 +1,573 @@ +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +/* Copyright (c) 1996-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include + +#if 0 +const qse_ipad4_t qse_ipad4_any = +{ + 0 /* 0.0.0.0 */ +}; + +const qse_ipad4_t qse_ipad4_loopback = +{ +#if defined(QSE_ENDIAN_BIG) + 0x7F000001u /* 127.0.0.1 */ +#elif defined(QSE_ENDIAN_LITTLE) + 0x0100007Fu +#else +# error Unknown endian +#endif +}; + +const qse_ipad6_t qse_ipad6_any = +{ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* :: */ +}; + +const qse_ipad6_t qse_ipad6_loopback = +{ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } /* ::1 */ +}; +#endif + +#if 0 +int qse_strtoipad4 (const qse_char_t* str, qse_ipad4_t* ipad) +{ + qse_char_t c; + int dots = 0, digits = 0; + qse_uint32_t acc = 0, addr = 0; + + do + { + c = *str; + + if (c == QSE_T('\0')) + { + if (dots < 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + break; + } + else if (c >= QSE_T('0') && c <= QSE_T('9')) + { + if (digits > 0 && acc == 0) return -1; + acc = acc * 10 + (c - QSE_T('0')); + if (acc > 255) return -1; + digits++; + } + else if (c == QSE_T('.')) + { + if (dots >= 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + dots++; acc = 0; digits = 0; + } + else return -1; + + str++; + } + while (1); + + if (ipad != QSE_NULL) ipad->value = qse_hton32(addr); + return 0; +} + +int qse_strxtoipad4 ( + const qse_char_t* str, qse_size_t len, qse_ipad4_t* ipad) +{ + qse_char_t c; + int dots = 0, digits = 0; + qse_uint32_t acc = 0, addr = 0; + const qse_char_t* end = str + len; + + do + { + if (str >= end) + { + if (dots < 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + break; + } + + c = *str; + + if (c >= QSE_T('0') && c <= QSE_T('9')) + { + if (digits > 0 && acc == 0) return -1; + acc = acc * 10 + (c - QSE_T('0')); + if (acc > 255) return -1; + digits++; + } + else if (c == QSE_T('.')) + { + if (dots >= 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + dots++; acc = 0; digits = 0; + } + else return -1; + + str++; + } + while (1); + + if (ipad != QSE_NULL) ipad->value = qse_hton32(addr); + return 0; +} + +#define __BTOA(b,p,end) \ + do { \ + qse_char_t* sp = p; \ + do { \ + if (p >= end) { \ + if (p == sp) break; \ + if (p - sp > 1) p[-2] = p[-1]; \ + p[-1] = (b % 10) + QSE_T('0'); \ + } \ + else *p++ = (b % 10) + QSE_T('0'); \ + b /= 10; \ + } while (b > 0); \ + if (p - sp > 1) { \ + qse_char_t t = sp[0]; \ + sp[0] = p[-1]; \ + p[-1] = t; \ + } \ + } while (0); + +#define __ADDDOT(p, end) \ + do { \ + if (p >= end) break; \ + *p++ = QSE_T('.'); \ + } while (0) + +qse_size_t qse_ipad4tostrx ( + const qse_ipad4_t* ipad, qse_char_t* buf, qse_size_t size) +{ + qse_byte_t b; + qse_char_t* p, * end; + qse_uint32_t ip; + + if (size <= 0) return 0; + + ip = ipad->value; + + p = buf; + end = buf + size - 1; + +#if defined(QSE_ENDIAN_BIG) + b = (ip >> 24) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 16) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 8) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 0) & 0xFF; __BTOA (b, p, end); +#elif defined(QSE_ENDIAN_LITTLE) + b = (ip >> 0) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 8) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 16) & 0xFF; __BTOA (b, p, end); __ADDDOT (p, end); + b = (ip >> 24) & 0xFF; __BTOA (b, p, end); +#else +# error Unknown Endian +#endif + + *p = QSE_T('\0'); + return p - buf; +} + +int qse_strtoipad6 (const qse_char_t* src, qse_ipad6_t* ipad) +{ +#if 0 + static const qse_char_t xdigits_l[] = QSE_T("0123456789abcdef"), + xdigits_u[] = QSE_T("0123456789ABCDEF"); + const qse_char_t* xdigits; +#endif + + qse_ipad6_t tmp; + qse_byte_t* tp, * endp, * colonp; + const qse_char_t* curtok; + qse_char_t ch; + int saw_xdigit; + unsigned int val; + + qse_memset (&tmp, 0, QSE_SIZEOF(tmp)); + tp = &tmp.value[0]; + endp = &tmp.value[QSE_COUNTOF(tmp.value)]; + colonp = QSE_NULL; + + /* Leading :: requires some special handling. */ + if (*src == QSE_T(':')) + { + if (*++src != QSE_T(':')) return -1; + } + + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != QSE_T('\0')) + { + #if 0 + const char *pch; + if ((pch = qse_strchr((xdigits = xdigits_l), ch)) == QSE_NULL) + pch = qse_strchr((xdigits = xdigits_u), ch); + if (pch != QSE_NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) return -1; + saw_xdigit = 1; + continue; + } + #endif + int v1; + if (ch >= QSE_T('0') && ch <= QSE_T('9')) + v1 = ch - QSE_T('0'); + else if (ch >= QSE_T('A') && ch <= QSE_T('F')) + v1 = ch - QSE_T('A') + 10; + else if (ch >= QSE_T('a') && ch <= QSE_T('f')) + v1 = ch - QSE_T('a') + 10; + else v1 = -1; + if (v1 >= 0) + { + val <<= 4; + val |= v1; + if (val > 0xffff) return -1; + saw_xdigit = 1; + continue; + } + + if (ch == QSE_T(':')) + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) return -1; + colonp = tp; + continue; + } + else if (*src == QSE_T('\0')) + { + /* a colon can't be the last character */ + return -1; + } + + if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1; + *tp++ = (qse_byte_t) (val >> 8) & 0xff; + *tp++ = (qse_byte_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + #if 0 + if (ch == QSE_T('.') && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) + { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + #endif + if (ch == QSE_T('.') && ((tp + QSE_SIZEOF(qse_ipad4_t)) <= endp) && + qse_strtoipad4(curtok, (qse_ipad4_t*)tp) == 0) + { + tp += QSE_SIZEOF(qse_ipad4_t); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1; + *tp++ = (qse_byte_t) (val >> 8) & 0xff; + *tp++ = (qse_byte_t) val & 0xff; + } + if (colonp != QSE_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + qse_size_t n = tp - colonp; + qse_size_t i; + + for (i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + + if (tp != endp) return -1; + + *ipad = tmp; + return 0; +} + +int qse_strxtoipad6 (const qse_char_t* src, qse_size_t len, qse_ipad6_t* ipad) +{ + qse_ipad6_t tmp; + qse_byte_t* tp, * endp, * colonp; + const qse_char_t* curtok; + qse_char_t ch; + int saw_xdigit; + unsigned int val; + const qse_char_t* src_end; + + src_end = src + len; + + qse_memset (&tmp, 0, QSE_SIZEOF(tmp)); + tp = &tmp.value[0]; + endp = &tmp.value[QSE_COUNTOF(tmp.value)]; + colonp = QSE_NULL; + + /* Leading :: requires some special handling. */ + if (src < src_end && *src == QSE_T(':')) + { + src++; + if (src >= src_end || *src != QSE_T(':')) return -1; + } + + curtok = src; + saw_xdigit = 0; + val = 0; + + while (src < src_end) + { + int v1; + + ch = *src++; + + if (ch >= QSE_T('0') && ch <= QSE_T('9')) + v1 = ch - QSE_T('0'); + else if (ch >= QSE_T('A') && ch <= QSE_T('F')) + v1 = ch - QSE_T('A') + 10; + else if (ch >= QSE_T('a') && ch <= QSE_T('f')) + v1 = ch - QSE_T('a') + 10; + else v1 = -1; + if (v1 >= 0) + { + val <<= 4; + val |= v1; + if (val > 0xffff) return -1; + saw_xdigit = 1; + continue; + } + + if (ch == QSE_T(':')) + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) return -1; + colonp = tp; + continue; + } + else if (src >= src_end) + { + /* a colon can't be the last character */ + return -1; + } + + *tp++ = (qse_byte_t) (val >> 8) & 0xff; + *tp++ = (qse_byte_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + + if (ch == QSE_T('.') && ((tp + QSE_SIZEOF(qse_ipad4_t)) <= endp) && + qse_strxtoipad4(curtok, src_end - curtok, (qse_ipad4_t*)tp) == 0) + { + tp += QSE_SIZEOF(qse_ipad4_t); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + QSE_SIZEOF(qse_uint16_t) > endp) return -1; + *tp++ = (qse_byte_t) (val >> 8) & 0xff; + *tp++ = (qse_byte_t) val & 0xff; + } + if (colonp != QSE_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + qse_size_t n = tp - colonp; + qse_size_t i; + + for (i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + + if (tp != endp) return -1; + + *ipad = tmp; + return 0; +} + +qse_size_t qse_ipad6tostrx ( + const qse_ipad6_t* ipad, qse_char_t* buf, qse_size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + +#define IP6ADDR_NWORDS (QSE_SIZEOF(ipad->value) / QSE_SIZEOF(qse_uint16_t)) + + qse_char_t tmp[QSE_COUNTOF(QSE_T("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))], *tp; + struct { int base, len; } best, cur; + qse_uint16_t words[IP6ADDR_NWORDS]; + int i; + + if (size <= 0) return 0; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + qse_memset (words, 0, QSE_SIZEOF(words)); + for (i = 0; i < QSE_SIZEOF(ipad->value); i++) + words[i / 2] |= (ipad->value[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + + for (i = 0; i < IP6ADDR_NWORDS; i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + { + cur.base = i; + cur.len = 1; + } + else + { + cur.len++; + } + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) best = cur; + } + if (best.base != -1 && best.len < 2) best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < IP6ADDR_NWORDS; i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) + { + if (i == best.base) *tp++ = QSE_T(':'); + continue; + } + + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) *tp++ = QSE_T(':'); + + /* Is this address an encapsulated IPv4? ipv4-compatible or ipv4-mapped */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + qse_ipad4_t ipad4; + qse_memcpy (&ipad4.value, ipad->value+12, QSE_SIZEOF(ipad4.value)); + tp += qse_ipad4tostrx (&ipad4, tp, QSE_SIZEOF(tmp) - (tp - tmp)); + break; + } + + tp += qse_uint16tostr_lower (words[i], tp, QSE_SIZEOF(tmp) - (tp - tmp), 16, QSE_T('\0')); + } + + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && + (best.base + best.len) == IP6ADDR_NWORDS) *tp++ = QSE_T(':'); + *tp++ = QSE_T('\0'); + + return qse_strxcpy (buf, size, tmp); + +#undef IP6ADDR_NWORDS +} + +int qse_strtoipad (const qse_char_t* str, qse_ipad_t* ipad) +{ + if (qse_strtoipad4 (str, &ipad->u.ip4) <= -1) + { + if (qse_strtoipad6 (str, &ipad->u.ip6) <= -1) return -1; + ipad->type = QSE_IPAD_IP6; + } + else ipad->type = QSE_IPAD_IP4; + + return 0; +} + +int qse_strxtoipad (const qse_char_t* str, qse_size_t len, qse_ipad_t* ipad) +{ + if (qse_strxtoipad4 (str, len, &ipad->u.ip4) <= -1) + { + if (qse_strxtoipad6 (str, len, &ipad->u.ip6) <= -1) return -1; + ipad->type = QSE_IPAD_IP6; + } + else ipad->type = QSE_IPAD_IP4; + + return 0; +} +#endif diff --git a/qse/lib/cmn/mbwc.c b/qse/lib/cmn/mbwc.c index 3a176d64..07360da3 100644 --- a/qse/lib/cmn/mbwc.c +++ b/qse/lib/cmn/mbwc.c @@ -47,6 +47,7 @@ qse_cmgr_t* qse_slmbcmgr = &builtin_cmgr[0]; qse_cmgr_t* qse_utf8cmgr = &builtin_cmgr[1]; static qse_cmgr_t* dfl_cmgr = &builtin_cmgr[0]; +static qse_cmgr_finder_t cmgr_finder = QSE_NULL; qse_cmgr_t* qse_getdflcmgr (void) { @@ -58,24 +59,34 @@ void qse_setdflcmgr (qse_cmgr_t* cmgr) dfl_cmgr = (cmgr? cmgr: &builtin_cmgr[0]); } -/* TODO: -qse_addcmgr (const qse_char_t* name, qse_cmgr_t* cmgr); -qse_delcmgr (const qse_char_t* name); -*/ - -qse_cmgr_t* qse_getcmgrbyname (const qse_char_t* name) +qse_cmgr_t* qse_findcmgr (const qse_char_t* name) { if (name) { - /* TODO: binary search */ + if (cmgr_finder) + { + qse_cmgr_t* cmgr; + cmgr = cmgr_finder (name); + if (cmgr) return cmgr; + } + if (qse_strcmp(name, QSE_T("")) == 0) return dfl_cmgr; if (qse_strcmp(name, QSE_T("utf8")) == 0) return qse_utf8cmgr; if (qse_strcmp(name, QSE_T("slmb")) == 0) return qse_slmbcmgr; - /* TODO: add more - handle those added with qse_addcmgr() */ } return QSE_NULL; } +void qse_setcmgrfinder (qse_cmgr_finder_t finder) +{ + cmgr_finder = finder; +} + +qse_cmgr_finder_t qse_getcmgrfinder (void) +{ + return cmgr_finder; +} + /* string conversion function using default character conversion manager */ int qse_mbstowcs ( diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c new file mode 100644 index 00000000..55684eef --- /dev/null +++ b/qse/lib/cmn/nwad.c @@ -0,0 +1,37 @@ +/* + * $Id$ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +/* Copyright (c) 1996-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c index 026abd84..8eb96d34 100644 --- a/qse/lib/cmn/pio.c +++ b/qse/lib/cmn/pio.c @@ -49,7 +49,6 @@ static qse_ssize_t pio_output ( #if defined(_WIN32) static qse_pio_errnum_t syserr_to_errnum (DWORD e) { - switch (e) { case ERROR_INVALID_PARAMETER: @@ -573,13 +572,18 @@ int qse_pio_init ( if (flags & QSE_PIO_WRITEIN) { /* child reads, parent writes */ - if (CreatePipe ( - &handle[0], &handle[1], - &secattr, 0) == FALSE) goto oops; + if (CreatePipe (&handle[0], &handle[1], &secattr, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } /* don't inherit write handle */ - if (SetHandleInformation ( - handle[1], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops; + if (SetHandleInformation (handle[1], HANDLE_FLAG_INHERIT, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } minidx = 0; maxidx = 1; } @@ -587,13 +591,18 @@ int qse_pio_init ( if (flags & QSE_PIO_READOUT) { /* child writes, parent reads */ - if (CreatePipe ( - &handle[2], &handle[3], - &secattr, 0) == FALSE) goto oops; + if (CreatePipe (&handle[2], &handle[3], &secattr, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } /* don't inherit read handle */ - if (SetHandleInformation ( - handle[2], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops; + if (SetHandleInformation (handle[2], HANDLE_FLAG_INHERIT, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } if (minidx == -1) minidx = 2; maxidx = 3; @@ -602,13 +611,18 @@ int qse_pio_init ( if (flags & QSE_PIO_READERR) { /* child writes, parent reads */ - if (CreatePipe ( - &handle[4], &handle[5], - &secattr, 0) == FALSE) goto oops; + if (CreatePipe (&handle[4], &handle[5], &secattr, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } /* don't inherit read handle */ - if (SetHandleInformation ( - handle[4], HANDLE_FLAG_INHERIT, 0) == FALSE) goto oops; + if (SetHandleInformation (handle[4], HANDLE_FLAG_INHERIT, 0) == FALSE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } if (minidx == -1) minidx = 4; maxidx = 5; @@ -629,7 +643,11 @@ int qse_pio_init ( FILE_SHARE_READ | FILE_SHARE_WRITE, &secattr, OPEN_EXISTING, 0, NULL ); - if (windevnul == INVALID_HANDLE_VALUE) goto oops; + if (windevnul == INVALID_HANDLE_VALUE) + { + pio->errnum = syserr_to_errnum (GetLastError()); + goto oops; + } } QSE_MEMSET (&procinfo, 0, QSE_SIZEOF(procinfo)); @@ -743,25 +761,7 @@ int qse_pio_init ( QSE_MMGR_FREE (mmgr, dupcmd); if (x == FALSE) - { - DWORD e = GetLastError (); - switch (e) - { - case ERROR_ACCESS_DENIED: - pio->errnum = QSE_PIO_EACCES; - break; - - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - pio->errnum = QSE_PIO_ENOENT; - break; - - case ERROR_NOT_ENOUGH_MEMORY: - case ERROR_OUTOFMEMORY: - pio->errnum = QSE_PIO_ENOMEM; - break; - } - } + pio->errnum = syserr_to_errnum (GetLastError()); } if (windevnul != INVALID_HANDLE_VALUE) @@ -792,18 +792,32 @@ int qse_pio_init ( #elif defined(__OS2__) #define DOS_DUP_HANDLE(x,y) QSE_BLOCK ( \ - if (DosDupHandle(x,y) != NO_ERROR) goto oops; \ + rc = DosDupHandle(x,y); \ + if (rc != NO_ERROR) \ + { \ + pio->errnum = syserr_to_errnum (rc); \ + goto oops; \ + } \ ) if (flags & QSE_PIO_WRITEIN) { /* child reads, parent writes */ - if (DosCreatePipe ( - &handle[0], &handle[1], pipe_size) != NO_ERROR) goto oops; + rc = DosCreatePipe (&handle[0], &handle[1], pipe_size); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } /* the parent writes to handle[1] and the child reads from * handle[0] inherited. set the flag not to inherit handle[1]. */ - if (DosSetFHState (handle[1], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops; + rc = DosSetFHState (handle[1], OPEN_FLAGS_NOINHERIT); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } /* Need to do somthing like this to set the flag instead? ULONG state; @@ -816,12 +830,21 @@ int qse_pio_init ( if (flags & QSE_PIO_READOUT) { /* child writes, parent reads */ - if (DosCreatePipe ( - &handle[2], &handle[3], pipe_size) != NO_ERROR) goto oops; + rc = DosCreatePipe (&handle[2], &handle[3], pipe_size); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } /* the parent reads from handle[2] and the child writes to * handle[3] inherited. set the flag not to inherit handle[2] */ - if (DosSetFHState (handle[2], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops; + rc = DosSetFHState (handle[2], OPEN_FLAGS_NOINHERIT); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } if (minidx == -1) minidx = 2; maxidx = 3; @@ -830,12 +853,21 @@ int qse_pio_init ( if (flags & QSE_PIO_READERR) { /* child writes, parent reads */ - if (DosCreatePipe ( - &handle[4], &handle[5], pipe_size) != NO_ERROR) goto oops; + rc = DosCreatePipe (&handle[4], &handle[5], pipe_size); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } /* the parent reads from handle[4] and the child writes to * handle[5] inherited. set the flag not to inherit handle[4] */ - if (DosSetFHState (handle[4], OPEN_FLAGS_NOINHERIT) != NO_ERROR) goto oops; + rc = DosSetFHState (handle[4], OPEN_FLAGS_NOINHERIT); + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } if (minidx == -1) minidx = 4; maxidx = 5; @@ -867,22 +899,32 @@ int qse_pio_init ( OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, 0L ); - if (rc != NO_ERROR) goto oops; + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } } /* duplicate the current stdin/out/err to old_in/out/err as a new handle */ - if (DosDupHandle (std_in, &old_in) != NO_ERROR) + rc = DosDupHandle (std_in, &old_in); + if (rc != NO_ERROR) { + pio->errnum = syserr_to_errnum (rc); goto oops; } - if (DosDupHandle (std_out, &old_out) != NO_ERROR) + rc = DosDupHandle (std_out, &old_out); + if (rc != NO_ERROR) { + pio->errnum = syserr_to_errnum (rc); DosClose (old_in); old_in = QSE_PIO_HND_NIL; goto oops; } - if (DosDupHandle (std_err, &old_err) != NO_ERROR) + rc = DosDupHandle (std_err, &old_err); + if (rc != NO_ERROR) { + pio->errnum = syserr_to_errnum (rc); DosClose (old_out); old_out = QSE_PIO_HND_NIL; DosClose (old_in); old_in = QSE_PIO_HND_NIL; goto oops; @@ -1060,8 +1102,6 @@ int qse_pio_init ( cmd_file ); -/* TODO: translate error code ... */ - QSE_MMGR_FREE (mmgr, cmd_line); cmd_line = QSE_NULL; @@ -1074,7 +1114,11 @@ int qse_pio_init ( DosDupHandle (old_err, &std_err); DosClose (old_err); old_err = QSE_PIO_HND_NIL; - if (rc != NO_ERROR) goto oops; + if (rc != NO_ERROR) + { + pio->errnum = syserr_to_errnum (rc); + goto oops; + } pio->child = child_rc.codeTerminate; #elif defined(__DOS__) @@ -1085,20 +1129,32 @@ int qse_pio_init ( #elif defined(HAVE_POSIX_SPAWN) if (flags & QSE_PIO_WRITEIN) { - if (QSE_PIPE(&handle[0]) <= -1) goto oops; + if (QSE_PIPE(&handle[0]) <= -1) + { + pio->errnum = syserr_to_errnum (errno); + goto oops; + } minidx = 0; maxidx = 1; } if (flags & QSE_PIO_READOUT) { - if (QSE_PIPE(&handle[2]) <= -1) goto oops; + if (QSE_PIPE(&handle[2]) <= -1) + { + pio->errnum = syserr_to_errnum (errno); + goto oops; + } if (minidx == -1) minidx = 2; maxidx = 3; } if (flags & QSE_PIO_READERR) { - if (QSE_PIPE(&handle[4]) <= -1) goto oops; + if (QSE_PIPE(&handle[4]) <= -1) + { + pio->errnum = syserr_to_errnum (errno); + goto oops; + } if (minidx == -1) minidx = 4; maxidx = 5; } diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd_task.c index e1e4e2fd..c22cad76 100644 --- a/qse/lib/net/httpd_task.c +++ b/qse/lib/net/httpd_task.c @@ -411,94 +411,21 @@ qse_httpd_task_t* qse_httpd_entaskcontinue ( /*------------------------------------------------------------------------*/ -#if 0 -typedef struct task_file_t task_file_t; -struct task_file_t +qse_httpd_task_t* qse_httpd_entaskauth ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + const qse_httpd_task_t* task, const qse_mchar_t* realm, qse_htre_t* req) { - qse_ubi_t handle; - qse_foff_t left; - qse_foff_t offset; -}; - -static int task_init_file ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - task_file_t* xtn = qse_httpd_gettaskxtn (httpd, task); - QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); - task->ctx = xtn; - return 0; -} - -static void task_fini_file ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - task_file_t* ctx = (task_file_t*)task->ctx; -qse_printf (QSE_T("closing file %d\n"), ctx->handle.i); - QSE_CLOSE (ctx->handle.i); -} - -static int task_main_file ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - qse_ssize_t n; - qse_size_t count; - task_file_t* ctx = (task_file_t*)task->ctx; - - count = MAX_SEND_SIZE; - if (count >= ctx->left) count = ctx->left; - -/* TODO: more adjustment needed for OS with different sendfile semantics... */ - n = httpd->cbs->client.sendfile ( - httpd, client, ctx->handle, &ctx->offset, count); - if (n <= -1) - { -// HANDLE EGAIN specially??? - return -1; /* TODO: any logging */ - } - - if (n == 0 && count > 0) - { - /* The file could be truncated when this condition is set. - * The content-length sent in the header can't be fulfilled. - * So let's return an error here so that the main loop abort - * the connection. */ -/* TODO: any logging....??? */ - return -1; - } - - ctx->left -= n; - if (ctx->left <= 0) return 0; - - return 1; /* more work to do */ -} - -qse_httpd_task_t* qse_httpd_entaskfile ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - const qse_httpd_task_t* pred, - qse_ubi_t handle, - qse_foff_t offset, - qse_foff_t size) -{ - qse_httpd_task_t task; - task_file_t data; - - QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); - data.handle = handle; - data.offset = offset; - data.left = size; - - QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); - task.init = task_init_file; - task.main = task_main_file; - task.fini = task_fini_file; - task.ctx = &data; - -qse_printf (QSE_T("Debug: entasking file (%d)\n"), client->handle.i); - return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data)); + const qse_http_version_t* version = qse_htre_getversion(req); +/* TODO: */ + return qse_httpd_entaskformat ( + httpd, client, task, + QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nContent-Length: 0\r\nWWW-Authenticate: Digest realm=\"%s\", qop=\"auth\", nonce=\"%s\""), + version->major, version->minor); } /*------------------------------------------------------------------------*/ + +#if 0 typedef struct task_dir_t task_dir_t; struct task_dir_t { @@ -867,161 +794,6 @@ static int task_init_path ( return 0; } -static QSE_INLINE int task_main_path_file ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_httpd_task_t* task, qse_foff_t filesize) -{ - task_path_t* data = (task_path_t*)task->ctx; - qse_httpd_task_t* x = task; - qse_ubi_t handle; - int oflags; - -/* TODO: if you should deal with files on a network-mounted drive, - setting a trigger or non-blocking I/O are needed. */ - - /* when it comes to the file size, using fstat after opening - * can be more accurate. but this function uses information - * set into the task context before the call to this function */ - -qse_printf (QSE_T("opening file %hs\n"), data->name); - - oflags = O_RDONLY; -#if defined(O_LARGEFILE) - oflags |= O_LARGEFILE; -#endif - handle.i = QSE_OPEN (data->name, oflags, 0); - if (handle.i <= -1) - { - x = entask_error ( - httpd, client, x, 404, &data->version, data->keepalive); - goto no_file_send; - } - oflags = QSE_FCNTL (handle.i, F_GETFD, 0); - if (oflags >= 0) - QSE_FCNTL (handle.i, F_SETFD, oflags | FD_CLOEXEC); - - if (data->range.type != QSE_HTTP_RANGE_NONE) - { - const qse_mchar_t* mime_type = QSE_NULL; - - if (data->range.type == QSE_HTTP_RANGE_SUFFIX) - { - if (data->range.to > filesize) data->range.to = filesize; - data->range.from = filesize - data->range.to; - data->range.to = data->range.to + data->range.from; - if (filesize > 0) data->range.to--; - } - - if (data->range.from >= filesize) - { - x = entask_error ( - httpd, client, x, 416, &data->version, data->keepalive); - goto no_file_send; - } - - if (data->range.to >= filesize) data->range.to = filesize - 1; - - if (httpd->cbs->getmimetype) - { - httpd->errnum = QSE_HTTPD_ENOERR; - mime_type = httpd->cbs->getmimetype (httpd, data->name); - /*TODO: how to handle an error... */ - } - -#if (QSE_SIZEOF_LONG_LONG > 0) - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"), - data->version.major, - data->version.minor, - (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long long)(data->range.to - data->range.from + 1), - (unsigned long long)data->range.from, - (unsigned long long)data->range.to, - (unsigned long long)filesize - ); -#else - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 206 Partial Content\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"), - data->version.major, - data->version.minor, - (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long)(data->range.to - data->range.from + 1), - (unsigned long)data->range.from, - (unsigned long)data->range.to, - (unsigned long)filesize - ); -#endif - if (x) - { - x = qse_httpd_entaskfile ( - httpd, client, x, - handle, - data->range.from, - (data->range.to - data->range.from + 1) - ); - } - } - else - { -/* TODO: int64 format.... don't hard code it llu */ - const qse_mchar_t* mime_type = QSE_NULL; - - if (httpd->cbs->getmimetype) - { - httpd->errnum = QSE_HTTPD_ENOERR; - mime_type = httpd->cbs->getmimetype (httpd, data->name); -/*TODO: how to handle an error... */ - } - - /* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header. - * if the reply doesn't contain 'Connection: keep-alive', it didn't - * close connection.*/ -#if (QSE_SIZEOF_LONG_LONG > 0) - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\n\r\n"), - data->version.major, data->version.minor, - (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long long)filesize - ); -#else - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %lu\r\n\r\n"), - data->version.major, - data->version.minor, - (data->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long)filesize - ); -#endif - if (x) - { - x = qse_httpd_entaskfile ( - httpd, client, x, handle, 0, filesize); - } - } - - return (x == QSE_NULL)? -1: 0; - -no_file_send: - if (handle.i >= 0) close (handle.i); - return (x == QSE_NULL)? -1: 0; -} - static QSE_INLINE int task_main_path_dir ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { @@ -1259,8 +1031,8 @@ static QSE_INLINE int task_main_file ( task_file_t* file; qse_httpd_task_t* x; qse_ubi_t handle; - qse_foff_t filesize; int fileopen = 0; + qse_httpd_stat_t st; file = (task_file_t*)task->ctx; x = task; @@ -1269,9 +1041,21 @@ static QSE_INLINE int task_main_file ( setting a trigger or non-blocking I/O are needed. */ qse_printf (QSE_T("opening file %hs\n"), file->path); + + httpd->errnum = QSE_HTTPD_ENOERR; + if (httpd->cbs->file.stat (httpd, file->path, &st) <= -1) + { + int http_errnum; + http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: + (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; + x = entask_error ( + httpd, client, x, http_errnum, + &file->version, file->keepalive); + goto no_file_send; + } httpd->errnum = QSE_HTTPD_ENOERR; - if (httpd->cbs->file.ropen (httpd, file->path, &handle, &filesize) <= -1) + if (httpd->cbs->file.ropen (httpd, file->path, &handle) <= -1) { int http_errnum; http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: @@ -1285,31 +1069,22 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); if (file->range.type != QSE_HTTP_RANGE_NONE) { - const qse_mchar_t* mime_type = QSE_NULL; - if (file->range.type == QSE_HTTP_RANGE_SUFFIX) { - if (file->range.to > filesize) file->range.to = filesize; - file->range.from = filesize - file->range.to; + if (file->range.to > st.size) file->range.to = st.size; + file->range.from = st.size - file->range.to; file->range.to = file->range.to + file->range.from; - if (filesize > 0) file->range.to--; + if (st.size > 0) file->range.to--; } - if (file->range.from >= filesize) + if (file->range.from >= st.size) { x = entask_error ( httpd, client, x, 416, &file->version, file->keepalive); goto no_file_send; } - if (file->range.to >= filesize) file->range.to = filesize - 1; - - if (httpd->cbs->getmimetype) - { - httpd->errnum = QSE_HTTPD_ENOERR; - mime_type = httpd->cbs->getmimetype (httpd, file->path); - /*TODO: how to handle an error... */ - } + if (file->range.to >= st.size) file->range.to = st.size - 1; #if (QSE_SIZEOF_LONG_LONG > 0) x = qse_httpd_entaskformat ( @@ -1318,13 +1093,13 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); file->version.major, file->version.minor, (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), + (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), + (st.mime? st.mime: QSE_MT("")), + (st.mime? QSE_MT("\r\n"): QSE_MT("")), (unsigned long long)(file->range.to - file->range.from + 1), (unsigned long long)file->range.from, (unsigned long long)file->range.to, - (unsigned long long)filesize + (unsigned long long)st.size ); #else x = qse_httpd_entaskformat ( @@ -1333,13 +1108,13 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); file->version.major, file->version.minor, (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), + (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), + (st.mime? st.mime: QSE_MT("")), + (st.mime? QSE_MT("\r\n"): QSE_MT("")), (unsigned long)(file->range.to - file->range.from + 1), (unsigned long)file->range.from, (unsigned long)file->range.to, - (unsigned long)filesize + (unsigned long)st.size ); #endif if (x) @@ -1355,15 +1130,6 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); else { /* TODO: int64 format.... don't hard code it llu */ - const qse_mchar_t* mime_type = QSE_NULL; - - if (httpd->cbs->getmimetype) - { - httpd->errnum = QSE_HTTPD_ENOERR; - mime_type = httpd->cbs->getmimetype (httpd, file->path); -/*TODO: how to handle an error... */ - } - /* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header. * if the reply doesn't contain 'Connection: keep-alive', it didn't * close connection.*/ @@ -1373,10 +1139,10 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); QSE_MT("HTTP/%d.%d 200 OK\r\nConnection: %s\r\n%s%s%sContent-Length: %llu\r\n\r\n"), file->version.major, file->version.minor, (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long long)filesize + (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), + (st.mime? st.mime: QSE_MT("")), + (st.mime? QSE_MT("\r\n"): QSE_MT("")), + (unsigned long long)st.size ); #else x = qse_httpd_entaskformat ( @@ -1385,16 +1151,15 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); file->version.major, file->version.minor, (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (mime_type? QSE_MT("Content-Type: "): QSE_MT("")), - (mime_type? mime_type: QSE_MT("")), - (mime_type? QSE_MT("\r\n"): QSE_MT("")), - (unsigned long)filesize + (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), + (st.mime? st.mime: QSE_MT("")), + (st.mime? QSE_MT("\r\n"): QSE_MT("")), + (unsigned long)st.size ); #endif if (x) { - x = entask_file_segment ( - httpd, client, x, handle, 0, filesize); + x = entask_file_segment (httpd, client, x, handle, 0, st.size); } } @@ -1772,6 +1537,7 @@ qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), qse_htre_getqpathptr(req), qse_htre_getqpat qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), proto); } // TODO: HTTP_ headers. +// TODO: REMOTE_USER ... #if 0 qse_env_insertmbs (env, "SERVER_NAME", @@ -2573,19 +2339,6 @@ static QSE_INLINE qse_httpd_task_t* entask_cgi ( qse_httpd_task_t task; task_cgi_arg_t arg; -#if 0 - int x; - -/* TODO: NEED TO CHECK IF it's a regular file and executable?? -directory may be treated as executable??? -*/ - x = httpd->cbs->path.executable (httpd, path); - if (x == 0) - return qse_httpd_entaskerror (httpd, client, pred, 403, req); - else if (x <= -1) - return qse_httpd_entaskerror (httpd, client, pred, 404, req); -#endif - arg.path = path; arg.req = req; arg.nph = nph; diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index ac417150..79a83a64 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -5,9 +5,11 @@ #include #include #include +#include #include #include +#include #if defined(_WIN32) # include #else @@ -18,6 +20,8 @@ #endif #include +#include +#include // TODO: remove this and export structured needed like qse_httpd_client_t @@ -226,22 +230,59 @@ static int mux_writable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec) /* ------------------------------------------------------------------- */ -static int path_executable (qse_httpd_t* httpd, const qse_mchar_t* path) +static int file_executable (qse_httpd_t* httpd, const qse_mchar_t* path) { if (access (path, X_OK) == -1) return (errno == EACCES)? 0 /*no*/: -1 /*error*/; return 1; /* yes */ } -/* ------------------------------------------------------------------- */ +static int file_stat ( + qse_httpd_t* httpd, const qse_mchar_t* path, qse_httpd_stat_t* hst) +{ + struct stat st; + +/* TODO: lstat? or stat? */ + if (stat (path, &st) <= -1) + { + qse_httpd_seterrnum (httpd, + (errno == ENOENT? QSE_HTTPD_ENOENT: + errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS)); + return -1; + } + + /* stating for a file. it should be a regular file. + * i don't allow other file types. */ + if (!S_ISREG(st.st_mode)) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES); + return -1; + } + + memset (hst, 0, QSE_SIZEOF(*hst)); + + hst->size = st.st_size; +#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + hst->mtime = QSE_SECNSEC_TO_MSEC(st.st_mtim.tv_sec,st.st_mtim.tv_nsec); +#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + hst->mtime = QSE_SECNSEC_TO_MSEC(st.st_mtimespec.tv_sec,st.st_mtimespec.tv_nsec); +#else + hst->mtime = st.st_mtime * QSE_MSECS_PER_SEC; +#endif + + hst->mime = qse_mbsend (path, QSE_MT(".html"))? QSE_MT("text/html"): + qse_mbsend (path, QSE_MT(".txt"))? QSE_MT("text/plain"): + qse_mbsend (path, QSE_MT(".jpg"))? QSE_MT("image/jpeg"): + qse_mbsend (path, QSE_MT(".mp4"))? QSE_MT("video/mp4"): + qse_mbsend (path, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"): QSE_NULL; + return 0; +} static int file_ropen ( - qse_httpd_t* httpd, const qse_mchar_t* path, - qse_ubi_t* handle, qse_foff_t* size) + qse_httpd_t* httpd, const qse_mchar_t* path, qse_ubi_t* handle) { int fd; int flags; - struct stat st; flags = O_RDONLY; #if defined(O_LARGEFILE) @@ -261,25 +302,6 @@ qse_printf (QSE_T("opening file [%hs] for reading\n"), path); flags = fcntl (fd, F_GETFD); if (flags >= 0) fcntl (fd, F_SETFD, flags | FD_CLOEXEC); -/* TODO: fstat64??? */ - if (fstat (fd, &st) <= -1) - { - qse_httpd_seterrnum (httpd, - (errno == ENOENT? QSE_HTTPD_ENOENT: - errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS)); - close (fd); - return -1; - } - -/* check if it is a link. symbolic link??? */ - if (!S_ISREG(st.st_mode)) - { - qse_httpd_seterrnum (httpd, QSE_HTTPD_EACCES); - close (fd); - return -1; - } - - *size = (st.st_size <= 0)? 0: st.st_size; handle->i = fd; qse_printf (QSE_T("opened file %hs\n"), path); return 0; @@ -617,16 +639,6 @@ static int handle_request ( return process_request (httpd, client, req, 0); } -const qse_mchar_t* get_mime_type (qse_httpd_t* httpd, const qse_mchar_t* path) -{ - if (qse_mbsend (path, QSE_MT(".html"))) return QSE_MT("text/html"); - if (qse_mbsend (path, QSE_MT(".txt"))) return QSE_MT("text/plain"); - if (qse_mbsend (path, QSE_MT(".jpg"))) return QSE_MT("image/jpeg"); - if (qse_mbsend (path, QSE_MT(".mp4"))) return QSE_MT("video/mp4"); - if (qse_mbsend (path, QSE_MT(".mp3"))) return QSE_MT("audio/mpeg"); - return QSE_NULL; -} - int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path) { return 404; @@ -637,11 +649,10 @@ static qse_httpd_cbs_t httpd_cbs = /* multiplexer */ { mux_readable, mux_writable }, - /* path operation */ - { path_executable }, - /* file operation */ - { file_ropen, + { file_executable, + file_stat, + file_ropen, file_wopen, file_close, file_read, @@ -659,7 +670,6 @@ static qse_httpd_cbs_t httpd_cbs = peek_request, handle_request, - get_mime_type, list_directory };