changed sockets and pipes used in httped to work in non-blocking mode

This commit is contained in:
hyung-hwan 2014-07-25 17:28:20 +00:00
parent 6137df4e86
commit e8a241ed71
10 changed files with 767 additions and 551 deletions

View File

@ -92,7 +92,14 @@ enum qse_pio_flag_t
/** return immediately from qse_pio_wait() if a child has not exited */ /** return immediately from qse_pio_wait() if a child has not exited */
QSE_PIO_WAITNOBLOCK = (1 << 23), QSE_PIO_WAITNOBLOCK = (1 << 23),
/** do not wait again if waitpid has been interrupted */ /** do not wait again if waitpid has been interrupted */
QSE_PIO_WAITNORETRY = (1 << 24) QSE_PIO_WAITNORETRY = (1 << 24),
/** put stdin to non-blocking mode (only on supported platforms) */
QSE_PIO_INNOBLOCK = (1 << 25),
/** put stdout to non-blocking mode (only on supported platforms)*/
QSE_PIO_OUTNOBLOCK = (1 << 26),
/** put stderr to non-blocking mode (only on supported platforms) */
QSE_PIO_ERRNOBLOCK = (1 << 27)
}; };
/** /**

View File

@ -438,6 +438,26 @@ qse_mux_errnum_t qse_mux_geterrnum (qse_mux_t* mux)
int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt) int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt)
{ {
#if defined(USE_SELECT)
/* nothing */
#elif defined(USE_KQUEUE)
struct kevent chlist[2];
int count = 0;
#elif defined(USE_EPOLL)
struct epoll_event ev;
#elif defined(__OS2__)
/* nothing */
#else
/* nothing */
#endif
/* sanity check */
if (!(evt->mask & (QSE_MUX_IN | QSE_MUX_OUT)) || evt->hnd < 0)
{
mux->errnum = QSE_MUX_EINVAL;
return -1;
}
#if defined(USE_SELECT) #if defined(USE_SELECT)
/* TODO: windows seems to return a pretty high file descriptors /* TODO: windows seems to return a pretty high file descriptors
@ -482,9 +502,6 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt)
return 0; return 0;
#elif defined(USE_KQUEUE) #elif defined(USE_KQUEUE)
struct kevent chlist[2];
int count = 0;
/* TODO: study if it is better to put 'evt' to the udata /* TODO: study if it is better to put 'evt' to the udata
* field of chlist? */ * field of chlist? */
@ -502,11 +519,7 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt)
count++; count++;
} }
if (count == 0 || evt->hnd < 0) QSE_ASSERT (count > 0);
{
mux->errnum = QSE_MUX_EINVAL;
return -1;
}
if (evt->hnd >= mux->me.ubound) if (evt->hnd >= mux->me.ubound)
{ {
@ -550,17 +563,12 @@ int qse_mux_insert (qse_mux_t* mux, const qse_mux_evt_t* evt)
return 0; return 0;
#elif defined(USE_EPOLL) #elif defined(USE_EPOLL)
struct epoll_event ev;
QSE_MEMSET (&ev, 0, QSE_SIZEOF(ev)); QSE_MEMSET (&ev, 0, QSE_SIZEOF(ev));
if (evt->mask & QSE_MUX_IN) ev.events |= EPOLLIN; if (evt->mask & QSE_MUX_IN) ev.events |= EPOLLIN;
if (evt->mask & QSE_MUX_OUT) ev.events |= EPOLLOUT; if (evt->mask & QSE_MUX_OUT) ev.events |= EPOLLOUT;
if (ev.events == 0 || evt->hnd < 0) QSE_ASSERT (ev.events != 0);
{
mux->errnum = QSE_MUX_EINVAL;
return -1;
}
if (evt->hnd >= mux->me.ubound) if (evt->hnd >= mux->me.ubound)
{ {
@ -937,13 +945,13 @@ int qse_mux_poll (qse_mux_t* mux, const qse_ntime_t* tmout)
if (mux->ee.ptr[i].events & EPOLLIN) xevt.mask |= QSE_MUX_IN; if (mux->ee.ptr[i].events & EPOLLIN) xevt.mask |= QSE_MUX_IN;
if (mux->ee.ptr[i].events & EPOLLOUT) xevt.mask |= QSE_MUX_OUT; if (mux->ee.ptr[i].events & EPOLLOUT) xevt.mask |= QSE_MUX_OUT;
if (mux->ee.ptr[i].events & EPOLLHUP) if (mux->ee.ptr[i].events & (EPOLLHUP | EPOLLERR))
{ {
if (evt->mask & QSE_MUX_IN) xevt.mask |= QSE_MUX_IN; if (evt->mask & QSE_MUX_IN) xevt.mask |= QSE_MUX_IN;
if (evt->mask & QSE_MUX_OUT) xevt.mask |= QSE_MUX_OUT; if (evt->mask & QSE_MUX_OUT) xevt.mask |= QSE_MUX_OUT;
} }
mux->evtfun (mux, &xevt); if (xevt.mask > 0) mux->evtfun (mux, &xevt);
} }
return nfds; return nfds;

View File

@ -429,6 +429,22 @@ static int get_highest_fd (void)
#endif #endif
static int set_pipe_nonblock (qse_pio_t* pio, qse_pio_hnd_t fd, int enabled)
{
#if defined(O_NONBLOCK)
int flag = QSE_FCNTL (fd, F_GETFL, 0);
if (flag >= 0) flag = QSE_FCNTL (fd, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK)));
if (flag <= -1) pio->errnum = syserr_to_errnum (errno);
return flag;
#else
pio->errnum = QSE_PIO_ENOIMPL;
return -1;
#endif
}
int qse_pio_init ( int qse_pio_init (
qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd,
qse_env_t* env, int flags) qse_env_t* env, int flags)
@ -1785,6 +1801,13 @@ create_process:
#endif #endif
if (((flags & QSE_PIO_INNOBLOCK) && set_pipe_nonblock(pio, handle[1], 1) <= -1) ||
((flags & QSE_PIO_OUTNOBLOCK) && set_pipe_nonblock(pio, handle[2], 1) <= -1) ||
((flags & QSE_PIO_ERRNOBLOCK) && set_pipe_nobnlock(pio, handle[4], 1) <= -1))
{
goto oops;
}
/* store back references */ /* store back references */
pio->pin[QSE_PIO_IN].self = pio; pio->pin[QSE_PIO_IN].self = pio;
pio->pin[QSE_PIO_OUT].self = pio; pio->pin[QSE_PIO_OUT].self = pio;
@ -1795,6 +1818,7 @@ create_process:
pio->pin[QSE_PIO_OUT].handle = handle[2]; pio->pin[QSE_PIO_OUT].handle = handle[2];
pio->pin[QSE_PIO_ERR].handle = handle[4]; pio->pin[QSE_PIO_ERR].handle = handle[4];
if (flags & QSE_PIO_TEXT) if (flags & QSE_PIO_TEXT)
{ {
int topt = 0; int topt = 0;

View File

@ -25,6 +25,16 @@
#include <qse/cmn/fmt.h> #include <qse/cmn/fmt.h>
#include <qse/cmn/path.h> #include <qse/cmn/path.h>
#if defined(_WIN32)
/* nothing */
#elif defined(__OS2__)
/* nothing */
#elif defined(__DOS__)
/* nothing */
#else
# include "../cmn/syscall.h"
#endif
#include <stdio.h> /* TODO: remove this */ #include <stdio.h> /* TODO: remove this */
#if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) #if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200))
# define snprintf _snprintf # define snprintf _snprintf
@ -104,6 +114,8 @@ struct cgi_client_req_hdr_ctx_t
qse_env_t* env; qse_env_t* env;
}; };
static int cgi_capture_client_header ( static int cgi_capture_client_header (
qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx) qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{ {
@ -637,33 +649,14 @@ static void cgi_forward_client_input_to_script (
/* normal forwarding */ /* normal forwarding */
qse_ssize_t n; qse_ssize_t n;
if (writable) goto forward;
n = httpd->opt.scb.mux.writable (
httpd, qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN), 0);
if (n >= 1)
{
forward:
/* writable */
n = qse_pio_write ( n = qse_pio_write (
&cgi->pio, QSE_PIO_IN, &cgi->pio, QSE_PIO_IN,
QSE_MBS_PTR(cgi->reqfwdbuf), QSE_MBS_PTR(cgi->reqfwdbuf),
QSE_MBS_LEN(cgi->reqfwdbuf) QSE_MBS_LEN(cgi->reqfwdbuf)
); );
if (n > 0)
{
/* TODO: improve performance.. instead of copying the remaing part
to the head all the time.. grow the buffer to a certain limit. */
qse_mbs_del (cgi->reqfwdbuf, 0, n);
if (QSE_MBS_LEN(cgi->reqfwdbuf) <= 0)
{
if (cgi->reqflags & CGI_REQ_GOTALL) goto done;
else task->trigger.v[1].mask = 0; /* pipe output to child */
}
}
}
if (n <= -1) if (n <= -1)
{
if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{ {
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio write error - ")); log_cgi_script_error (cgi, QSE_MT("cgi pio write error - "));
@ -690,6 +683,18 @@ to the head all the time.. grow the buffer to a certain limit. */
task->trigger.v[1].mask = 0; /* pipe output to child */ task->trigger.v[1].mask = 0; /* pipe output to child */
} }
} }
else if (n > 0)
{
/* TODO: improve performance.. instead of copying the remaing part
to the head all the time.. grow the buffer to a certain limit. */
qse_mbs_del (cgi->reqfwdbuf, 0, n);
if (QSE_MBS_LEN(cgi->reqfwdbuf) <= 0)
{
if (cgi->reqflags & CGI_REQ_GOTALL) goto done;
else task->trigger.v[1].mask = 0; /* pipe output to child */
}
}
}
} }
else if (cgi->reqflags & CGI_REQ_GOTALL) else if (cgi->reqflags & CGI_REQ_GOTALL)
{ {
@ -953,10 +958,18 @@ static QSE_INLINE qse_ssize_t cgi_read_script_output_to_buffer (
&cgi->buf[cgi->buflen], &cgi->buf[cgi->buflen],
QSE_SIZEOF(cgi->buf) - cgi->buflen QSE_SIZEOF(cgi->buf) - cgi->buflen
); );
if (n > 0) cgi->buflen += n; if (n <= -1)
{
if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return -1;
}
n = -999;
}
else if (n > 0) cgi->buflen += n;
return n; return n;
} }
@ -966,16 +979,25 @@ static QSE_INLINE qse_ssize_t cgi_write_script_output_to_client (
{ {
qse_ssize_t n; qse_ssize_t n;
QSE_ASSERT (cgi->buflen > 0);
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen); n = httpd->opt.scb.client.send (httpd, client, cgi->buf, cgi->buflen);
if (n > 0) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi write error to client - "));
}
else n = 0;
}
else if (n > 0)
{ {
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
cgi->buflen -= n; cgi->buflen -= n;
} }
if (n <= -1 && cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi write error to client - "));
return n; return n;
} }
@ -998,10 +1020,7 @@ static int task_main_cgi_5 (
} }
} }
if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ cgi->buflen > 0)
(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{
if (cgi->buflen > 0)
{ {
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1)
{ {
@ -1009,7 +1028,6 @@ static int task_main_cgi_5 (
return -1; return -1;
} }
} }
}
/* if forwarding didn't finish, something is not really right... /* if forwarding didn't finish, something is not really right...
* so long as the output from CGI is finished, no more forwarding * so long as the output from CGI is finished, no more forwarding
@ -1042,9 +1060,21 @@ static int task_main_cgi_4_nph (
{ {
if (cgi->buflen < QSE_SIZEOF(cgi->buf)) if (cgi->buflen < QSE_SIZEOF(cgi->buf))
{ {
n = cgi_read_script_output_to_buffer (httpd, client, cgi); n = qse_pio_read (
if (n <= -1) return -1; /* TODO: logging */ &cgi->pio, QSE_PIO_OUT,
if (n == 0) &cgi->buf[cgi->buflen],
QSE_SIZEOF(cgi->buf) - cgi->buflen
);
if (n <= -1)
{
if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return -1;
}
}
else if (n == 0)
{ {
/* switch to the next phase */ /* switch to the next phase */
task->main = task_main_cgi_5; task->main = task_main_cgi_5;
@ -1052,10 +1082,10 @@ static int task_main_cgi_4_nph (
task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
return 1; return 1;
} }
else cgi->buflen += n;
} }
QSE_ASSERT (cgi->buflen > 0); if (cgi->buflen > 0 && cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
} }
return 1; return 1;
@ -1109,12 +1139,15 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
count - extra count - extra
); );
if (n <= -1) if (n <= -1)
{
if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{ {
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return -1; return -1;
} }
if (n == 0) }
else if (n == 0)
{ {
/* the cgi script closed the output */ /* the cgi script closed the output */
cgi->buf[cgi->buflen++] = QSE_MT('0'); cgi->buf[cgi->buflen++] = QSE_MT('0');
@ -1128,7 +1161,8 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
return 1; return 1;
} }
else
{
/* set the chunk length. if the length string is less /* set the chunk length. if the length string is less
* than 4 digits, the right side of the string is filled * than 4 digits, the right side of the string is filled
* with space letters. for example, the chunk length line * with space letters. for example, the chunk length line
@ -1159,13 +1193,26 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
} }
} }
} }
}
else else
{ {
if (cgi->buflen < QSE_SIZEOF(cgi->buf)) if (cgi->buflen < QSE_SIZEOF(cgi->buf))
{ {
n = cgi_read_script_output_to_buffer (httpd, client, cgi); n = qse_pio_read (
if (n <= -1) return -1; /* TODO: logging */ &cgi->pio, QSE_PIO_OUT,
if (n == 0) &cgi->buf[cgi->buflen],
QSE_SIZEOF(cgi->buf) - cgi->buflen
);
if (n <= -1)
{
if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
return -1;
}
}
else if (n == 0)
{ {
/* switch to the next phase */ /* switch to the next phase */
task->main = task_main_cgi_5; task->main = task_main_cgi_5;
@ -1173,7 +1220,8 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
return 1; return 1;
} }
else
{
cgi->script_output_received += n; cgi->script_output_received += n;
if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) &&
cgi->script_output_received > cgi->script_output_length) cgi->script_output_received > cgi->script_output_length)
@ -1185,12 +1233,12 @@ printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
} }
} }
} }
}
/* the main loop invokes the task function only if the client /* the main loop invokes the task function only if the client
* side is writable. it should be safe to write whenever * side is writable. it should be safe to write whenever
* this task function is called. */ * this task function is called. */
QSE_ASSERT (cgi->buflen > 0); if (cgi->buflen > 0 && cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
if (cgi_write_script_output_to_client (httpd, client, cgi) <= -1) return -1;
} }
return 1; return 1;
@ -1226,25 +1274,26 @@ printf ("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
/* send the partial reponse received with the initial line and headers /* send the partial reponse received with the initial line and headers
* so long as the client-side handle is writable... */ * so long as the client-side handle is writable... */
if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ cgi->res_left > 0)
(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{ {
count = MAX_SEND_SIZE; count = cgi->res_left;
if (count >= cgi->res_left) count = cgi->res_left; if (count >= MAX_SEND_SIZE) count = MAX_SEND_SIZE;
if (count > 0) httpd->errnum = QSE_HTTPD_ENOERR;
{
n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count); n = httpd->opt.scb.client.send (httpd, client, cgi->res_ptr, count);
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - ")); log_cgi_script_error (cgi, QSE_MT("cgi initial write error to client - "));
return -1; return -1;
} }
}
else if (n > 0)
{
cgi->res_ptr += n; cgi->res_ptr += n;
cgi->res_left -= n; cgi->res_left -= n;
}
if (cgi->res_left <= 0) if (cgi->res_left <= 0)
{ {
@ -1270,7 +1319,7 @@ printf ("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
} }
return 1; return 1;
} }
}
} }
return 1; /* more work to do */ return 1; /* more work to do */
@ -1319,13 +1368,16 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
QSE_SIZEOF(cgi->buf) - cgi->buflen QSE_SIZEOF(cgi->buf) - cgi->buflen
); );
if (n <= -1) if (n <= -1)
{
if (qse_pio_geterrnum(&cgi->pio) != QSE_PIO_EAGAIN)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
log_cgi_script_error (cgi, QSE_MT("cgi pio read error - ")); log_cgi_script_error (cgi, QSE_MT("cgi pio read error - "));
goto oops; goto oops;
} }
if (n == 0) }
else if (n == 0)
{ {
/* end of output from cgi before it has seen a header. /* end of output from cgi before it has seen a header.
* the cgi script must be crooked. */ * the cgi script must be crooked. */
@ -1333,8 +1385,13 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
log_cgi_script_error (cgi, QSE_MT("cgi premature eof - ")); log_cgi_script_error (cgi, QSE_MT("cgi premature eof - "));
goto oops; goto oops;
} }
else
{
cgi->buflen += n; cgi->buflen += n;
}
if (cgi->buflen > 0)
{
if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1) if (qse_htrd_feed (cgi->script_htrd, cgi->buf, cgi->buflen) <= -1)
{ {
if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT) if (cgi->httpd->opt.trait & QSE_HTTPD_LOGACT)
@ -1343,6 +1400,7 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
} }
cgi->buflen = 0; cgi->buflen = 0;
}
if (QSE_MBS_LEN(cgi->res) > 0) if (QSE_MBS_LEN(cgi->res) > 0)
{ {
@ -1410,7 +1468,11 @@ static int task_main_cgi (
if (cgi->res == QSE_NULL) goto oops; if (cgi->res == QSE_NULL) goto oops;
} }
pio_options = QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_MBSCMD; /* <<WARNING>>
* QSE_PIO_INNOBLOCK and QSE_PIO_OUTNONBLOCK are not supported
* on non-unix/linux platforms. so the CGI task can only be
* used on unix/linux platforms */
pio_options = QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_MBSCMD | QSE_PIO_INNOBLOCK | QSE_PIO_OUTNOBLOCK;
if (httpd->opt.trait & QSE_HTTPD_CGIERRTONUL) if (httpd->opt.trait & QSE_HTTPD_CGIERRTONUL)
pio_options |= QSE_PIO_ERRTONUL; pio_options |= QSE_PIO_ERRTONUL;
else else
@ -1446,6 +1508,7 @@ static int task_main_cgi (
goto oops; goto oops;
} }
cgi->pio_inited = 1; cgi->pio_inited = 1;
/* set the trigger that the main loop can use this /* set the trigger that the main loop can use this

View File

@ -93,12 +93,19 @@ static int task_main_getfseg (
count = MAX_SEND_SIZE; count = MAX_SEND_SIZE;
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.sendfile ( n = httpd->opt.scb.client.sendfile (
httpd, client, ctx->handle, &ctx->offset, count); httpd, client, ctx->handle, &ctx->offset, count);
if (n <= -1) if (n <= -1)
{ {
/* HANDLE EGAIN specially??? */ /* HANDLE EGAIN specially??? */
return -1; /* TODO: any logging */ if (httpd->errnum != QSE_HTTPD_EAGAIN)
{
/* TODO: logging */
return -1;
}
goto more_work;
} }
if (n == 0 && count > 0) if (n == 0 && count > 0)
@ -114,6 +121,7 @@ static int task_main_getfseg (
ctx->left -= n; ctx->left -= n;
if (ctx->left <= 0) return 0; if (ctx->left <= 0) return 0;
more_work:
return 1; /* more work to do */ return 1; /* more work to do */
} }

View File

@ -658,8 +658,7 @@ static qse_htrd_recbs_t proxy_peer_htrd_cbs =
proxy_htrd_handle_peer_output proxy_htrd_handle_peer_output
}; };
static void proxy_forward_client_input_to_peer ( static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_task_t* task)
qse_httpd_t* httpd, qse_httpd_task_t* task, int writable)
{ {
task_proxy_t* proxy = (task_proxy_t*)task->ctx; task_proxy_t* proxy = (task_proxy_t*)task->ctx;
@ -680,41 +679,21 @@ static void proxy_forward_client_input_to_peer (
/* normal forwarding */ /* normal forwarding */
qse_ssize_t n; qse_ssize_t n;
if (writable) goto forward;
n = httpd->opt.scb.mux.writable (httpd, proxy->peer.handle, 0);
#if 0
if (n == 0) qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@NOT WRITABLE\n"));
#endif
if (n >= 1)
{
forward:
/* writable */
#if 0 #if 0
qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), qse_printf (QSE_T("PROXY FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"),
(int)QSE_MBS_LEN(proxy->reqfwdbuf), (int)QSE_MBS_LEN(proxy->reqfwdbuf),
QSE_MBS_PTR(proxy->reqfwdbuf)); QSE_MBS_PTR(proxy->reqfwdbuf));
#endif #endif
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.peer.send ( n = httpd->opt.scb.peer.send (
httpd, &proxy->peer, httpd, &proxy->peer,
QSE_MBS_PTR(proxy->reqfwdbuf), QSE_MBS_PTR(proxy->reqfwdbuf),
QSE_MBS_LEN(proxy->reqfwdbuf) QSE_MBS_LEN(proxy->reqfwdbuf)
); );
/* TODO: improve performance.. instead of copying the remaing part
to the head all the time.. grow the buffer to a certain limit. */
if (n > 0)
{
qse_mbs_del (proxy->reqfwdbuf, 0, n);
if (QSE_MBS_LEN(proxy->reqfwdbuf) <= 0)
{
if (proxy->req == QSE_NULL) goto done;
else task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
}
}
}
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy send-to-peer error - "); log_proxy_error (proxy, "proxy send-to-peer error - ");
@ -732,6 +711,18 @@ to the head all the time.. grow the buffer to a certain limit. */
task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */ task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */
} }
} }
else if (n > 0)
{
/* TODO: improve performance.. instead of copying the remaing part
to the head all the time.. grow the buffer to a certain limit. */
qse_mbs_del (proxy->reqfwdbuf, 0, n);
if (QSE_MBS_LEN(proxy->reqfwdbuf) <= 0)
{
if (proxy->req == QSE_NULL) goto done;
else task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
}
}
}
} }
else if (proxy->req == QSE_NULL) else if (proxy->req == QSE_NULL)
{ {
@ -1038,6 +1029,7 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask);
#endif #endif
#if 0
if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
/* if the client side is readable */ /* if the client side is readable */
@ -1048,23 +1040,30 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
/* if the peer side is writable while the client side is not readable*/ /* if the peer side is writable while the client side is not readable*/
proxy_forward_client_input_to_peer (httpd, task, 1); proxy_forward_client_input_to_peer (httpd, task, 1);
} }
#endif
proxy_forward_client_input_to_peer (httpd, task);
if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ proxy->buflen > 0)
(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{
if (proxy->buflen > 0)
{ {
/* wrote to the client socket as long as there's something to
* write. it's safe to do so as the socket is non-blocking.
* i commented out the check in the 'if' condition above */
/* TODO: check if proxy outputs more than content-length if it is set... */ /* TODO: check if proxy outputs more than content-length if it is set... */
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen);
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy send-to-client error - "); log_proxy_error (proxy, "proxy send-to-client error - ");
return -1; return -1;
} }
}
else if (n > 0)
{
QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n);
proxy->buflen -= n; proxy->buflen -= n;
} }
@ -1087,6 +1086,8 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask);
#endif #endif
proxy_forward_client_input_to_peer (httpd, task);
/*
if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task, 0);
@ -1095,15 +1096,14 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
{ {
proxy_forward_client_input_to_peer (httpd, task, 1); proxy_forward_client_input_to_peer (httpd, task, 1);
} }
*/
if (task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if ((task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) &&
proxy->buflen < QSE_SIZEOF(proxy->buf))
{ {
qse_ssize_t n; qse_ssize_t n;
if (proxy->buflen < QSE_SIZEOF(proxy->buf))
{
/* reading from the peer */ /* reading from the peer */
httpd->errnum = QSE_HTTPD_ENOERR; httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.peer.recv ( n = httpd->opt.scb.peer.recv (
httpd, &proxy->peer, httpd, &proxy->peer,
@ -1113,11 +1113,16 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
if (n <= -1) if (n <= -1)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy recv-from-peer error - "); log_proxy_error (proxy, "proxy recv-from-peer error - ");
return -1; return -1;
} }
if (n == 0)
/* carry on as if recv was't called at all */
}
else if (n == 0)
{ {
/* peer closed connection */ /* peer closed connection */
if (proxy->resflags & PROXY_RES_PEER_LENGTH) if (proxy->resflags & PROXY_RES_PEER_LENGTH)
@ -1152,7 +1157,8 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
return 1; return 1;
} }
else
{
proxy->buflen += n; proxy->buflen += n;
proxy->peer_output_received += n; proxy->peer_output_received += n;
@ -1177,22 +1183,34 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
} }
} }
} }
}
if (proxy->buflen)
{
/* the main loop invokes the task function only if the client /* the main loop invokes the task function only if the client
* side is writable. it should be safe to write whenever * side is writable. it should be safe to write whenever
* this task function is called. */ * this task function is called. even if it's not writable,
* it should still be ok as the client socket is non-blocking. */
qse_ssize_t n;
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen);
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
/* can't return internal server error any more... */ /* can't return internal server error any more... */
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy send-to-client error - "); log_proxy_error (proxy, "proxy send-to-client error - ");
return -1; return -1;
} }
}
else if (n > 0)
{
QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n); QSE_MEMCPY (&proxy->buf[0], &proxy->buf[n], proxy->buflen - n);
proxy->buflen -= n; proxy->buflen -= n;
} }
}
return 1; return 1;
} }
@ -1212,6 +1230,8 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg
task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask);
#endif #endif
proxy_forward_client_input_to_peer (httpd, task);
/*
if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task, 0);
@ -1220,34 +1240,41 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg
{ {
proxy_forward_client_input_to_peer (httpd, task, 1); proxy_forward_client_input_to_peer (httpd, task, 1);
} }
*/
if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) &&*/ proxy->res_pending > 0)
(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{ {
/* the client socket is non-blocking. so attempt to send
* so long as there's something to send regardless of writability
* of the client socket. see the check commented out in the 'if'
* condition above.*/
qse_ssize_t n; qse_ssize_t n;
qse_size_t count; qse_size_t count;
count = proxy->res_pending; count = proxy->res_pending;
if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE;
if (count > 0) httpd->errnum = QSE_HTTPD_ENOERR;
{
n = httpd->opt.scb.client.send ( n = httpd->opt.scb.client.send (
httpd, client, httpd, client,
&QSE_MBS_CHAR(proxy->res,proxy->res_consumed), &QSE_MBS_CHAR(proxy->res,proxy->res_consumed),
count count
); );
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy send-to-client error - "); log_proxy_error (proxy, "proxy send-to-client error - ");
return -1; return -1;
} }
}
else if (n > 0)
{
proxy->resflags |= PROXY_RES_EVER_SENTBACK; proxy->resflags |= PROXY_RES_EVER_SENTBACK;
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
}
if (proxy->res_pending <= 0) if (proxy->res_pending <= 0)
{ {
@ -1276,6 +1303,7 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg
return 1; return 1;
} }
} }
}
return 1; /* more work to do */ return 1; /* more work to do */
} }
@ -1291,6 +1319,8 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask);
#endif #endif
proxy_forward_client_input_to_peer (httpd, task);
#if 0
if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
/* client is readable */ /* client is readable */
@ -1301,19 +1331,19 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
/* client is not readable but peer is writable */ /* client is not readable but peer is writable */
proxy_forward_client_input_to_peer (httpd, task, 1); proxy_forward_client_input_to_peer (httpd, task, 1);
} }
#endif
if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ if (/*(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) && */ proxy->res_pending > 0)
(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE))
{
if (proxy->res_pending > 0)
{ {
/* the 'if' condition becomes true only if '100 Continue' /* the 'if' condition becomes true only if '100 Continue'
* is received without an actual reply in a previous call to * is received without an actual reply in a previous call to
* qse_htrd_feed() below. Since the actual reply is not * qse_htrd_feed() far below. Since the actual reply is not
* received yet, i just want to read more while realying * received yet, i just want to read more while relaying
* '100 Continue' to the client. this task handler is called * '100 Continue' to the client.
* only if the client side handle is writable. i can safely *
* write to the client without a check. */ * attempt to write to the client regardless of writability of
* the cleint socket as it is non-blocking. see the check commented
* in the 'if' condition above. */
qse_ssize_t n; qse_ssize_t n;
qse_size_t count; qse_size_t count;
@ -1324,18 +1354,23 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
count = proxy->res_pending; count = proxy->res_pending;
if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE;
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send ( n = httpd->opt.scb.client.send (
httpd, client, httpd, client,
QSE_MBS_CPTR(proxy->res,proxy->res_consumed), QSE_MBS_CPTR(proxy->res,proxy->res_consumed),
count count
); );
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy send-to-client error - "); log_proxy_error (proxy, "proxy send-to-client error - ");
goto oops; goto oops;
} }
}
else if (n > 0)
{
proxy->resflags |= PROXY_RES_EVER_SENTBACK; proxy->resflags |= PROXY_RES_EVER_SENTBACK;
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
@ -1366,17 +1401,20 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
QSE_SIZEOF(proxy->buf) - proxy->buflen QSE_SIZEOF(proxy->buf) - proxy->buflen
); );
if (n <= -1) if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy recv-from-peer error - "); log_proxy_error (proxy, "proxy recv-from-peer error - ");
goto oops; goto oops;
} }
if (n == 0) }
else if (n == 0)
{ {
if (!(proxy->resflags & PROXY_RES_RECEIVED_RESHDR)) if (!(proxy->resflags & PROXY_RES_RECEIVED_RESHDR))
{ {
/* end of output from peer before it has seen a header. /* end of output from peer before it has seen a header.
* the proxy peer must be crooked. */ * the proxy peer must be bad. */
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
log_proxy_error (proxy, "proxy premature eof - "); log_proxy_error (proxy, "proxy premature eof - ");
@ -1405,8 +1443,10 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
goto oops; goto oops;
} }
} }
else
{
proxy->buflen += n; proxy->buflen += n;
}
#if 0 #if 0
qse_printf (QSE_T("#####PROXY FEEDING %d [\n"), (int)proxy->buflen); qse_printf (QSE_T("#####PROXY FEEDING %d [\n"), (int)proxy->buflen);
@ -1416,7 +1456,8 @@ for (i = 0; i < proxy->buflen; i++) qse_printf (QSE_T("%hc"), proxy->buf[i]);
} }
qse_printf (QSE_T("]\n")); qse_printf (QSE_T("]\n"));
#endif #endif
if (proxy->buflen > 0)
{
if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1) if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
@ -1425,6 +1466,7 @@ qse_printf (QSE_T("]\n"));
} }
proxy->buflen = 0; proxy->buflen = 0;
}
if (QSE_MBS_LEN(proxy->res) > 0) if (QSE_MBS_LEN(proxy->res) > 0)
{ {
@ -1530,7 +1572,7 @@ static int task_main_proxy_1 (
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
{ {
/* forward the initial part of the input to the peer */ /* forward the initial part of the input to the peer */
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task);
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
{ {
/* there are still more to forward in the buffer /* there are still more to forward in the buffer
@ -1697,7 +1739,7 @@ static int task_main_proxy (
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
{ {
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task);
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0)
{ {
task->trigger.v[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger.v[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;

View File

@ -135,6 +135,9 @@ static qse_httpd_errnum_t skerr_to_errnum (DWORD e)
case WSAEINTR: case WSAEINTR:
return QSE_HTTPD_EINTR; return QSE_HTTPD_EINTR;
case WASEWOULDBLOCK:
return QSE_HTTPD_EAGAIN;
case WSAECONNREFUSED: case WSAECONNREFUSED:
case WSAENETUNREACH: case WSAENETUNREACH:
case WSAEHOSTUNREACH: case WSAEHOSTUNREACH:
@ -180,6 +183,9 @@ static qse_httpd_errnum_t skerr_to_errnum (int e)
case SOCEPIPE: case SOCEPIPE:
return QSE_HTTPD_EPIPE; return QSE_HTTPD_EPIPE;
case SOCEAGAIN:
return QSE_HTTPD_EAGAIN;
case SOCECONNREFUSED: case SOCECONNREFUSED:
case SOCENETUNREACH: case SOCENETUNREACH:
case SOCEHOSTUNREACH: case SOCEHOSTUNREACH:
@ -229,6 +235,9 @@ static qse_httpd_errnum_t skerr_to_errnum (int e)
return QSE_HTTPD_EPIPE; return QSE_HTTPD_EPIPE;
case EAGAIN: case EAGAIN:
#if defined(EWEOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
return QSE_HTTPD_EAGAIN; return QSE_HTTPD_EAGAIN;
#if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN) #if defined(ECONNREFUSED) || defined(ENETUNREACH) || defined(EHOSTUNREACH) || defined(EHOSTDOWN)
@ -640,13 +649,86 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd)
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
#if defined(_WIN32)
typedef SOCKET sock_t;
# define SOCK_INIT INVALID_SOCKET
#else
typedef int sock_t;
# define SOCK_INIT -1
#endif
#if !defined(HAVE_SOCKLEN_T)
typedef int socklen_t;
#endif
static QSE_INLINE int is_valid_socket (sock_t fd)
{
#if defined(_WIN32)
return fd != INVALID_SOCKET;
#else
return fd >= 0;
#endif
}
static QSE_INLINE void close_socket (sock_t fd)
{
#if defined(_WIN32)
closesocket (fd);
#elif defined(__OS2__)
soclose (fd);
#elif defined(__DOS__)
/* TODO: */
#else
QSE_CLOSE (fd);
#endif
}
static int set_socket_nonblock (qse_httpd_t* httpd, sock_t fd, int enabled)
{
#if defined(_WIN32)
if (ioctlsocket (fd, FIONBIO, &enabled) == SOCKET_ERROR)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
return -1;
}
return 0;
#elif defined(__OS2__)
if (ioctl (fd, FIONBIO, (char*)&enabled, sizeof(enabled)) <= -1)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
return -1;
}
return 0;
#elif defined(O_NONBLOCK)
int flag = fcntl (fd, F_GETFL);
if (flag >= 0) flag = fcntl (fd, F_SETFL, (enabled? (flag | O_NONBLOCK): (flag & ~O_NONBLOCK)));
if (flag <= -1)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
return -1;
}
return 0;
#else
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
return -1;
#endif
}
/* ------------------------------------------------------------------- */
static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
#if defined(__DOS__) #if defined(__DOS__)
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
return -1; return -1;
#else #else
int fd = -1, flag; sock_t fd = SOCK_INIT, flag;
qse_skad_t addr; qse_skad_t addr;
int addrsize; int addrsize;
@ -658,7 +740,11 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
} }
fd = socket (qse_skadfamily(&addr), SOCK_STREAM, IPPROTO_TCP); fd = socket (qse_skadfamily(&addr), SOCK_STREAM, IPPROTO_TCP);
if (fd <= -1) goto oops; if (!is_valid_socket(fd))
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
#if defined(FD_CLOEXEC) #if defined(FD_CLOEXEC)
flag = fcntl (fd, F_GETFD); flag = fcntl (fd, F_GETFD);
@ -720,6 +806,7 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1)
{ {
/* TODO: logging ... */ /* TODO: logging ... */
qse_httpd_seterrnum (httpd, ((len <= 0)? QSE_HTTPD_EINVAL: SKERR_TO_ERRNUM()));
goto oops; goto oops;
} }
#endif #endif
@ -735,50 +822,44 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
int on = 1; int on = 1;
setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1) goto oops; if (bind (fd, (struct sockaddr*)&addr, addrsize) <= -1)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
}
else
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
} }
else goto oops;
#else #else
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops; goto oops;
#endif #endif
} }
if (listen (fd, 10) <= -1) goto oops; if (listen (fd, 10) <= -1)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
#if defined(O_NONBLOCK) if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops;
flag = fcntl (fd, F_GETFL);
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
#endif
server->handle.i = fd; server->handle.i = fd;
return 0; return 0;
oops: oops:
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); if (is_valid_socket(fd)) close_socket (fd);
#if defined(_WIN32)
if (fd != INVALID_SOCKET) closesocket (fd);
#elif defined(__OS2__)
if (fd >= 0) soclose (fd);
#elif defined(__DOS__)
/* TODO: */
#else
if (fd >= 0) QSE_CLOSE (fd);
#endif
return -1; return -1;
#endif #endif
} }
static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server) static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
#if defined(_WIN32) close_socket (server->handle.i);
closesocket (server->handle.i);
#elif defined(__OS2__)
soclose (server->handle.i);
#elif defined(__DOS__)
/* TODO: */
#else
QSE_CLOSE (server->handle.i);
#endif
} }
static int server_accept ( static int server_accept (
@ -790,29 +871,25 @@ static int server_accept (
#else #else
qse_skad_t addr; qse_skad_t addr;
#if defined(HAVE_SOCKLEN_T)
socklen_t addrlen; socklen_t addrlen;
#else sock_t fd = SOCK_INIT;
int addrlen; int flag;
#endif
int fd, flag;
addrlen = QSE_SIZEOF(addr); addrlen = QSE_SIZEOF(addr);
fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen); fd = accept (server->handle.i, (struct sockaddr*)&addr, &addrlen);
if (fd <= -1) if (!is_valid_socket(fd))
{ {
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
return -1; goto oops;
} }
#if 0 #if 0
/* TODO: implement maximum number of client per server??? */
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"));
/*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/ /*TODO: qse_httpd_seterrnum (httpd, QSE_HTTPD_EXXXXX);*/
QSE_CLOSE (fd); goto oops;
return -1;
} }
#endif #endif
@ -821,10 +898,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
#endif #endif
#if defined(O_NONBLOCK) if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops;
flag = fcntl (fd, F_GETFL);
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
#endif
if (qse_skadtonwad (&addr, &client->remote_addr) <= -1) if (qse_skadtonwad (&addr, &client->remote_addr) <= -1)
{ {
@ -867,6 +941,10 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n"));
client->handle.i = fd; client->handle.i = fd;
return 0; return 0;
oops:
if (is_valid_socket(fd)) close_socket (fd);
return -1;
#endif #endif
} }
@ -885,17 +963,14 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
qse_skad_t connaddr, bindaddr; qse_skad_t connaddr, bindaddr;
int connaddrsize, bindaddrsize; int connaddrsize, bindaddrsize;
int connected = 1; int connected = 1;
sock_t fd = SOCK_INIT;
#if defined(_WIN32) #if defined(_WIN32)
SOCKET fd = -1;
unsigned long cmd; unsigned long cmd;
#elif defined(__OS2__) #elif defined(__OS2__)
int fd = -1;
int cmd; int cmd;
#elif defined(__DOS__) #elif defined(__DOS__)
int fd = -1;
int flag; int flag;
#else #else
int fd = -1;
int flag; int flag;
#endif #endif
@ -908,7 +983,11 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
} }
fd = socket (qse_skadfamily(&connaddr), SOCK_STREAM, IPPROTO_TCP); fd = socket (qse_skadfamily(&connaddr), SOCK_STREAM, IPPROTO_TCP);
if (fd <= -1) goto oops; if (!is_valid_socket(fd))
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
#if defined(IP_TRANSPARENT) #if defined(IP_TRANSPARENT)
flag = 1; flag = 1;
@ -921,72 +1000,58 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
/* TODO: some logging for this failure though */ /* TODO: some logging for this failure though */
} }
#if defined(_WIN32)
cmd = 1;
if (ioctlsocket(fd, FIONBIO, &cmd) == SOCKET_ERROR) goto oops;
if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1)
{
if (WSAGetLastError() != WSAEWOULDBLOCK) goto oops;
connected = 0;
}
cmd = 0;
if (ioctlsocket(fd, FIONBIO, &cmd) == SOCKET_ERROR) goto oops;
#elif defined(__OS2__)
cmd = 1;
if (ioctl(fd, FIONBIO, (char*)&cmd, QSE_SIZEOF(cmd)) == -1) goto oops;
if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) == -1)
{
if (sock_errno() != SOCEINPROGRESS) goto oops;
connected = 0;
}
cmd = 0;
if (ioctl(fd, FIONBIO, (char*)&cmd, QSE_SIZEOF(cmd)) == -1) goto oops;
#elif defined(__DOS__)
/* TODO: */
#else
#if defined(FD_CLOEXEC) #if defined(FD_CLOEXEC)
flag = fcntl (fd, F_GETFD); flag = fcntl (fd, F_GETFD);
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
#endif #endif
flag = fcntl (fd, F_GETFL); if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops;
if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK);
#if defined(_WIN32)
if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1)
{ {
if (errno != EINPROGRESS) goto oops; if (WSAGetLastError() != WSAEWOULDBLOCK)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
connected = 0; connected = 0;
} }
/* restore flags */ #elif defined(__OS2__)
if (fcntl (fd, F_SETFL, flag) <= -1) goto oops; if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) == -1)
{
if (sock_errno() != SOCEINPROGRESS)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
connected = 0;
}
#elif defined(__DOS__)
/* TODO: */
#else
if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1)
{
if (errno != EINPROGRESS)
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
connected = 0;
}
#endif #endif
/*if (set_socket_nonblock (httpd, fd, 0) <= -1) goto oops;*/
peer->handle.i = fd; peer->handle.i = fd;
return connected; return connected;
oops: oops:
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
#if defined(_WIN32) if (is_valid_socket(fd)) close_socket (fd);
if (fd != INVALID_SOCKET) closesocket (fd);
#elif defined(__OS2__)
if (fd >= 0) soclose (fd);
#elif defined(__DOS__)
/* TODO: */
#else
if (fd >= 0) QSE_CLOSE (fd);
#endif
return -1; return -1;
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -995,15 +1060,7 @@ oops:
static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer) static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
{ {
#if defined(_WIN32) close_socket (peer->handle.i);
closesocket (peer->handle.i);
#elif defined(__OS2__)
soclose (peer->handle.i);
#elif defined(__DOS__)
/* TODO: */
#else
QSE_CLOSE (peer->handle.i);
#endif
} }
static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
@ -1057,11 +1114,7 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
#else #else
#if defined(HAVE_SOCKLEN_T)
socklen_t len; socklen_t len;
#else
int len;
#endif
int ret; int ret;
len = QSE_SIZEOF(ret); len = QSE_SIZEOF(ret);
@ -1747,26 +1800,22 @@ static int dir_read (qse_httpd_t* httpd, qse_ubi_t handle, qse_httpd_dirent_t* d
# define SHUT_RDWR 2 # define SHUT_RDWR 2
#endif #endif
static void client_close ( static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client)
qse_httpd_t* httpd, qse_httpd_client_t* client)
{ {
#if defined(_WIN32) #if defined(_WIN32)
shutdown (client->handle.i, SHUT_RDWR); shutdown (client->handle.i, SHUT_RDWR);
closesocket (client->handle.i);
#elif defined(__OS2__) #elif defined(__OS2__)
shutdown (client->handle.i, SHUT_RDWR); shutdown (client->handle.i, SHUT_RDWR);
soclose (client->handle.i);
#elif defined(__DOS__) #elif defined(__DOS__)
/* TODO: */ /* TODO: */
#else #else
shutdown (client->handle.i, SHUT_RDWR); shutdown (client->handle.i, SHUT_RDWR);
QSE_CLOSE (client->handle.i);
#endif #endif
close_socket (client->handle.i);
} }
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(_WIN32) #if defined(_WIN32)
shutdown (client->handle.i, SHUT_RDWR); shutdown (client->handle.i, SHUT_RDWR);
@ -2201,7 +2250,8 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
return -1; return -1;
#else #else
int fd = -1, flag; sock_t fd = SOCK_INIT;
int flag;
qse_nwad_t nwad; qse_nwad_t nwad;
dns_ctx_t* dc; dns_ctx_t* dc;
httpd_xtn_t* httpd_xtn; httpd_xtn_t* httpd_xtn;
@ -2276,7 +2326,11 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
} }
fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP); fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP);
if (fd <= -1) goto oops; if (!is_valid_socket(fd))
{
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
goto oops;
}
#if defined(FD_CLOEXEC) #if defined(FD_CLOEXEC)
flag = fcntl (fd, F_GETFD); flag = fcntl (fd, F_GETFD);
@ -2293,22 +2347,14 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag)); setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag));
#endif #endif
if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops;
dns->handle.i = fd; dns->handle.i = fd;
dns->ctx = dc; dns->ctx = dc;
return 0; return 0;
oops: oops:
if (fd >= 0) if (is_valid_socket(fd)) close_socket (fd);
{
#if defined(_WIN32)
closesocket (fd);
#elif defined(__OS2__)
soclose (fd);
#else
QSE_CLOSE (fd);
#endif
}
if (dc) qse_httpd_freemem (httpd, dc); if (dc) qse_httpd_freemem (httpd, dc);
return -1; return -1;
@ -2447,7 +2493,7 @@ static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
dns_ctx_t* dc = (dns_ctx_t*)dns->ctx; dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
qse_skad_t fromaddr; qse_skad_t fromaddr;
socklen_t fromlen; /* TODO: change type */ socklen_t fromlen;
qse_uint8_t buf[DNS_MAX_MSG_LEN]; qse_uint8_t buf[DNS_MAX_MSG_LEN];
qse_ssize_t len; qse_ssize_t len;
@ -2614,16 +2660,13 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t
qse_size_t name_len; qse_size_t name_len;
dns_ans_t* ans; dns_ans_t* ans;
printf ("finding answer in cache...\n");
ans = dns_get_answer_from_cache (dc, name); ans = dns_get_answer_from_cache (dc, name);
if (ans) if (ans)
{ {
printf ("found answer in cache...\n");
resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx); resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx);
return 0; return 0;
} }
printf ("found XXXXX in cache...\n");
seq = dc->seq; seq = dc->seq;
seq = (seq + 1) % QSE_COUNTOF(dc->reqs); seq = (seq + 1) % QSE_COUNTOF(dc->reqs);
dc->seq = seq; dc->seq = seq;

View File

@ -90,13 +90,19 @@ static int task_main_format (
count = MAX_SEND_SIZE; count = MAX_SEND_SIZE;
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count);
if (n <= -1) return -1; if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1;
}
else if (n > 0)
{
ctx->left -= n; ctx->left -= n;
if (ctx->left <= 0) return 0; if (ctx->left <= 0) return 0;
ctx->ptr += n; ctx->ptr += n;
}
return 1; /* more work to do */ return 1; /* more work to do */
} }

View File

@ -53,13 +53,18 @@ static int task_main_text (
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
/* TODO: do i need to add code to skip this send if count is 0? */ /* TODO: do i need to add code to skip this send if count is 0? */
httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count); n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count);
if (n <= -1) return -1; if (n <= -1)
{
if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1;
}
else if (n > 0)
{
ctx->left -= n; ctx->left -= n;
if (ctx->left <= 0) return 0; if (ctx->left <= 0) return 0;
ctx->ptr += n; ctx->ptr += n;
}
return 1; /* more work to do */ return 1; /* more work to do */
} }

View File

@ -921,7 +921,7 @@ static int update_mux_for_current_task (qse_httpd_t* httpd, qse_httpd_client_t*
{ {
/* active to inactive */ /* active to inactive */
printf ("ACTIVE TO INACTIVE....\n"); /*printf ("ACTIVE TO INACTIVE....\n");*/
for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++)
{ {
if (client->status & CLIENT_TASK_TRIGGER_RW_IN_MUX(i)) if (client->status & CLIENT_TASK_TRIGGER_RW_IN_MUX(i))
@ -942,21 +942,21 @@ printf ("ACTIVE TO INACTIVE....\n");
return 0; return 0;
} }
printf ("INACTIVE TO ACTIVE....\n"); /*printf ("INACTIVE TO ACTIVE....\n");*/
/* inactive to active . go on*/ /* inactive to active . go on*/
} }
else else
{ {
if (task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE) if (task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE)
{ {
printf ("INACTIVE TO INACTIVE....\n"); /*printf ("INACTIVE TO INACTIVE....\n");*/
/* inactive to inactive. /* inactive to inactive.
* save the trigger as the trigger handle and masks could change */ * save the trigger as the trigger handle and masks could change */
client->trigger = task->trigger; client->trigger = task->trigger;
return 0; return 0;
} }
printf ("ACTIVE TO ACTIVE....\n"); /*printf ("ACTIVE TO ACTIVE....\n");*/
/* active to active. go on */ /* active to active. go on */
} }
@ -1183,13 +1183,23 @@ static int invoke_client_task (
{ {
if (mask & QSE_HTTPD_MUX_READ) if (mask & QSE_HTTPD_MUX_READ)
{ {
QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ); /*QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ);*/
/* the assertion above may be false if a task for the same
* trigger set was called earlier by a qse_mux_poll() call.
* and the task has changed some masks.
*
* for instance, you put handle A and B in to a trigger.
* if the task is triggered for A but the task may change
* the mask for B. the task may get executed for B by
* the same qse_mux_poll() call.
*/
task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE; task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE;
trigger_fired = 1; trigger_fired = 1;
} }
if (mask & QSE_HTTPD_MUX_WRITE) if (mask & QSE_HTTPD_MUX_WRITE)
{ {
QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE); /*QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE);*/
task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE;
trigger_fired = 1; trigger_fired = 1;
} }