From 6c8755de002bd0817a056a0eb555d154db522296 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 28 Feb 2012 09:41:01 +0000 Subject: [PATCH] deleted more system dependent code from qse_httpd_t --- qse/include/qse/cmn/ipad.h | 15 - qse/include/qse/cmn/nwad.h | 34 +- qse/include/qse/net/httpd.h | 57 ++- qse/lib/cmn/nwad.c | 224 +++++---- qse/lib/net/Makefile.am | 2 +- qse/lib/net/Makefile.in | 6 +- qse/lib/net/{httpd_task.c => httpd-task.c} | 54 +- qse/lib/net/httpd.c | 546 ++++++--------------- qse/lib/net/httpd.h | 55 +-- qse/samples/cmn/nwad01.c | 6 +- qse/samples/net/http01.c | 278 ++++++++++- 11 files changed, 669 insertions(+), 608 deletions(-) rename qse/lib/net/{httpd_task.c => httpd-task.c} (97%) diff --git a/qse/include/qse/cmn/ipad.h b/qse/include/qse/cmn/ipad.h index 58b56db8..1eee5462 100644 --- a/qse/include/qse/cmn/ipad.h +++ b/qse/include/qse/cmn/ipad.h @@ -39,21 +39,6 @@ struct qse_ipad6_t }; #include -struct qse_ipad_t -{ - enum - { - QSE_IPAD_V4, - QSE_IPAD_V6 - } type; - - union - { - qse_ipad4_t v4; - qse_ipad6_t v6; - } u; -}; - #ifdef __cplusplus extern "C" { #endif diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h index cf4ec12c..94e2fd28 100644 --- a/qse/include/qse/cmn/nwad.h +++ b/qse/include/qse/cmn/nwad.h @@ -52,6 +52,22 @@ struct qse_nwad_t } u; }; +enum qse_nwadtostr_flag_t +{ + QSE_NWADTOSTR_ADDR = (1 << 0), +#define QSE_NWADTOMBS_ADDR QSE_NWADTOSTR_ADDR +#define QSE_NWADTOWCS_ADDR QSE_NWADTOSTR_ADDR + + QSE_NWADTOSTR_PORT = (1 << 1), +#define QSE_NWADTOMBS_PORT QSE_NWADTOSTR_PORT +#define QSE_NWADTOWCS_PORT QSE_NWADTOSTR_PORT + + QSE_NWADTOSTR_ALL = (QSE_NWADTOSTR_ADDR | QSE_NWADTOSTR_PORT) +#define QSE_NWADTOMBS_ALL QSE_NWADTOSTR_ALL +#define QSE_NWADTOWCS_ALL QSE_NWADTOSTR_ALL +}; + + #ifdef __cplusplus extern "C" { #endif @@ -81,23 +97,25 @@ int qse_wcsntonwad ( qse_size_t qse_nwadtombs ( const qse_nwad_t* nwad, qse_mchar_t* mbs, - qse_size_t len + qse_size_t len, + int flags ); qse_size_t qse_nwadtowcs ( const qse_nwad_t* nwad, qse_wchar_t* wcs, - qse_size_t len + qse_size_t len, + int flags ); #if defined(QSE_CHAR_IS_MCHAR) -# define qse_strtonwad(ptr,nwad) qse_mbstonwad(ptr,nwad) -# define qse_strntonwad(ptr,len,nwad) qse_mbsntonwad(ptr,len,nwad) -# define qse_nwadtostr(nwad,ptr,len) qse_nwadtombs(nwad,ptr,len) +# define qse_strtonwad(ptr,nwad) qse_mbstonwad(ptr,nwad) +# define qse_strntonwad(ptr,len,nwad) qse_mbsntonwad(ptr,len,nwad) +# define qse_nwadtostr(nwad,ptr,len,flags) qse_nwadtombs(nwad,ptr,len,flags) #else -# define qse_strtonwad(ptr,nwad) qse_wcstonwad(ptr,nwad) -# define qse_strntonwad(ptr,len,nwad) qse_wcsntonwad(ptr,len,nwad) -# define qse_nwadtostr(nwad,ptr,len) qse_nwadtowcs(nwad,ptr,len) +# define qse_strtonwad(ptr,nwad) qse_wcstonwad(ptr,nwad) +# define qse_strntonwad(ptr,len,nwad) qse_wcsntonwad(ptr,len,nwad) +# define qse_nwadtostr(nwad,ptr,len,flags) qse_nwadtowcs(nwad,ptr,len,flags) #endif #ifdef __cplusplus diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index 2aaacd51..7a50018c 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -24,6 +24,7 @@ #include #include #include +#include #include typedef struct qse_httpd_t qse_httpd_t; @@ -32,17 +33,25 @@ typedef struct qse_httpd_client_t qse_httpd_client_t; enum qse_httpd_errnum_t { QSE_HTTPD_ENOERR, + QSE_HTTPD_ENOMEM, QSE_HTTPD_EINVAL, - QSE_HTTPD_ENOENT, QSE_HTTPD_EACCES, - QSE_HTTPD_EINTERN, + QSE_HTTPD_ENOENT, + QSE_HTTPD_EEXIST, + QSE_HTTPD_EINTR, + QSE_HTTPD_EAGAIN, + QSE_HTTPD_EIOMUX, - QSE_HTTPD_ESUBSYS, - QSE_HTTPD_ESOCKET, QSE_HTTPD_EDISCON, /* client disconnnected */ QSE_HTTPD_EBADREQ, /* bad request */ - QSE_HTTPD_ETASK + QSE_HTTPD_ETASK, + + QSE_HTTPD_EINTERN, + QSE_HTTPD_ESYSERR, + QSE_HTTPD_ENOIMPL, + + QSE_HTTPD_EOTHER }; typedef enum qse_httpd_errnum_t qse_httpd_errnum_t; @@ -60,9 +69,28 @@ struct qse_httpd_stat_t const qse_mchar_t* mime; }; +typedef struct qse_httpd_server_t qse_httpd_server_t; +struct qse_httpd_server_t +{ + qse_httpd_server_t* next; + + qse_nwad_t nwad; + int secure; + + /* set by server.open callback */ + qse_ubi_t handle; +}; + typedef struct qse_httpd_cbs_t qse_httpd_cbs_t; struct qse_httpd_cbs_t { + struct + { + int (*open) (qse_httpd_t* httpd, qse_httpd_server_t* server); + void (*close) (qse_httpd_t* httpd, qse_httpd_server_t* server); + int (*accept) (qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client); + } server; + struct { int (*readable) ( @@ -98,16 +126,27 @@ struct qse_httpd_cbs_t struct { + void (*close) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); + + void (*shutdown) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); + /* action */ - qse_ssize_t (*recv) (qse_httpd_t* httpd, + qse_ssize_t (*recv) ( + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_mchar_t* buf, qse_size_t bufsize); - qse_ssize_t (*send) (qse_httpd_t* httpd, + qse_ssize_t (*send) ( + qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* buf, qse_size_t bufsize); - qse_ssize_t (*sendfile) (qse_httpd_t* httpd, + qse_ssize_t (*sendfile) ( + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_ubi_t handle, qse_foff_t* offset, qse_size_t count); @@ -229,7 +268,7 @@ void qse_httpd_stop ( ); -int qse_httpd_addlistener ( +int qse_httpd_addserver ( qse_httpd_t* httpd, const qse_char_t* uri ); diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c index c8517772..07a53f07 100644 --- a/qse/lib/cmn/nwad.c +++ b/qse/lib/cmn/nwad.c @@ -397,140 +397,194 @@ done: return 0; } -qse_size_t qse_nwadtombs (const qse_nwad_t* nwad, qse_mchar_t* buf, qse_size_t len) +qse_size_t qse_nwadtombs ( + const qse_nwad_t* nwad, qse_mchar_t* buf, qse_size_t len, int flags) { qse_size_t xlen = 0; + /* unsupported types will result in an empty string */ + switch (nwad->type) { case QSE_NWAD_IN4: - if (xlen + 1 < len) + if (flags & QSE_NWADTOMBS_ADDR) { - xlen = qse_ipad4tombs (&nwad->u.in4.addr, buf, len); - if (xlen + 1 < len && nwad->u.in4.port != 0) + if (xlen + 1 >= len) goto done; + xlen += qse_ipad4tombs (&nwad->u.in4.addr, buf, len); + } + + if (flags & QSE_NWADTOMBS_PORT) + { + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in4.port != 0) { - buf[xlen++] = QSE_MT(':'); - if (xlen + 1 < len) + if (flags & QSE_NWADTOMBS_ADDR) { - xlen += qse_fmtuintmaxtombs ( - &buf[xlen], len - xlen, - qse_ntoh16(nwad->u.in4.port), - 10, 0, QSE_WT('\0'), QSE_NULL); + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT(':'); } + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtombs ( + &buf[xlen], len - xlen, + qse_ntoh16(nwad->u.in4.port), + 10, 0, QSE_MT('\0'), QSE_NULL); } } break; case QSE_NWAD_IN6: - if (xlen + 1 < len) + if (flags & QSE_NWADTOMBS_PORT) { - if (nwad->u.in6.port != 0) buf[xlen++] = QSE_MT('['); - - if (xlen + 1 < len) + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in6.port != 0) { - xlen += qse_ipad6tombs (&nwad->u.in6.addr, buf, len); - if (xlen + 1 < len && nwad->u.in6.scope != 0) - { - buf[xlen++] = QSE_MT('%'); - if (xlen + 1 < len) - { - xlen += qse_fmtuintmaxtombs ( - &buf[xlen], len - xlen, - nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); - } - } - - if (xlen + 1 < len && nwad->u.in6.port != 0) - { - buf[xlen++] = QSE_MT(']'); - if (xlen + 1 < len) - { - buf[xlen++] = QSE_MT(':'); - if (xlen + 1 < len) - { - xlen += qse_fmtuintmaxtombs ( - &buf[xlen], len - xlen, - qse_ntoh16(nwad->u.in6.port), - 10, 0, QSE_WT('\0'), QSE_NULL); - } - } - } + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT('['); } - } + + if (flags & QSE_NWADTOMBS_ADDR) + { + if (xlen + 1 >= len) goto done; + xlen += qse_ipad6tombs (&nwad->u.in6.addr, &buf[xlen], len - xlen); + + if (nwad->u.in6.scope != 0) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT('%'); + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtombs ( + &buf[xlen], len - xlen, + nwad->u.in6.scope, 10, 0, QSE_MT('\0'), QSE_NULL); + } + } + + if (flags & QSE_NWADTOMBS_PORT) + { + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in6.port != 0) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT(']'); + + if (flags & QSE_NWADTOMBS_ADDR) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT(':'); + } + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtombs ( + &buf[xlen], len - xlen, + qse_ntoh16(nwad->u.in6.port), + 10, 0, QSE_MT('\0'), QSE_NULL); + } + } + break; } - if (xlen + 1 < len) buf[xlen] = QSE_MT('\0'); +done: + if (xlen < len) buf[xlen] = QSE_MT('\0'); return xlen; } -qse_size_t qse_nwadtowcs (const qse_nwad_t* nwad, qse_wchar_t* buf, qse_size_t len) + +qse_size_t qse_nwadtowcs ( + const qse_nwad_t* nwad, qse_wchar_t* buf, qse_size_t len, int flags) { qse_size_t xlen = 0; + /* unsupported types will result in an empty string */ + switch (nwad->type) { case QSE_NWAD_IN4: - if (xlen + 1 < len) + if (flags & QSE_NWADTOWCS_ADDR) { - xlen = qse_ipad4towcs (&nwad->u.in4.addr, buf, len); - if (xlen + 1 < len && nwad->u.in4.port != 0) + if (xlen + 1 >= len) goto done; + xlen += qse_ipad4towcs (&nwad->u.in4.addr, buf, len); + } + + if (flags & QSE_NWADTOWCS_PORT) + { + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in4.port != 0) { - buf[xlen++] = QSE_WT(':'); - if (xlen + 1 < len) + if (flags & QSE_NWADTOMBS_ADDR) { - xlen += qse_fmtuintmaxtowcs ( - &buf[xlen], len - xlen, - qse_ntoh16(nwad->u.in4.port), - 10, 0, QSE_WT('\0'), QSE_NULL); + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT(':'); } + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtowcs ( + &buf[xlen], len - xlen, + qse_ntoh16(nwad->u.in4.port), + 10, 0, QSE_WT('\0'), QSE_NULL); } } break; case QSE_NWAD_IN6: - if (xlen + 1 < len) + if (flags & QSE_NWADTOWCS_PORT) { - if (nwad->u.in6.port != 0) buf[xlen++] = QSE_WT('['); - - if (xlen + 1 < len) + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in6.port != 0) { - xlen += qse_ipad6towcs (&nwad->u.in6.addr, &buf[xlen], len - xlen); - if (xlen + 1 < len && nwad->u.in6.scope != 0) - { - buf[xlen++] = QSE_WT('%'); - if (xlen + 1 < len) - { - xlen += qse_fmtuintmaxtowcs ( - &buf[xlen], len - xlen, - nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); - } - } - - if (xlen + 1 < len && nwad->u.in6.port != 0) - { - buf[xlen++] = QSE_WT(']'); - if (xlen + 1 < len) - { - buf[xlen++] = QSE_WT(':'); - if (xlen + 1 < len) - { - xlen += qse_fmtuintmaxtowcs ( - &buf[xlen], len - xlen, - qse_ntoh16(nwad->u.in6.port), - 10, 0, QSE_WT('\0'), QSE_NULL); - } - } - } + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT('['); } - } + + if (flags & QSE_NWADTOWCS_ADDR) + { + if (xlen + 1 >= len) goto done; + xlen += qse_ipad6towcs (&nwad->u.in6.addr, &buf[xlen], len - xlen); + + if (nwad->u.in6.scope != 0) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT('%'); + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtowcs ( + &buf[xlen], len - xlen, + nwad->u.in6.scope, 10, 0, QSE_WT('\0'), QSE_NULL); + } + } + + if (flags & QSE_NWADTOWCS_PORT) + { + if (!(flags & QSE_NWADTOMBS_ADDR) || + nwad->u.in6.port != 0) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT(']'); + + if (flags & QSE_NWADTOMBS_ADDR) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT(':'); + } + + if (xlen + 1 >= len) goto done; + xlen += qse_fmtuintmaxtowcs ( + &buf[xlen], len - xlen, + qse_ntoh16(nwad->u.in6.port), + 10, 0, QSE_WT('\0'), QSE_NULL); + } + } + break; } +done: if (xlen < len) buf[xlen] = QSE_WT('\0'); return xlen; } + diff --git a/qse/lib/net/Makefile.am b/qse/lib/net/Makefile.am index b478ae79..461d3f6e 100644 --- a/qse/lib/net/Makefile.am +++ b/qse/lib/net/Makefile.am @@ -12,7 +12,7 @@ libqsenet_la_SOURCES = \ htrd.c \ httpd.h \ httpd.c \ - httpd_task.c + httpd-task.c libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) libqsenet_la_LIBADD = -lqsecmn diff --git a/qse/lib/net/Makefile.in b/qse/lib/net/Makefile.in index 8de866de..f3663132 100644 --- a/qse/lib/net/Makefile.in +++ b/qse/lib/net/Makefile.in @@ -73,7 +73,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libqsenet_la_DEPENDENCIES = am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \ - httpd_task.lo + httpd-task.lo libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS) libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -255,7 +255,7 @@ libqsenet_la_SOURCES = \ htrd.c \ httpd.h \ httpd.c \ - httpd_task.c + httpd-task.c libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) libqsenet_la_LIBADD = -lqsecmn @@ -336,8 +336,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htrd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htre.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.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_task.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd-task.c similarity index 97% rename from qse/lib/net/httpd_task.c rename to qse/lib/net/httpd-task.c index 1193ffd3..b889198f 100644 --- a/qse/lib/net/httpd_task.c +++ b/qse/lib/net/httpd-task.c @@ -41,7 +41,7 @@ static int task_main_disconnect ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { - shutdown (client->handle.i, SHUT_RDWR); + httpd->cbs->client.shutdown (httpd, client); return 0; } @@ -1497,46 +1497,20 @@ qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), qse_htre_getqpathptr(req), qse_htre_getqpat qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp); } - // TODO: SERVER_HOST, REMOTE_HOST, { - qse_mchar_t port[16]; - snprintf (port, QSE_COUNTOF(port), - QSE_MT("%d"), (int)ntohs(client->local_addr.in4.sin_port)); - qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), port); - - snprintf (port, QSE_COUNTOF(port), - QSE_MT("%d"), (int)ntohs(client->remote_addr.in4.sin_port)); - qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), port); - } - -#if defined(AF_INET6) - if (client->local_addr.in4.sin_family == AF_INET6) - { - qse_mchar_t ipaddr[128]; - inet_ntop (client->local_addr.in6.sin6_family, &client->local_addr.in6.sin6_addr, ipaddr, QSE_COUNTOF(ipaddr)); - qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), ipaddr); - } - else -#endif - { - qse_mchar_t ipaddr[128]; - inet_ntop (client->local_addr.in4.sin_family, &client->local_addr.in4.sin_addr, ipaddr, QSE_COUNTOF(ipaddr)); - qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), ipaddr); - } - -#if defined(AF_INET6) - if (client->remote_addr.in4.sin_family == AF_INET6) - { - qse_mchar_t ipaddr[128]; - inet_ntop (client->remote_addr.in6.sin6_family, &client->remote_addr.in6.sin6_addr, ipaddr, QSE_COUNTOF(ipaddr)); - qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), ipaddr); - } - else -#endif - { - qse_mchar_t ipaddr[128]; - inet_ntop (client->remote_addr.in4.sin_family, &client->remote_addr.in4.sin_addr, ipaddr, QSE_COUNTOF(ipaddr)); - qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), ipaddr); + qse_mchar_t addr[128]; + qse_nwadtombs (&client->local_addr, + addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT); + qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), addr); + qse_nwadtombs (&client->local_addr, + addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR); + qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), addr); + qse_nwadtombs (&client->remote_addr, + addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_PORT); + qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), addr); + qse_nwadtombs (&client->remote_addr, + addr, QSE_COUNTOF(addr), QSE_NWADTOMBS_ADDR); + qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), addr); } { diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 7bb2fe6c..d6cad7b4 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -29,11 +29,7 @@ #include #include #include - -#include -#include -#include -#include +#include #include @@ -50,7 +46,8 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd) #define DEFAULT_PORT 80 #define DEFAULT_SECURE_PORT 443 -static void free_listener_list (qse_httpd_t* httpd, listener_t* l); +static void free_server_list ( + qse_httpd_t* httpd, qse_httpd_server_t* server); qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) { @@ -80,7 +77,9 @@ int qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr) { QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd)); httpd->mmgr = mmgr; - httpd->listener.max = -1; + +/* TODO: abstract away this field */ + httpd->server.max = -1; return 0; } @@ -88,8 +87,8 @@ int qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr) void qse_httpd_fini (qse_httpd_t* httpd) { /* TODO */ - free_listener_list (httpd, httpd->listener.list); - httpd->listener.list = QSE_NULL; + free_server_list (httpd, httpd->server.list); + httpd->server.list = QSE_NULL; } void qse_httpd_stop (qse_httpd_t* httpd) @@ -255,133 +254,151 @@ static qse_htrd_recbs_t htrd_recbs = htrd_handle_request }; -static void deactivate_listener (qse_httpd_t* httpd, listener_t* l) +/* --------------------------------------------------- */ + +static void deactivate_servers (qse_httpd_t* httpd) { - QSE_ASSERT (l->handle >= 0); + qse_httpd_server_t* server; -/* TODO: callback httpd->cbs.listener_deactivated (httpd, l);*/ -/* TODO: suport https... */ - close (l->handle); - l->handle = -1; -} - -static int get_listener_sockaddr (const listener_t* l, sockaddr_t* addr) -{ - int addrsize; - - QSE_MEMSET (addr, 0, QSE_SIZEOF(*addr)); - - switch (l->family) + for (server = httpd->server.list; server; server = server->next) { - case AF_INET: - { - addr->in4.sin_family = l->family; - addr->in4.sin_addr = l->addr.in4; - addr->in4.sin_port = htons (l->port); - addrsize = QSE_SIZEOF(addr->in4); - break; - } - -#ifdef AF_INET6 - case AF_INET6: - { - addr->in6.sin6_family = l->family; - addr->in6.sin6_addr = l->addr.in6; - addr->in6.sin6_port = htons (l->port); - /* TODO: addr.in6.sin6_scope_id */ - addrsize = QSE_SIZEOF(addr->in6); - break; - } -#endif - - default: - { - QSE_ASSERT (!"This should never happen"); - } + httpd->cbs->server.close (httpd, server); } - return addrsize; + FD_ZERO (&httpd->server.set); + httpd->server.max = -1; } -static int activate_listener (qse_httpd_t* httpd, listener_t* l) +static int activate_servers (qse_httpd_t* httpd) { -/* TODO: suport https... */ - int s = -1, flag; - sockaddr_t addr; - int addrsize; + qse_httpd_server_t* server; - QSE_ASSERT (l->handle <= -1); +/* TODO: delete these two variables */ + fd_set server_set; + int server_max = -1; - s = socket (l->family, SOCK_STREAM, IPPROTO_TCP); - if (s <= -1) goto oops_esocket; + FD_ZERO (&server_set); - flag = 1; - setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, QSE_SIZEOF(flag)); + for (server = httpd->server.list; server; server = server->next) + { + if (httpd->cbs->server.open (httpd, server) <= -1) + { + } - addrsize = get_listener_sockaddr (l, &addr); +/* TODO: abstract away these 2 lines to a callback ... */ + FD_SET (server->handle.i, &server_set); + if (server->handle.i >= server_max) server_max = server->handle.i; + } - /* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the - * address size for AF_INET. */ - /*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/ - if (bind (s, (struct sockaddr*)&addr, addrsize) <= -1) goto oops_esocket; - if (listen (s, 10) <= -1) goto oops_esocket; +/* abstract away these 2 lines also */ + httpd->server.set = server_set; + httpd->server.max = server_max; + return 0; +} + +static void free_server_list (qse_httpd_t* httpd, qse_httpd_server_t* server) +{ + while (server) + { + qse_httpd_server_t* next = server->next; + + httpd->cbs->server.close (httpd, server); + qse_httpd_freemem (httpd, server); + + server = next; + } +} + +static qse_httpd_server_t* parse_server_uri ( + qse_httpd_t* httpd, const qse_char_t* uri) +{ + qse_httpd_server_t* server; + qse_uint16_t default_port; + qse_cstr_t tmp; + + server = qse_httpd_allocmem (httpd, QSE_SIZEOF(*server)); + if (server == QSE_NULL) goto oops; /* alloc set error number. */ + + QSE_MEMSET (server, 0, QSE_SIZEOF(*server)); + + /* check the protocol part */ + tmp.ptr = uri; + while (*uri != QSE_T(':')) + { + if (*uri == QSE_T('\0')) + { + httpd->errnum = QSE_HTTPD_EINVAL; + goto oops; + } + uri++; + } + tmp.len = uri - tmp.ptr; + if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0) + { + server->secure = 0; + default_port = DEFAULT_PORT; + } + else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0) + { + server->secure = 1; + default_port = DEFAULT_SECURE_PORT; + } + else goto oops; - flag = fcntl (s, F_GETFL); - if (flag >= 0) fcntl (s, F_SETFL, flag | O_NONBLOCK); - fcntl (s, F_SETFD, FD_CLOEXEC); - - l->handle = s; - s = -1; - - return 0; - -oops_esocket: - httpd->errnum = QSE_HTTPD_ESOCKET; - if (s >= 0) close (s); - return -1; -} - -static void deactivate_listeners (qse_httpd_t* httpd) -{ - listener_t* l; - - for (l = httpd->listener.list; l; l = l->next) + uri++; /* skip : */ + if (*uri != QSE_T('/')) { - if (l->handle >= 0) deactivate_listener (httpd, l); + httpd->errnum = QSE_HTTPD_EINVAL; + goto oops; + } + uri++; /* skip / */ + if (*uri != QSE_T('/')) + { + httpd->errnum = QSE_HTTPD_EINVAL; + goto oops; + } + uri++; /* skip / */ + + if (qse_strtonwad (uri, &server->nwad) <= -1) + { + httpd->errnum = QSE_HTTPD_EINVAL; + goto oops; } - FD_ZERO (&httpd->listener.set); - httpd->listener.max = -1; -} - -static int activate_listeners (qse_httpd_t* httpd) -{ - listener_t* l; - fd_set listener_set; - int listener_max = -1; - - FD_ZERO (&listener_set); - for (l = httpd->listener.list; l; l = l->next) + if (server->nwad.type == QSE_NWAD_IN4) { - if (l->handle <= -1) - { - if (activate_listener (httpd, l) <= -1) goto oops; -/*TODO: callback httpd->cbs.listener_activated (httpd, l);*/ - } - - FD_SET (l->handle, &listener_set); - if (l->handle >= listener_max) listener_max = l->handle; + if (server->nwad.u.in4.port == 0) + server->nwad.u.in4.port = qse_hton16(default_port); + } + else if (server->nwad.type == QSE_NWAD_IN6) + { + if (server->nwad.u.in6.port == 0) + server->nwad.u.in6.port = qse_hton16(default_port); } - httpd->listener.set = listener_set; - httpd->listener.max = listener_max; - return 0; + return server; oops: - deactivate_listeners (httpd); - return -1; + if (server) qse_httpd_freemem (httpd, server); + return QSE_NULL; } + +int qse_httpd_addserver (qse_httpd_t* httpd, const qse_char_t* uri) +{ + qse_httpd_server_t* server; + + server = parse_server_uri (httpd, uri); + if (server == QSE_NULL) return -1; + + server->next = httpd->server.list; + httpd->server.list = server; + + return 0; +} + +/* --------------------------------------------------- */ + static void init_client_array (qse_httpd_t* httpd) { client_array_t* array = &httpd->client.array; @@ -406,7 +423,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Debug: closing socket %d\n"), array->data[fd].ha if (httpd->cbs->client.closed) httpd->cbs->client.closed (httpd, &array->data[fd]); - close (array->data[fd].handle.i); + httpd->cbs->client.close (httpd, &array->data[fd]); array->size--; } } @@ -480,79 +497,41 @@ static qse_httpd_client_t* insert_into_client_array ( return &array->data[fd]; } -static int accept_client_from_listener (qse_httpd_t* httpd, listener_t* l) +static int accept_client_from_server ( + qse_httpd_t* httpd, qse_httpd_server_t* server) { - int flag; - -#ifdef HAVE_SOCKLEN_T - socklen_t addrlen; -#else - int addrlen; -#endif qse_httpd_client_t clibuf; qse_httpd_client_t* client; QSE_MEMSET (&clibuf, 0, QSE_SIZEOF(clibuf)); - clibuf.secure = l->secure; - addrlen = QSE_SIZEOF(clibuf.remote_addr); - clibuf.handle.i = accept ( - l->handle, (struct sockaddr*)&clibuf.remote_addr, &addrlen); - if (clibuf.handle.i <= -1) - { - httpd->errnum = QSE_HTTPD_ESOCKET; -qse_fprintf (QSE_STDERR, QSE_T("Error: accept returned failure\n")); - goto oops; - } + if (httpd->cbs->server.accept (httpd, server, &clibuf) <= -1) return -1; - /* select() uses a fixed-size array so the file descriptor can not - * exceeded FD_SETSIZE */ - if (clibuf.handle.i >= FD_SETSIZE) - { - close (clibuf.handle.i); -qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); - /* httpd->errnum = QSE_HTTPD_EOVERFLOW; */ - goto oops; - } - - addrlen = QSE_SIZEOF(clibuf.local_addr); - if (getsockname (clibuf.handle.i, (struct sockaddr*)&clibuf.local_addr, &addrlen) <= -1) - get_listener_sockaddr (l, &clibuf.local_addr); - - /* set the nonblock flag in case read() after select() blocks - * for various reasons - data received may be dropped after - * arrival for wrong checksum, for example. */ - flag = fcntl (clibuf.handle.i, F_GETFL); - if (flag >= 0) fcntl (clibuf.handle.i, F_SETFL, flag | O_NONBLOCK); - - flag = fcntl (clibuf.handle.i, F_GETFD); - if (flag >= 0) fcntl (clibuf.handle.i, F_SETFD, flag | FD_CLOEXEC); +/* TODO: check maximum number of client. if exceed call client.close */ + clibuf.secure = server->secure; client = insert_into_client_array (httpd, &clibuf); - if (client == QSE_NULL) { - close (clibuf.handle.i); - goto oops; + httpd->cbs->client.close (httpd, &clibuf); + return -1; } qse_printf (QSE_T("connection %d accepted\n"), clibuf.handle.i); - return 0; - -oops: - return -1; } -static void accept_client_from_listeners (qse_httpd_t* httpd, fd_set* r) +static void accept_client_from_servers (qse_httpd_t* httpd, fd_set* r) { - listener_t* l; + qse_httpd_server_t* server; - for (l = httpd->listener.list; l; l = l->next) + for (server = httpd->server.list; server; server = server->next) { - if (FD_ISSET(l->handle, r)) + /* TODO: abstract this part... */ + if (FD_ISSET(server->handle.i, r)) { - accept_client_from_listener (httpd, l); + accept_client_from_server (httpd, server); + /* TODO: if (accept_client_from_listener (httpd, l) <= -1) httpd->cbs.on_error (httpd, l).... */ } @@ -570,8 +549,8 @@ static int make_fd_set_from_client_array ( /* qse_http_loop() needs to monitor listner handles * to handle a new client connection. */ - max = httpd->listener.max; - *r = httpd->listener.set; + max = httpd->server.max; + *r = httpd->server.set; FD_ZERO (w); for (fd = 0; fd < ca->capa; fd++) @@ -695,22 +674,22 @@ reread: m = httpd->cbs->client.recv (httpd, client, buf, QSE_SIZEOF(buf)); if (m <= -1) { -// TODO: handle errno in the callback... and devise a new return value -// to indicate no data at this momemnt (EAGAIN, EWOULDBLOCK)... -// EINTR to be hnalded inside callback if needed... - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (httpd->errnum == QSE_HTTPD_EAGAIN) { /* nothing to read yet. */ qse_fprintf (QSE_STDERR, QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i); return 0; /* return ok */ } - else if (errno != EINTR) + else if (httpd->errnum == QSE_HTTPD_EINTR) { - httpd->errnum = QSE_HTTPD_ESOCKET; + goto reread; + } + else + { + /* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */ qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), client->handle.i); return -1; } - goto reread; } else if (m == 0) { @@ -748,7 +727,7 @@ int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs) httpd->stopreq = 0; httpd->cbs = cbs; - QSE_ASSERTX (httpd->listener.list != QSE_NULL, + QSE_ASSERTX (httpd->server.list != QSE_NULL, "Add listeners before calling qse_httpd_loop()" ); @@ -756,14 +735,14 @@ int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_cbs_t* cbs) "Set httpd callbacks before calling qse_httpd_loop()" ); - if (httpd->listener.list == QSE_NULL) + if (httpd->server.list == QSE_NULL) { /* no listener specified */ httpd->errnum = QSE_HTTPD_EINVAL; return -1; } - if (activate_listeners (httpd) <= -1) return -1; + if (activate_servers (httpd) <= -1) return -1; init_client_array (httpd); @@ -794,7 +773,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n")); } /* check the listener activity */ - accept_client_from_listeners (httpd, &r); + accept_client_from_servers (httpd, &r); /* check the client activity */ for (fd = 0; fd < httpd->client.array.capa; fd++) @@ -904,218 +883,11 @@ qse_printf (QSE_T(".....TRIGGER WRITABLE....\n")); } fini_client_array (httpd); - deactivate_listeners (httpd); + deactivate_servers (httpd); return 0; } -static void free_listener (qse_httpd_t* httpd, listener_t* l) -{ - if (l->host) qse_httpd_freemem (httpd, l->host); - if (l->handle >= 0) close (l->handle); - qse_httpd_freemem (httpd, l); -} - -static void free_listener_list (qse_httpd_t* httpd, listener_t* l) -{ - while (l) - { - listener_t* cur = l; - l = l->next; - free_listener (httpd, cur); - } -} - -static listener_t* parse_listener_uri ( - qse_httpd_t* httpd, const qse_char_t* uri) -{ - const qse_char_t* p = uri; - listener_t* ltmp = QSE_NULL; - qse_cstr_t tmp; - qse_mchar_t* host; - int x; - - ltmp = qse_httpd_allocmem (httpd, QSE_SIZEOF(*ltmp)); - if (ltmp == QSE_NULL) goto oops; /* alloc set error number. so goto oops */ - - QSE_MEMSET (ltmp, 0, QSE_SIZEOF(*ltmp)); - ltmp->handle = -1; - - /* check the protocol part */ - tmp.ptr = p; - while (*p != QSE_T(':')) - { - if (*p == QSE_T('\0')) goto oops_einval; - p++; - } - tmp.len = p - tmp.ptr; - if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0) - { - ltmp->secure = 0; - ltmp->port = DEFAULT_PORT; - } - else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0) - { - ltmp->secure = 1; - ltmp->port = DEFAULT_SECURE_PORT; - } - else goto oops; - - p++; /* skip : */ - if (*p != QSE_T('/')) goto oops_einval; - p++; /* skip / */ - if (*p != QSE_T('/')) goto oops_einval; - p++; /* skip / */ - -#ifdef AF_INET6 - if (*p == QSE_T('[')) - { - /* IPv6 address */ - p++; /* skip [ */ - - for (tmp.ptr = p; *p != QSE_T(']'); p++) - { - if (*p == QSE_T('\0')) goto oops_einval; - } - - tmp.len = p - tmp.ptr; - ltmp->family = AF_INET6; - - p++; /* skip ] */ - if (*p != QSE_T(':') && *p != QSE_T('\0')) goto oops_einval; - } - else - { -#endif - /* host name or IPv4 address */ - for (tmp.ptr = p; ; p++) - { - if (*p == QSE_T(':') || *p == QSE_T('\0')) break; - } - tmp.len = p - tmp.ptr; - ltmp->family = AF_INET; -#ifdef AF_INET6 - } -#endif - - ltmp->host = qse_strxdup (tmp.ptr, tmp.len, httpd->mmgr); - if (ltmp->host == QSE_NULL) goto oops_enomem; - -#ifdef QSE_CHAR_IS_WCHAR - host = qse_wcstombsdup (ltmp->host, httpd->mmgr); - if (host == QSE_NULL) goto oops_enomem; -#else - host = ltmp->host; -#endif - - x = inet_pton (ltmp->family, host, <mp->addr); -#ifdef QSE_CHAR_IS_WCHAR - qse_httpd_freemem (httpd, host); -#endif - if (x != 1) - { - /* TODO: need to support host names??? - if (getaddrinfo... ).... -or CALL a user callback for name resolution? - if (httpd->cbs.resolve_hostname (httpd, ltmp->host) <= -1) must call this with host before freeing it up???? - */ - goto oops_einval; - } - - if (*p == QSE_T(':')) - { - unsigned int port = 0; - - /* port number */ - p++; - - for (tmp.ptr = p; QSE_ISDIGIT(*p); p++) - port = port * 10 + (*p - QSE_T('0')); - - tmp.len = p - tmp.ptr; - if (tmp.len <= 0 || - tmp.len >= 6 || - port > QSE_TYPE_MAX(unsigned short)) goto oops_einval; - ltmp->port = port; - } - - /* skip spaces */ - while (QSE_ISSPACE(*p)) p++; - - return ltmp; - -oops_einval: - httpd->errnum = QSE_HTTPD_EINVAL; - goto oops; - -oops_enomem: - httpd->errnum = QSE_HTTPD_ENOMEM; - goto oops; - -oops: - if (ltmp) free_listener (httpd, ltmp); - return QSE_NULL; -} - -static int add_listener (qse_httpd_t* httpd, const qse_char_t* uri) -{ - listener_t* lsn; - - lsn = parse_listener_uri (httpd, uri); - if (lsn == QSE_NULL) return -1; - - lsn->next = httpd->listener.list; - httpd->listener.list = lsn; -/* -TODO: mutex protection... -if in the activated state... -activate_additional_listeners (httpd, l) -recalc httpd->listener.set. -recalc httpd->listener.max. -*/ - return 0; -} - -#if 0 -static int delete_listeners (qse_httpd_t* httpd, const qse_char_t* uri) -{ - listener_t* lh, * li, * hl; - - lh = parse_listener_uri (httpd, uri, QSE_NULL); - if (lh == QSE_NULL) return -1; - - for (li = lh; li; li = li->next) - { - for (hl = httpd->listener.list; hl; hl = hl->next) - { - if (li->secure == hl->secuire && - li->addr == hl->addr && - li->port == hl->port) - { - mark_delete - } - } - } -} -#endif - -int qse_httpd_addlistener (qse_httpd_t* httpd, const qse_char_t* uri) -{ - return add_listener (httpd, uri); -} - -#if 0 -int qse_httpd_dellistener (qse_httpd_t* httpd, const qse_char_t* uri) -{ - return delete_listeners (httpd, uri); -} - -void qse_httpd_clearlisteners (qse_httpd_t* httpd) -{ - deactivate_listeners (httpd); - free_listener_list (httpd, httpd->listener.list); - httpd->listener.list = QSE_NULL; -} -#endif +/* --------------------------------------------------- */ qse_httpd_task_t* qse_httpd_entask ( qse_httpd_t* httpd, qse_httpd_client_t* client, diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index 74201470..625bff34 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -25,27 +25,16 @@ #include #include +#include -#include -#include -#include +/* REMOVE THESE headers after abstracting away select()/fd_set */ +#include +#include +#include -#ifndef SHUT_RDWR -# define SHUT_RDWR 2 -#endif typedef struct client_array_t client_array_t; -union sockaddr_t -{ - struct sockaddr_in in4; -#ifdef AF_INET6 - struct sockaddr_in6 in6; -#endif -}; - -typedef union sockaddr_t sockaddr_t; - typedef struct task_queue_node_t task_queue_node_t; struct task_queue_node_t { @@ -58,12 +47,14 @@ struct qse_httpd_client_t { qse_ubi_t handle; qse_ubi_t handle2; + qse_nwad_t local_addr; + qse_nwad_t remote_addr; + + /* ------------------------------ */ int ready; int secure; int bad; - sockaddr_t local_addr; - sockaddr_t remote_addr; qse_htrd_t* htrd; struct @@ -84,26 +75,6 @@ struct client_array_t qse_httpd_client_t* data; }; -typedef struct listener_t listener_t; -struct listener_t -{ - int family;/* AF_INET, AF_INET6 */ - int secure; - - qse_char_t* host; - union - { - struct in_addr in4; -#ifdef AF_INET6 - struct in6_addr in6; -#endif - } addr; - - int port; - int handle; - listener_t* next; -}; - struct qse_httpd_t { QSE_DEFINE_COMMON_FIELDS (httpd) @@ -120,10 +91,10 @@ struct qse_httpd_t struct { - listener_t* list; - fd_set set; - int max; - } listener; + qse_httpd_server_t* list; + fd_set set; + int max; + } server; }; #ifdef __cplusplus diff --git a/qse/samples/cmn/nwad01.c b/qse/samples/cmn/nwad01.c index e07b0dad..03a2203a 100644 --- a/qse/samples/cmn/nwad01.c +++ b/qse/samples/cmn/nwad01.c @@ -105,7 +105,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) } else { - qse_nwadtostr (&nwad, buf, QSE_COUNTOF(buf)); + qse_nwadtostr (&nwad, buf, QSE_COUNTOF(buf), QSE_NWADTOSTR_ALL); qse_printf (QSE_T("Converted <%s> to <%s>\n"), ipstr[i], buf); } } @@ -119,7 +119,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) } else { - qse_nwadtombs (&nwad, mbsbuf, QSE_COUNTOF(mbsbuf)); + qse_nwadtombs (&nwad, mbsbuf, QSE_COUNTOF(mbsbuf), QSE_NWADTOMBS_ALL); qse_printf (QSE_T("Converted <%hs> to <%hs>\n"), ipstr_mbs[i], mbsbuf); } } @@ -133,7 +133,7 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) } else { - qse_nwadtowcs (&nwad, wcsbuf, QSE_COUNTOF(wcsbuf)); + qse_nwadtowcs (&nwad, wcsbuf, QSE_COUNTOF(wcsbuf), QSE_NWADTOWCS_ALL); qse_printf (QSE_T("Converted <%ls> to <%ls>\n"), ipstr_wcs[i], wcsbuf); } } diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index f6866c9f..2c26dead 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -17,6 +17,8 @@ # include # include # include +# include +# include #endif #include @@ -125,6 +127,37 @@ static qse_ssize_t xsendfile_ssl ( return n; } +/* ------------------------------------------------------------------- */ +static qse_httpd_errnum_t syserr_to_errnum (int e) +{ + switch (e) + { + case ENOMEM: + return QSE_HTTPD_ENOMEM; + + case EINVAL: + return QSE_HTTPD_EINVAL; + + case EACCES: + return QSE_HTTPD_EACCES; + + case ENOENT: + return QSE_HTTPD_ENOENT; + + case EEXIST: + return QSE_HTTPD_EEXIST; + + case EINTR: + return QSE_HTTPD_EINTR; + + case EAGAIN: + /*case EWOULDBLOCK:*/ + return QSE_HTTPD_EAGAIN; + + default: + return QSE_HTTPD_ESYSERR; + } +} /* ------------------------------------------------------------------- */ typedef struct httpd_xtn_t httpd_xtn_t; @@ -190,6 +223,190 @@ static void fini_xtn_ssl (httpd_xtn_t* xtn) /* ------------------------------------------------------------------- */ +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 server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) +{ + int fd = -1, flag; +/* TODO: if AF_INET6 is not defined sockaddr_storage is not available... + * create your own union or somehting similar... */ + struct sockaddr_storage addr; + int addrsize; + + addrsize = nwad_to_sockaddr (&server->nwad, &addr); + if (addrsize <= -1) + { + qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); + return -1; + } + + fd = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP); + if (fd <= -1) goto oops; + + flag = 1; + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flag, QSE_SIZEOF(flag)); + + /* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the + * address size for AF_INET. */ + /*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/ + if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1) goto oops; + if (listen (fd, 10) <= -1) goto oops; + + flag = fcntl (fd, F_GETFL); + if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); + + flag = fcntl (fd, F_GETFD); + if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); + + server->handle.i = fd; + return 0; + +oops: + qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); + if (fd >= 0) close (fd); + return -1; +} + +static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server) +{ + close (server->handle.i); +} + +static int server_accept ( + qse_httpd_t* httpd, + qse_httpd_server_t* server, qse_httpd_client_t* client) +{ + struct sockaddr_storage addr; + +#ifdef HAVE_SOCKLEN_T + socklen_t addrlen; +#else + int addrlen; +#endif + int fd, flag; + + addrlen = QSE_SIZEOF(addr); + fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen); + if (fd <= -1) + { + qse_httpd_seterrnum (httpd, syserr_to_errnum (errno)); + return -1; + } + + if (fd >= FD_SETSIZE) + { +qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); + /*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/ + close (fd); + return -1; + } + + flag = fcntl (fd, F_GETFL); + if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); + + flag = fcntl (fd, F_GETFD); + if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); + + if (sockaddr_to_nwad (&addr, &client->remote_addr) <= -1) + { +/* TODO: logging */ + client->remote_addr = server->nwad; + } + + addrlen = QSE_SIZEOF(addr); + if (getsockname (fd, (struct sockaddr*)&addr, &addrlen) <= -1 || + sockaddr_to_nwad (&addr, &client->local_addr) <= -1) + { +/* TODO: logging */ + client->local_addr = server->nwad; + } + + client->handle.i = fd; + return 0; +} + +/* ------------------------------------------------------------------- */ + static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec) { fd_set r; @@ -245,9 +462,7 @@ static int file_stat ( /* 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)); + qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); return -1; } @@ -293,9 +508,7 @@ qse_printf (QSE_T("opening file [%hs] for reading\n"), path); fd = open (path, flags, 0); if (fd <= -1) { - qse_httpd_seterrnum (httpd, - (errno == ENOENT? QSE_HTTPD_ENOENT: - errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS)); + qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); return -1; } @@ -323,9 +536,7 @@ qse_printf (QSE_T("opening file [%hs] for writing\n"), path); fd = open (path, flags, 0644); if (fd <= -1) { - qse_httpd_seterrnum (httpd, - (errno == ENOENT? QSE_HTTPD_ENOENT: - errno == EACCES? QSE_HTTPD_EACCES: QSE_HTTPD_ESUBSYS)); + qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); return -1; } @@ -354,17 +565,39 @@ static qse_ssize_t file_write ( } /* ------------------------------------------------------------------- */ +static void client_close ( + qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + close (client->handle.i); +} + +static void client_shutdown ( + qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + shutdown (client->handle.i, SHUT_RDWR); +} + static qse_ssize_t client_recv ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_mchar_t* buf, qse_size_t bufsize) { if (client->secure) { - return SSL_read (client->handle2.ptr, buf, bufsize); + int ret = SSL_read (client->handle2.ptr, buf, bufsize); + if (ret <= -1) + { + if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_READ) + qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); + else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + } + return ret; } else { - return read (client->handle.i, buf, bufsize); + ssize_t ret = read (client->handle.i, buf, bufsize); + if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); + return ret; } } @@ -374,11 +607,21 @@ static qse_ssize_t client_send ( { if (client->secure) { - return SSL_write (client->handle2.ptr, buf, bufsize); + int ret = SSL_write (client->handle2.ptr, buf, bufsize); + if (ret <= -1) + { + if (SSL_get_error(client->handle2.ptr,ret) == SSL_ERROR_WANT_WRITE) + qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); + else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + } + return ret; } else { - return write (client->handle.i, buf, bufsize); + ssize_t ret = write (client->handle.i, buf, bufsize); + if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); + return ret; } } @@ -665,6 +908,9 @@ int list_directory (qse_httpd_t* httpd, const qse_mchar_t* path) static qse_httpd_cbs_t httpd_cbs = { + /* server */ + { server_open, server_close, server_accept }, + /* multiplexer */ { mux_readable, mux_writable }, @@ -679,7 +925,9 @@ static qse_httpd_cbs_t httpd_cbs = }, /* client connection */ - { client_recv, + { client_close, + client_shutdown, + client_recv, client_send, client_sendfile, client_accepted, @@ -730,7 +978,7 @@ int httpd_main (int argc, qse_char_t* argv[]) for (i = 1; i < argc; i++) { - if (qse_httpd_addlistener (httpd, argv[i]) <= -1) + if (qse_httpd_addserver (httpd, argv[i]) <= -1) { qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listener - %s\n"), argv[i]);