abstracted out most of muplexing code from httpd

This commit is contained in:
hyung-hwan 2012-03-18 14:24:54 +00:00
parent 6c8755de00
commit c55bceb220
5 changed files with 890 additions and 593 deletions

View File

@ -24,6 +24,7 @@
#include <qse/types.h> #include <qse/types.h>
#include <qse/macros.h> #include <qse/macros.h>
#include <qse/net/htre.h> #include <qse/net/htre.h>
#include <qse/net/htrd.h>
#include <qse/cmn/nwad.h> #include <qse/cmn/nwad.h>
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
@ -73,6 +74,7 @@ typedef struct qse_httpd_server_t qse_httpd_server_t;
struct qse_httpd_server_t struct qse_httpd_server_t
{ {
qse_httpd_server_t* next; qse_httpd_server_t* next;
int active;
qse_nwad_t nwad; qse_nwad_t nwad;
int secure; int secure;
@ -81,6 +83,20 @@ struct qse_httpd_server_t
qse_ubi_t handle; qse_ubi_t handle;
}; };
enum qse_httpd_mux_mask_t
{
QSE_HTTPD_MUX_READ = (1 << 0),
QSE_HTTPD_MUX_WRITE = (1 << 1)
};
typedef int (*qse_httpd_muxcb_t) (
qse_httpd_t* httpd,
void* mux,
qse_ubi_t handle,
int mask, /* ORed of qse_httpd_mux_mask_t */
void* cbarg
);
typedef struct qse_httpd_cbs_t qse_httpd_cbs_t; typedef struct qse_httpd_cbs_t qse_httpd_cbs_t;
struct qse_httpd_cbs_t struct qse_httpd_cbs_t
{ {
@ -93,6 +109,14 @@ struct qse_httpd_cbs_t
struct struct
{ {
void* (*open) (qse_httpd_t* httpd);
void (*close) (qse_httpd_t* httpd, void* mux);
int (*addhnd) (
qse_httpd_t* httpd, void* mux, qse_ubi_t handle,
int mask, qse_httpd_muxcb_t cbfun, void* cbarg);
int (*delhnd) (qse_httpd_t* httpd, void* mux, qse_ubi_t handle);
int (*poll) (qse_httpd_t* httpd, void* mux, qse_ntime_t timeout);
int (*readable) ( int (*readable) (
qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t timeout); qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t timeout);
int (*writable) ( int (*writable) (
@ -200,6 +224,8 @@ enum qse_httpd_task_trigger_mask_t
struct qse_httpd_task_t struct qse_httpd_task_t
{ {
/* == PUBLIC == */
/* you must not call another entask functions from within /* you must not call another entask functions from within
* an initailizer. you can call entask functions from within * an initailizer. you can call entask functions from within
* a finalizer and a main function. */ * a finalizer and a main function. */
@ -210,7 +236,50 @@ struct qse_httpd_task_t
int trigger_mask; int trigger_mask;
qse_ubi_t trigger[3]; qse_ubi_t trigger[3];
#if 0
struct
{
int mask; /* QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */
qse_ubi_t handle;
} trigger[3];
#endif
void* ctx; void* ctx;
/* == PRIVATE == */
qse_httpd_task_t* prev;
qse_httpd_task_t* next;
};
struct qse_httpd_client_t
{
/* == PUBLIC == */
qse_ubi_t handle;
qse_ubi_t handle2;
qse_nwad_t local_addr;
qse_nwad_t remote_addr;
/* == PRIVATE == */
qse_htrd_t* htrd;
int secure;
int status;
qse_httpd_client_t* prev;
qse_httpd_client_t* next;
qse_httpd_client_t* bad_next;
qse_httpd_client_t* prev_tasked;
qse_httpd_client_t* next_tasked;
struct
{
int count;
qse_httpd_task_t* head;
qse_httpd_task_t* tail;
} task;
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -257,7 +326,8 @@ void qse_httpd_setoption (
*/ */
int qse_httpd_loop ( int qse_httpd_loop (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_cbs_t* cbs qse_httpd_cbs_t* cbs,
qse_ntime_t timeout
); );
/** /**
@ -288,7 +358,7 @@ void qse_httpd_completecontent (
qse_httpd_task_t* qse_httpd_entask ( qse_httpd_task_t* qse_httpd_entask (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_httpd_task_t* task, const qse_httpd_task_t* task,
qse_size_t xtnsize qse_size_t xtnsize
); );
@ -298,58 +368,37 @@ qse_httpd_task_t* qse_httpd_entask (
qse_httpd_task_t* qse_httpd_entaskdisconnect ( qse_httpd_task_t* qse_httpd_entaskdisconnect (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred qse_httpd_task_t* pred
); );
qse_httpd_task_t* qse_httpd_entasktext ( qse_httpd_task_t* qse_httpd_entasktext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* text const qse_mchar_t* text
); );
qse_httpd_task_t* qse_httpd_entaskstatictext ( qse_httpd_task_t* qse_httpd_entaskstatictext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* text const qse_mchar_t* text
); );
qse_httpd_task_t* qse_httpd_entaskformat ( qse_httpd_task_t* qse_httpd_entaskformat (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* fmt, const qse_mchar_t* fmt,
... ...
); );
/* -------------------------------------------- */ /* -------------------------------------------- */
#if 0
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* qse_httpd_entaskdir (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
qse_ubi_t handle,
int chunked
);
#endif
/* -------------------------------------------- */
qse_httpd_task_t* qse_httpd_entaskerror ( qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_httpd_task_t* pred,
int code, int code,
qse_htre_t* req qse_htre_t* req
); );
@ -357,7 +406,7 @@ qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_task_t* qse_httpd_entaskcontinue ( qse_httpd_task_t* qse_httpd_entaskcontinue (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_httpd_task_t* pred,
qse_htre_t* req qse_htre_t* req
); );
@ -367,7 +416,7 @@ qse_httpd_task_t* qse_httpd_entaskcontinue (
qse_httpd_task_t* qse_httpd_entaskauth ( qse_httpd_task_t* qse_httpd_entaskauth (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_httpd_task_t* pred,
const qse_mchar_t* realm, const qse_mchar_t* realm,
qse_htre_t* req qse_htre_t* req
); );
@ -375,7 +424,7 @@ qse_httpd_task_t* qse_httpd_entaskauth (
qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
qse_htre_t* req qse_htre_t* req
); );
@ -383,7 +432,7 @@ qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_task_t* qse_httpd_entaskfile ( qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
qse_htre_t* req qse_htre_t* req
); );
@ -391,7 +440,7 @@ qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_task_t* qse_httpd_entaskcgi ( qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* path, const qse_mchar_t* path,
qse_htre_t* req qse_htre_t* req
); );
@ -399,7 +448,7 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_task_t* qse_httpd_entasknph ( qse_httpd_task_t* qse_httpd_entasknph (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* path, const qse_mchar_t* path,
qse_htre_t* req qse_htre_t* req
); );

View File

@ -48,7 +48,7 @@ static int task_main_disconnect (
qse_httpd_task_t* qse_httpd_entaskdisconnect ( qse_httpd_task_t* qse_httpd_entaskdisconnect (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred) qse_httpd_task_t* pred)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -86,7 +86,7 @@ static int task_main_statictext (
qse_httpd_task_t* qse_httpd_entaskstatictext ( qse_httpd_task_t* qse_httpd_entaskstatictext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* text) const qse_mchar_t* text)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -144,7 +144,7 @@ static int task_main_text (
qse_httpd_task_t* qse_httpd_entasktext ( qse_httpd_task_t* qse_httpd_entasktext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* text) const qse_mchar_t* text)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -217,7 +217,7 @@ static int task_main_format (
qse_httpd_task_t* qse_httpd_entaskformat ( qse_httpd_task_t* qse_httpd_entaskformat (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* fmt, ...) const qse_mchar_t* fmt, ...)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -315,7 +315,7 @@ qse_printf (QSE_T("SEND: [%.*hs]\n"), (int)l, buf);
static qse_httpd_task_t* entask_error ( static qse_httpd_task_t* entask_error (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, int code, qse_httpd_task_t* pred, int code,
const qse_http_version_t* version, int keepalive) const qse_http_version_t* version, int keepalive)
{ {
const qse_mchar_t* smsg; const qse_mchar_t* smsg;
@ -380,7 +380,7 @@ static qse_httpd_task_t* entask_error (
} }
return qse_httpd_entaskformat ( return qse_httpd_entaskformat (
httpd, client, task, httpd, client, pred,
QSE_MT("HTTP/%d.%d %d %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"), QSE_MT("HTTP/%d.%d %d %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"),
version->major, version->minor, code, smsg, version->major, version->minor, code, smsg,
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")), (keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
@ -390,21 +390,21 @@ static qse_httpd_task_t* entask_error (
qse_httpd_task_t* qse_httpd_entaskerror ( qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, int code, qse_htre_t* req) qse_httpd_task_t* pred, int code, qse_htre_t* req)
{ {
return entask_error ( return entask_error (
httpd, client, task, code, httpd, client, pred, code,
qse_htre_getversion(req), req->attr.keepalive); qse_htre_getversion(req), req->attr.keepalive);
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
qse_httpd_task_t* qse_httpd_entaskcontinue ( qse_httpd_task_t* qse_httpd_entaskcontinue (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_htre_t* req) qse_httpd_task_t* pred, qse_htre_t* req)
{ {
const qse_http_version_t* version = qse_htre_getversion(req); const qse_http_version_t* version = qse_htre_getversion(req);
return qse_httpd_entaskformat ( return qse_httpd_entaskformat (
httpd, client, task, httpd, client, pred,
QSE_MT("HTTP/%d.%d 100 Continue\r\n\r\n"), QSE_MT("HTTP/%d.%d 100 Continue\r\n\r\n"),
version->major, version->minor); version->major, version->minor);
} }
@ -413,7 +413,7 @@ qse_httpd_task_t* qse_httpd_entaskcontinue (
qse_httpd_task_t* qse_httpd_entaskauth ( qse_httpd_task_t* qse_httpd_entaskauth (
qse_httpd_t* httpd, qse_httpd_client_t* client, 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* pred, const qse_mchar_t* realm, qse_htre_t* req)
{ {
const qse_http_version_t* version; const qse_http_version_t* version;
const qse_mchar_t* lmsg; const qse_mchar_t* lmsg;
@ -422,7 +422,7 @@ qse_httpd_task_t* qse_httpd_entaskauth (
lmsg = QSE_MT("<html><head><title>Unauthorized</title></head><body><b>UNAUTHORIZED<b></body></html>"); lmsg = QSE_MT("<html><head><title>Unauthorized</title></head><body><b>UNAUTHORIZED<b></body></html>");
return qse_httpd_entaskformat ( return qse_httpd_entaskformat (
httpd, client, task, httpd, client, pred,
QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nConnection: %s\r\nWWW-Authenticate: Basic realm=\"%s\"\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"), QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nConnection: %s\r\nWWW-Authenticate: Basic realm=\"%s\"\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"),
version->major, version->minor, version->major, version->minor,
(req->attr.keepalive? QSE_MT("keep-alive"): QSE_MT("close")), (req->attr.keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
@ -764,7 +764,7 @@ send_dirlist:
qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_task_t* qse_httpd_entaskdir (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
qse_ubi_t handle, int chunked) qse_ubi_t handle, int chunked)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -888,7 +888,7 @@ static int task_main_path (
qse_httpd_task_t* qse_httpd_entaskpath ( qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
qse_htre_t* req) qse_htre_t* req)
{ {
@ -996,7 +996,7 @@ static int task_main_fseg (
static qse_httpd_task_t* entask_file_segment ( static qse_httpd_task_t* entask_file_segment (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
qse_ubi_t handle, qse_foff_t offset, qse_foff_t size) qse_ubi_t handle, qse_foff_t offset, qse_foff_t size)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -1179,7 +1179,7 @@ no_file_send:
qse_httpd_task_t* qse_httpd_entaskfile ( qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, qse_httpd_task_t* pred,
const qse_mchar_t* path, const qse_mchar_t* path,
qse_htre_t* req) qse_htre_t* req)
{ {
@ -1896,6 +1896,7 @@ static int task_main_cgi_4 (
QSE_ASSERT (cgi->pio_inited); QSE_ASSERT (cgi->pio_inited);
qse_printf (QSE_T("task_main_cgi_4 trigger_mask = %d\n"), task->trigger_mask);
if (task->trigger_mask & QSE_HTTPD_TASK_TRIGGER_RELAYABLE) if (task->trigger_mask & QSE_HTTPD_TASK_TRIGGER_RELAYABLE)
{ {
cgi_forward_content (httpd, task, 0); cgi_forward_content (httpd, task, 0);
@ -2069,6 +2070,7 @@ qse_printf (QSE_T("[cgi-3 send failure....\n"));
cgi->res_left -= n; cgi->res_left -= n;
if (cgi->res_left <= 0) if (cgi->res_left <= 0)
{ {
qse_printf (QSE_T("[switching to cgi-4....\n"));
task->main = task_main_cgi_4; task->main = task_main_cgi_4;
/* don't chain-call task_main_cgi_4 since it has another send /* don't chain-call task_main_cgi_4 since it has another send
* and it has already been sent here. so the writability must * and it has already been sent here. so the writability must
@ -2317,7 +2319,7 @@ oops:
static QSE_INLINE qse_httpd_task_t* entask_cgi ( static QSE_INLINE qse_httpd_task_t* entask_cgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, const qse_mchar_t* path, qse_httpd_task_t* pred, const qse_mchar_t* path,
qse_htre_t* req, int nph) qse_htre_t* req, int nph)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -2341,14 +2343,14 @@ static QSE_INLINE qse_httpd_task_t* entask_cgi (
qse_httpd_task_t* qse_httpd_entaskcgi ( qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req) qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req)
{ {
return entask_cgi (httpd, client, pred, path, req, 0); return entask_cgi (httpd, client, pred, path, req, 0);
} }
qse_httpd_task_t* qse_httpd_entasknph ( qse_httpd_task_t* qse_httpd_entasknph (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req) qse_httpd_task_t* pred, const qse_mchar_t* path, qse_htre_t* req)
{ {
return entask_cgi (httpd, client, pred, path, req, 1); return entask_cgi (httpd, client, pred, path, req, 1);
} }

File diff suppressed because it is too large Load Diff

View File

@ -24,56 +24,6 @@
/* private header file for httpd */ /* private header file for httpd */
#include <qse/net/httpd.h> #include <qse/net/httpd.h>
#include <qse/net/htrd.h>
#include <qse/cmn/nwad.h>
/* REMOVE THESE headers after abstracting away select()/fd_set */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct client_array_t client_array_t;
typedef struct task_queue_node_t task_queue_node_t;
struct task_queue_node_t
{
task_queue_node_t* next;
task_queue_node_t* prev;
qse_httpd_task_t task;
};
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;
qse_htrd_t* htrd;
struct
{
struct
{
int count;
task_queue_node_t* head;
task_queue_node_t* tail;
} queue;
} task;
};
struct client_array_t
{
int capa;
int size;
qse_httpd_client_t* data;
};
struct qse_httpd_t struct qse_httpd_t
{ {
@ -86,15 +36,29 @@ struct qse_httpd_t
struct struct
{ {
client_array_t array; struct
{
qse_httpd_client_t* head;
qse_httpd_client_t* tail;
} list;
struct
{
qse_httpd_client_t* head;
qse_httpd_client_t* tail;
} tasked;
qse_httpd_client_t* bad;
} client; } client;
struct struct
{ {
qse_httpd_server_t* list; qse_httpd_server_t* list;
fd_set set; qse_size_t navail;
int max; qse_size_t nactive;
} server; } server;
void* mux;
}; };
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -19,16 +19,13 @@
# include <sys/stat.h> # include <sys/stat.h>
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <sys/epoll.h>
#endif #endif
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/engine.h> #include <openssl/engine.h>
// TODO: remove this and export structured needed like qse_httpd_client_t
#include "../../lib/net/httpd.h"
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
#define MAX_SEND_SIZE 4096 #define MAX_SEND_SIZE 4096
@ -373,6 +370,7 @@ static int server_accept (
return -1; return -1;
} }
#if 0
if (fd >= FD_SETSIZE) if (fd >= FD_SETSIZE)
{ {
qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
@ -380,6 +378,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
close (fd); close (fd);
return -1; return -1;
} }
#endif
flag = fcntl (fd, F_GETFL); flag = fcntl (fd, F_GETFL);
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
@ -407,6 +406,161 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
struct mux_ev_t
{
qse_ubi_t handle;
int reqmask;
qse_httpd_muxcb_t cbfun;
void* cbarg;
struct mux_ee_t* next;
};
struct mux_t
{
int fd;
struct
{
struct epoll_event* ptr;
qse_size_t len;
qse_size_t capa;
} ee;
};
static void* mux_open (qse_httpd_t* httpd)
{
struct mux_t* mux;
mux = qse_httpd_allocmem (httpd, QSE_SIZEOF(*mux));
if (mux == QSE_NULL) return QSE_NULL;
memset (mux, 0, QSE_SIZEOF(*mux));
mux->fd = epoll_create (100);
if (mux->fd <= -1)
{
qse_httpd_freemem (httpd, mux);
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
return QSE_NULL;
}
return mux;
}
static void mux_close (qse_httpd_t* httpd, void* vmux)
{
struct mux_t* mux = (struct mux_t*)vmux;
if (mux->ee.ptr) qse_httpd_freemem (httpd, mux->ee.ptr);
close (mux->fd);
qse_httpd_freemem (httpd, mux);
}
static int mux_addhnd (
qse_httpd_t* httpd, void* vmux, qse_ubi_t handle,
int mask, qse_httpd_muxcb_t cbfun, void* cbarg)
{
struct mux_t* mux = (struct mux_t*)vmux;
struct epoll_event ev;
struct mux_ev_t* mev;
ev.events = 0;
if (mask & QSE_HTTPD_MUX_READ) ev.events |= EPOLLIN;
if (mask & QSE_HTTPD_MUX_WRITE) ev.events |= EPOLLOUT;
if (ev.events == 0)
{
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
return -1;
}
mev = qse_httpd_allocmem (httpd, QSE_SIZEOF(*mev));
if (mev == QSE_NULL) return -1;
if (mux->ee.len >= mux->ee.capa)
{
struct epoll_event* tmp;
tmp = qse_httpd_reallocmem (
httpd, mux->ee.ptr,
QSE_SIZEOF(*mux->ee.ptr) * (mux->ee.capa + 1) * 2);
if (tmp == QSE_NULL)
{
qse_httpd_freemem (httpd, mev);
return -1;
}
mux->ee.ptr = tmp;
mux->ee.capa = (mux->ee.capa + 1) * 2;
}
mev->handle = handle;
mev->reqmask = mask;
mev->cbfun = cbfun;
mev->cbarg = cbarg;
ev.data.ptr = mev;
if (epoll_ctl (mux->fd, EPOLL_CTL_ADD, handle.i, &ev) <= -1)
{
/* don't rollback ee.ptr */
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
qse_httpd_freemem (httpd, mev);
return -1;
}
mux->ee.len++;
return 0;
}
static int mux_delhnd (qse_httpd_t* httpd, void* vmux, qse_ubi_t handle)
{
struct mux_t* mux = (struct mux_t*)vmux;
if (epoll_ctl (mux->fd, EPOLL_CTL_DEL, handle.i, QSE_NULL) <= -1)
{
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
return -1;
}
mux->ee.len--;
return 0;
}
static int mux_poll (qse_httpd_t* httpd, void* vmux, qse_ntime_t timeout)
{
struct mux_t* mux = (struct mux_t*)vmux;
struct mux_ev_t* mev;
int mask, nfds, i;
nfds = epoll_wait (mux->fd, mux->ee.ptr, mux->ee.len, timeout);
if (nfds <= -1)
{
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
return -1;
}
for (i = 0; i < nfds; i++)
{
mev = mux->ee.ptr[i].data.ptr;
mask = 0;
if (mux->ee.ptr[i].events & EPOLLIN) mask |= QSE_HTTPD_MUX_READ;
if (mux->ee.ptr[i].events & EPOLLOUT) mask |= QSE_HTTPD_MUX_WRITE;
if (mux->ee.ptr[i].events & EPOLLHUP)
{
if (mev->reqmask & QSE_HTTPD_MUX_READ) mask |= QSE_HTTPD_MUX_READ;
if (mev->reqmask & QSE_HTTPD_MUX_WRITE) mask |= QSE_HTTPD_MUX_WRITE;
}
mev->cbfun (httpd, mux, mev->handle, mask, mev->cbarg);
//if (cbfun fails and the client is deleted???) other pending events should also be dropped???
}
return 0;
}
static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec) static int mux_readable (qse_httpd_t* httpd, qse_ubi_t handle, qse_ntoff_t msec)
{ {
fd_set r; fd_set r;
@ -574,7 +728,11 @@ static void client_close (
static void client_shutdown ( static void client_shutdown (
qse_httpd_t* httpd, qse_httpd_client_t* client) qse_httpd_t* httpd, qse_httpd_client_t* client)
{ {
#if defined(SHUT_RDWR)
shutdown (client->handle.i, SHUT_RDWR); shutdown (client->handle.i, SHUT_RDWR);
#else
shutdown (client->handle.i, 2);
#endif
} }
static qse_ssize_t client_recv ( static qse_ssize_t client_recv (
@ -912,7 +1070,15 @@ static qse_httpd_cbs_t httpd_cbs =
{ server_open, server_close, server_accept }, { server_open, server_close, server_accept },
/* multiplexer */ /* multiplexer */
{ mux_readable, mux_writable }, { mux_open,
mux_close,
mux_addhnd,
mux_delhnd,
mux_poll,
mux_readable,
mux_writable
},
/* file operation */ /* file operation */
{ file_executable, { file_executable,
@ -991,7 +1157,7 @@ int httpd_main (int argc, qse_char_t* argv[])
signal (SIGPIPE, SIG_IGN); signal (SIGPIPE, SIG_IGN);
qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL); qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL);
ret = qse_httpd_loop (httpd, &httpd_cbs); ret = qse_httpd_loop (httpd, &httpd_cbs, 10000);
signal (SIGINT, SIG_DFL); signal (SIGINT, SIG_DFL);
signal (SIGPIPE, SIG_DFL); signal (SIGPIPE, SIG_DFL);