added system call macros for x86 and x86_64 for implementing pio based on vfork

This commit is contained in:
hyung-hwan 2012-03-26 14:11:11 +00:00
parent 7c224230f2
commit 5a0bd73990
9 changed files with 766 additions and 66 deletions

9
qse/configure vendored
View File

@ -16179,12 +16179,13 @@ _ACEOF
fi
done
for ac_func in posix_spawn
for ac_func in fork vfork posix_spawn
do :
ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
if test "x$ac_cv_func_posix_spawn" = xyes; then :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_POSIX_SPAWN 1
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi

View File

@ -106,7 +106,7 @@ AC_CHECK_FUNCS([utime utimes])
AC_CHECK_FUNCS([sysconf])
AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([fdopendir])
AC_CHECK_FUNCS([posix_spawn])
AC_CHECK_FUNCS([fork vfork posix_spawn])
OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS"

View File

@ -94,6 +94,9 @@
/* Define to 1 if you have the `fmodl' function. */
#undef HAVE_FMODL
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `fstat64' function. */
#undef HAVE_FSTAT64
@ -321,6 +324,9 @@
/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H
/* Define to 1 if you have the `vfork' function. */
#undef HAVE_VFORK
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H

View File

@ -1453,25 +1453,25 @@ void* qse_awk_rtx_getxtnstd (qse_awk_rtx_t* rtx)
return (void*)((rxtn_t*)QSE_XTN(rtx) + 1);
}
static int fnc_rand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
static int fnc_rand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
{
qse_awk_val_t* r;
/*
rxtn_t* rxtn;
rxtn = (rxtn_t*) QSE_XTN (run);
rxtn = (rxtn_t*) QSE_XTN (rtx);
r = qse_awk_rtx_makefltval (
run, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX );
rtx, (qse_flt_t)(rand_r(rxtn->seed) % RAND_MAX) / RAND_MAX );
*/
r = qse_awk_rtx_makefltval (
run, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX);
rtx, (qse_flt_t)(rand() % RAND_MAX) / RAND_MAX);
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (run, r);
qse_awk_rtx_setretval (rtx, r);
return 0;
}
static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
static int fnc_srand (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
{
qse_size_t nargs;
qse_awk_val_t* a0;
@ -1481,16 +1481,16 @@ static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
unsigned int prev;
rxtn_t* rxtn;
rxtn = (rxtn_t*) QSE_XTN (run);
nargs = qse_awk_rtx_getnargs (run);
rxtn = (rxtn_t*) QSE_XTN (rtx);
nargs = qse_awk_rtx_getnargs (rtx);
QSE_ASSERT (nargs == 0 || nargs == 1);
prev = rxtn->seed;
if (nargs == 1)
{
a0 = qse_awk_rtx_getarg (run, 0);
n = qse_awk_rtx_valtolong (run, a0, &lv);
a0 = qse_awk_rtx_getarg (rtx, 0);
n = qse_awk_rtx_valtolong (rtx, a0, &lv);
if (n <= -1) return -1;
rxtn->seed = lv;
@ -1504,10 +1504,10 @@ static int fnc_srand (qse_awk_rtx_t* run, const qse_cstr_t* fnm)
srand (rxtn->seed);
r = qse_awk_rtx_makeintval (run, prev);
r = qse_awk_rtx_makeintval (rtx, prev);
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (run, r);
qse_awk_rtx_setretval (rtx, r);
return 0;
}
@ -1572,6 +1572,20 @@ skip_system:
return 0;
}
static int fnc_time (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm)
{
qse_awk_val_t* r;
qse_ntime_t now;
if (qse_gettime (&now) <= -1) now = 0;
r = qse_awk_rtx_makeintval (rtx, now);
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r);
return 0;
}
#if defined(QSE_CHAR_IS_WCHAR)
static qse_cmgr_t* getcmgr_from_cmgrtab (
qse_awk_rtx_t* rtx, const qse_char_t* ioname)
@ -1707,6 +1721,7 @@ static int add_functions (qse_awk_t* awk)
ADDFNC (awk, QSE_T("rand"), 0, 0, fnc_rand, 0);
ADDFNC (awk, QSE_T("srand"), 0, 1, fnc_srand, 0);
ADDFNC (awk, QSE_T("system"), 1, 1, fnc_system, 0);
ADDFNC (awk, QSE_T("time"), 0, 0, fnc_time, 0);
#if defined(QSE_CHAR_IS_WCHAR)
ADDFNC (awk, QSE_T("setenc"), 2, 2, fnc_setenc, QSE_AWK_RIO);
ADDFNC (awk, QSE_T("unsetenc"), 1, 1, fnc_unsetenc, QSE_AWK_RIO);

View File

@ -550,13 +550,23 @@ int qse_pio_init (
/* DOS not multi-processed. can't support pio */
#elif defined(HAVE_POSIX_SPAWN)
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
posix_spawn_file_actions_t fa;
int fa_inited = 0;
int pserr;
#if defined(__linux)
posix_spawnattr_t psattr;
#endif
qse_pio_pid_t pid;
param_t param;
extern char** environ;
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
qse_pio_pid_t pid;
param_t param;
extern char** environ;
char** envarr;
int highest_fd;
int dummy;
#else
qse_pio_pid_t pid;
param_t param;
@ -1178,7 +1188,7 @@ create_process:
pio->errnum = QSE_PIO_ENOIMPL;
return -1;
#elif defined(HAVE_POSIX_SPAWN)
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
if (flags & QSE_PIO_WRITEIN)
{
if (QSE_PIPE(&handle[0]) <= -1)
@ -1379,9 +1389,22 @@ create_process:
goto oops;
}
#if defined(__linux)
posix_spawnattr_init (&psattr);
#if !defined(POSIX_SPAWN_USEVFORK)
# define POSIX_SPAWN_USEVFORK 0x40
#endif
posix_spawnattr_setflags (&psattr, POSIX_SPAWN_USEVFORK);
#endif
pserr = posix_spawn(
&pid, param.argv[0], &fa, QSE_NULL, param.argv,
&pid, param.argv[0], &fa, &psattr, param.argv,
(env? qse_env_getarr(env): environ));
#if defined(__linux)
posix_spawnattr_destroy (&psattr);
#endif
free_param (pio, &param);
if (fa_inited)
{
@ -1411,6 +1434,210 @@ create_process:
handle[5] = QSE_PIO_HND_NIL;
}
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
if (flags & QSE_PIO_WRITEIN)
{
if (QSE_PIPE(&handle[0]) <= -1)
{
pio->errnum = syserr_to_errnum (errno);
goto oops;
}
minidx = 0; maxidx = 1;
}
if (flags & QSE_PIO_READOUT)
{
if (QSE_PIPE(&handle[2]) <= -1)
{
pio->errnum = syserr_to_errnum (errno);
goto oops;
}
if (minidx == -1) minidx = 2;
maxidx = 3;
}
if (flags & QSE_PIO_READERR)
{
if (QSE_PIPE(&handle[4]) <= -1)
{
pio->errnum = syserr_to_errnum (errno);
goto oops;
}
if (minidx == -1) minidx = 4;
maxidx = 5;
}
if (maxidx == -1)
{
pio->errnum = QSE_PIO_EINVAL;
goto oops;
}
if (make_param (pio, cmd, flags, &param) <= -1) goto oops;
/* check if the command(the command requested or /bin/sh) is
* exectuable to return an error without trying to execute it
* though this check alone isn't sufficient */
if (assert_executable (pio, param.argv[0]) <= -1)
{
free_param (pio, &param);
goto oops;
}
if (!(flags & QSE_PIO_NOCLOEXEC))
highest_fd = get_highest_fd ();
envarr = env? qse_env_getarr(env): environ;
QSE_SYSCALL0 (pid, SYS_vfork);
if (pid <= -1)
{
pio->errnum = QSE_PIO_EINVAL;
free_param (pio, &param);
goto oops;
}
if (pid == 0)
{
/* child */
qse_pio_hnd_t devnull = -1;
if (!(flags & QSE_PIO_NOCLOEXEC))
{
int fd = highest_fd;
/* close all other unknown open handles except
* stdin/out/err and the pipes. */
while (--fd > 2)
{
if (fd != handle[0] && fd != handle[1] &&
fd != handle[2] && fd != handle[3] &&
fd != handle[4] && fd != handle[5])
{
QSE_SYSCALL1 (dummy, SYS_close, fd);
}
}
}
if (flags & QSE_PIO_WRITEIN)
{
/* child should read */
QSE_SYSCALL1 (dummy, SYS_close, handle[1]);
/*handle[1] = QSE_PIO_HND_NIL;*/
QSE_SYSCALL2 (dummy, SYS_dup2, handle[0], 0);
if (dummy <= -1) goto child_oops;
QSE_SYSCALL1 (dummy, SYS_close, handle[0]);
/*handle[0] = QSE_PIO_HND_NIL;*/
}
if (flags & QSE_PIO_READOUT)
{
/* child should write */
QSE_SYSCALL1 (dummy, SYS_close, handle[2]);
/*handle[2] = QSE_PIO_HND_NIL;*/
QSE_SYSCALL2 (dummy, SYS_dup2, handle[3], 1);
if (dummy <= -1) goto child_oops;
if (flags & QSE_PIO_ERRTOOUT)
{
QSE_SYSCALL2 (dummy, SYS_dup2, handle[3], 2);
if (dummy <= -1) goto child_oops;
}
QSE_SYSCALL1 (dummy, SYS_close, handle[3]);
/*handle[3] = QSE_PIO_HND_NIL;*/
}
if (flags & QSE_PIO_READERR)
{
/* child should write */
QSE_SYSCALL1 (dummy, SYS_close, handle[4]);
/*handle[4] = QSE_PIO_HND_NIL;*/
QSE_SYSCALL2 (dummy, SYS_dup2, handle[5], 2);
if (dummy <= -1) goto child_oops;
if (flags & QSE_PIO_OUTTOERR)
{
QSE_SYSCALL2 (dummy, SYS_dup2, handle[5], 1);
if (dummy <= -1) goto child_oops;
}
QSE_SYSCALL1 (dummy, SYS_close, handle[5]);
/*handle[5] = QSE_PIO_HND_NIL;*/
}
if ((flags & QSE_PIO_INTONUL) ||
(flags & QSE_PIO_OUTTONUL) ||
(flags & QSE_PIO_ERRTONUL))
{
#if defined(O_LARGEFILE)
QSE_SYSCALL3 (devnull, SYS_open, QSE_MT("/dev/null"), O_RDWR|O_LARGEFILE, 0);
#else
QSE_SYSCALL3 (devnull, SYS_open, QSE_MT("/dev/null"), O_RDWR, 0);
#endif
if (devnull <= -1) goto child_oops;
}
if (flags & QSE_PIO_INTONUL)
{
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 0);
if (dummy <= -1) goto child_oops;
}
if (flags & QSE_PIO_OUTTONUL)
{
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 1);
if (dummy <= -1) goto child_oops;
}
if (flags & QSE_PIO_ERRTONUL)
{
QSE_SYSCALL2 (dummy, SYS_dup2, devnull, 2);
if (dummy <= -1) goto child_oops;
}
if ((flags & QSE_PIO_INTONUL) ||
(flags & QSE_PIO_OUTTONUL) ||
(flags & QSE_PIO_ERRTONUL))
{
QSE_SYSCALL1 (dummy, SYS_close, devnull);
devnull = -1;
}
if (flags & QSE_PIO_DROPIN) QSE_SYSCALL1 (dummy, SYS_close, 0);
if (flags & QSE_PIO_DROPOUT) QSE_SYSCALL1 (dummy, SYS_close, 1);
if (flags & QSE_PIO_DROPERR) QSE_SYSCALL1 (dummy, SYS_close, 2);
QSE_SYSCALL3 (dummy, SYS_execve, param.argv[0], param.argv, envarr);
if (dummy == -1)
{
printf ("hello\n");
}
/*free_param (pio, &param); */
child_oops:
if (devnull >= 0) QSE_SYSCALL1 (dummy, SYS_close, devnull);
QSE_SYSCALL1 (dummy, SYS_exit, 128);
}
/* parent */
free_param (pio, &param);
pio->child = pid;
if (flags & QSE_PIO_WRITEIN)
{
QSE_CLOSE (handle[0]);
handle[0] = QSE_PIO_HND_NIL;
}
if (flags & QSE_PIO_READOUT)
{
QSE_CLOSE (handle[3]);
handle[3] = QSE_PIO_HND_NIL;
}
if (flags & QSE_PIO_READERR)
{
QSE_CLOSE (handle[5]);
handle[5] = QSE_PIO_HND_NIL;
}
#else
if (flags & QSE_PIO_WRITEIN)
@ -1485,7 +1712,10 @@ create_process:
{
if (fd != handle[0] && fd != handle[1] &&
fd != handle[2] && fd != handle[3] &&
fd != handle[4] && fd != handle[5]) QSE_CLOSE (fd);
fd != handle[4] && fd != handle[5])
{
QSE_CLOSE (fd);
}
}
}
@ -1703,7 +1933,7 @@ oops:
#elif defined(__DOS__)
/* DOS not multi-processed. can't support pio */
#elif defined(HAVE_POSIX_SPAWN)
#elif defined(HAVE_POSIX_SPAWN) && !(defined(QSE_SYSCALL0) && defined(SYS_vfork))
if (fa_inited)
{
posix_spawn_file_actions_destroy (&fa);
@ -1713,6 +1943,11 @@ oops:
{
if (handle[i] != QSE_PIO_HND_NIL) QSE_CLOSE (handle[i]);
}
#elif defined(QSE_SYSCALL0) && defined(SYS_vfork)
for (i = minidx; i < maxidx; i++)
{
if (handle[i] != QSE_PIO_HND_NIL) QSE_CLOSE (handle[i]);
}
#else
for (i = minidx; i < maxidx; i++)
{

View File

@ -173,6 +173,12 @@
# define QSE_FORK() fork()
#endif
#if defined(SYS_vfork)
# define QSE_VFORK() syscall(SYS_vfork)
#else
# define QSE_VFORK() vfork()
#endif
#if defined(SYS_execve)
# define QSE_EXECVE(path,argv,envp) syscall(SYS_execve,path,argv,envp)
#else
@ -349,4 +355,110 @@
# define QSE_UTIMES(path,t) utimes(path,t)
#endif
/* ------------------------------------------------------------------------ */
#if defined(__linux) && defined(__GNUC__) && defined(__x86_64)
#include <sys/syscall.h>
/*
#define QSE_SYSCALL0(ret,num) \
__asm__ volatile ( \
"movq %1, %%rax\n\t" \
"syscall\n": \
"=&a"(ret): \
"g"((qse_uint64_t)num): \
"%rcx", "%r11")
#define QSE_SYSCALL1(ret,num,arg1) \
__asm__ volatile ( \
"movq %1, %%rax\n\t" \
"movq %2, %%rdi\n\t" \
"syscall\n": \
"=&a"(ret): \
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1): \
"%rdi", "%rcx", "%r11")
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
__asm__ volatile ( \
"movq %1, %%rax\n\t" \
"movq %2, %%rdi\n\t" \
"movq %3, %%rsi\n\t" \
"syscall\n": \
"=&a"(ret): \
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1), "g"((qse_uint64_t)arg2): \
"%rdi", "%rsi", "%rcx", "%r11")
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
__asm__ volatile ( \
"movq %1, %%rax\n\t" \
"movq %2, %%rdi\n\t" \
"movq %3, %%rsi\n\t" \
"movq %4, %%rdx\n\t" \
"syscall\n": \
"=&a"(ret): \
"g"((qse_uint64_t)num), "g"((qse_uint64_t)arg1), "g"((qse_uint64_t)arg2), "g"((qse_uint64_t)arg3): \
"%rdi", "%rsi", "%rdx", "%rcx", "%r11")
*/
#define QSE_SYSCALL0(ret,num) \
__asm__ volatile ( \
"syscall\n": \
"=a"(ret): \
"a"((qse_uint64_t)num) : \
"%rcx", "%r11")
#define QSE_SYSCALL1(ret,num,arg1) \
__asm__ volatile ( \
"syscall\n": \
"=a"(ret): \
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1): \
"%rcx", "%r11")
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
__asm__ volatile ( \
"syscall\n": \
"=a"(ret): \
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1), "S"((qse_uint64_t)arg2): \
"%rcx", "%r11")
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
__asm__ volatile ( \
"syscall\n": \
"=a"(ret): \
"a"((qse_uint64_t)num), "D"((qse_uint64_t)arg1), "S"((qse_uint64_t)arg2), "d"((qse_uint64_t)arg3): \
"%rcx", "%r11")
#elif defined(__linux) && defined(__GNUC__) && defined(__i386)
#include <sys/syscall.h>
#define QSE_SYSCALL0(ret,num) \
__asm__ volatile ( \
"int $0x80\n": \
"=a"(ret): \
"a"((qse_uint32_t)num))
#define QSE_SYSCALL1(ret,num,arg1) \
__asm__ volatile ( \
"int $0x80\n": \
"=a"(ret): \
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1))
#define QSE_SYSCALL2(ret,num,arg1,arg2) \
__asm__ volatile ( \
"int $0x80\n": \
"=a"(ret): \
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2))
#define QSE_SYSCALL3(ret,num,arg1,arg2,arg3) \
__asm__ volatile ( \
"int $0x80\n": \
"=a"(ret): \
"a"((qse_uint32_t)num), "b"((qse_uint32_t)arg1), "c"((qse_uint32_t)arg2), "d"((qse_uint32_t)arg3))
#endif
/* ------------------------------------------------------------------------ */
#endif

View File

@ -1572,8 +1572,8 @@ static int cgi_snatch_content (
task = (qse_httpd_task_t*)ctx;
cgi = (task_cgi_t*)task->ctx;
if (ptr) qse_printf (QSE_T("!!!SNATCHING [%.*hs]\n"), len, ptr);
else qse_printf (QSE_T("!!!SNATCHING DONE\n"));
if (ptr) qse_printf (QSE_T("!!!CGI SNATCHING [%.*hs]\n"), len, ptr);
else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n"));
if (ptr == QSE_NULL)
{
@ -1614,7 +1614,7 @@ else qse_printf (QSE_T("!!!SNATCHING DONE\n"));
{
return -1;
}
qse_printf (QSE_T("!!!SNATCHED [%.*hs]\n"), len, ptr);
qse_printf (QSE_T("!!!CGI SNATCHED [%.*hs]\n"), len, ptr);
}
return 0;
@ -1800,8 +1800,10 @@ done:
cgi->env = makecgienv (httpd, client, arg->req, arg->path, content_length);
if (cgi->env == QSE_NULL) goto oops;
/* i don't set triggers yet. triggers will be set task_main_cgi().
* this way, task_main_cgi() is called regardless of data availability */
/* no triggers yet since the main loop doesn't allow me to set
* triggers in the task initializer. however the main task handler
* will be invoked so long as the client handle is writable by
* the main loop. */
task->ctx = cgi;
return 0;
@ -2349,10 +2351,278 @@ qse_httpd_task_t* qse_httpd_entasknph (
/*------------------------------------------------------------------------*/
#if 0
typedef struct task_proxy_arg_t task_proxy_arg_t;
struct task_proxy_arg_t
{
const qse_mchar_t* host;
qse_htre_t* req;
int nph;
};
typedef struct task_proxy_t task_proxy_t;
struct task_proxy_t
{
int init_failed;
const qse_mchar_t* host;
qse_http_version_t version;
int keepalive; /* taken from the request */
qse_htrd_t* htrd;
qse_htre_t* req; /* original request associated with this */
qse_mbs_t* reqfwdbuf; /* content from the request */
int reqfwderr;
qse_mbs_t* res;
qse_mchar_t* res_ptr;
qse_size_t res_left;
};
typedef struct proxy_htrd_xtn_t proxy_htrd_xtn_t;
struct proxy_htrd_xtn_t
{
task_proxy_t* proxy;
};
static int proxy_snatch_content (
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
{
qse_httpd_task_t* task;
task_proxy_t* proxy;
task = (qse_httpd_task_t*)ctx;
proxy = (task_proxy_t*)task->ctx;
if (ptr) qse_printf (QSE_T("!!!PROXY SNATCHING [%.*hs]\n"), len, ptr);
else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
if (ptr == QSE_NULL)
{
/*
* this callback is called with ptr of QSE_NULL
* when the request is completed or discarded.
* and this indicates that there's nothing more to read
* from the client side. this can happen when the end of
* a request is seen or when an error occurs
*/
QSE_ASSERT (len == 0);
/* mark the there's nothing to read form the client side */
proxy->req = QSE_NULL;
/* since there is no more to read from the client side.
* the relay trigger is not needed any more. */
task->trigger[2].mask = 0;
#if 0
if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0 && proxy->pio_inited &&
!(task->trigger[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITE))
{
/* there's nothing more to read from the client side.
* there's something to forward in the forwarding buffer.
* but no write trigger is set. add the write trigger
* for task invocation. */
task->trigger[1].mask = QSE_HTTPD_TASK_TRIGGER_WRITE;
task->trigger[1].handle = qse_pio_gethandleasubi (&proxy->pio, QSE_PIO_IN);
}
#endif
}
else if (!proxy->reqfwderr)
{
/* we can write to the child process if a forwarding error
* didn't occur previously. we store data from the client side
* to the forwaring buffer only if there's no such previous
* error. if an error occurred, we simply drop the data. */
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
{
return -1;
}
qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr);
}
return 0;
}
static int proxy_htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req)
{
return -1;
}
static qse_htrd_recbs_t proxy_htrd_cbs =
{
proxy_htrd_peek_request,
QSE_NULL /* not needed for proxy */
};
static int task_init_proxy (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_proxy_t* proxy;
task_proxy_arg_t* arg;
qse_size_t content_length;
qse_size_t len;
const qse_mchar_t* ptr;
proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task);
arg = (task_proxy_arg_t*)task->ctx;
/* TODO: can content length be a different type???
* maybe qse_uintmax_t.... it thinks the data size can be larger than the max pointer size
* qse_htre_t and qse_htrd_t also needs changes to support it
*/
QSE_MEMSET (proxy, 0, QSE_SIZEOF(*proxy));
qse_mbscpy ((qse_mchar_t*)(proxy + 1), arg->host);
proxy->host = (qse_mchar_t*)(proxy + 1);
proxy->version = *qse_htre_getversion(arg->req);
proxy->keepalive = arg->req->attr.keepalive;
if (arg->req->state & QSE_HTRE_DISCARDED)
{
qse_printf (QSE_T("XXXXXXXXXXXXXXXXX\n"));
content_length = 0;
goto done;
}
len = qse_htre_getcontentlen(arg->req);
if ((arg->req->state & QSE_HTRE_COMPLETED) && len <= 0)
{
qse_printf (QSE_T("YYYYYYYYYYYYYYYYy\n"));
/* the content part is completed and no content
* in the content buffer. there is nothing to forward */
content_length = 0;
goto done;
}
if (!(arg->req->state & QSE_HTRE_COMPLETED) &&
!arg->req->attr.content_length_set)
{
qse_printf (QSE_T("ZZZZZZZZZZZZZZZ\n"));
/* if the request is not completed and doesn't have
* content-length set, it's not really possible to
* pass the content. this function, however, allows
* such a request to entask a proxy script dropping the
* content */
qse_htre_discardcontent (arg->req);
content_length = 0;
}
else
{
/* create a buffer to hold request content from the client
* and copy content received already */
proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
if (proxy->reqfwdbuf == QSE_NULL) goto oops;
ptr = qse_htre_getcontentptr(arg->req);
if (qse_mbs_ncpy (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
{
qse_mbs_close (proxy->reqfwdbuf);
proxy->reqfwdbuf = QSE_NULL;
goto oops;
}
if (arg->req->state & QSE_HTRE_COMPLETED)
{
/* no furthur forwarding is needed.
* even a chunked request entaksed when completed
* should reach here. if content-length is set
* the length should match len. */
QSE_ASSERT (len > 0);
QSE_ASSERT (!arg->req->attr.content_length_set ||
(arg->req->attr.content_length_set && arg->req->attr.content_length == len));
qse_printf (QSE_T("HHHHHHHHHHHHHHHHhh %d\n"), (int)len);
content_length = len;
}
else
{
/* CGI entasking is invoked probably from the peek handler
* that was triggered after the request header is received.
* you can know this because the request is not completed.
* In this case, arrange to forward content
* bypassing the buffer in the request object itself. */
/* TODO: callback chain instead of a single pointer???
if the request is already set up with a callback, something will go wrong.
*/
/* set up a callback to be called when the request content
* is fed to the htrd reader. qse_htre_addcontent() that
* htrd calls invokes this callback. */
proxy->req = arg->req;
qse_htre_setconcb (proxy->req, proxy_snatch_content, task);
QSE_ASSERT (arg->req->attr.content_length_set);
content_length = arg->req->attr.content_length;
qse_printf (QSE_T("TTTTTTTTTTTTTTTTTTTT %d\n"), (int)content_length);
}
}
done:
/* no triggers yet since the main loop doesn't allow me to set
* triggers in the task initializer. however the main task handler
* will be invoked so long as the client handle is writable by
* the main loop. */
task->ctx = proxy;
return 0;
oops:
/* since a new task can't be added in the initializer,
* i mark that initialization failed and let task_main_proxy()
* add an error task */
proxy->init_failed = 1;
task->ctx = proxy;
return 0;
}
static void task_fini_proxy (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
}
static int task_main_proxy (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
proxy_htrd_xtn_t* xtn;
int http_errnum = 500;
if (proxy->init_failed) goto oops;
proxy->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(proxy_htrd_xtn_t));
if (proxy->htrd == QSE_NULL) goto oops;
xtn = (proxy_htrd_xtn_t*) qse_htrd_getxtn (proxy->htrd);
xtn->proxy = proxy;
qse_htrd_setrecbs (proxy->htrd, &proxy_htrd_cbs);
qse_htrd_setoption (
proxy->htrd,
QSE_HTRD_SKIPINITIALLINE |
QSE_HTRD_PEEKONLY |
QSE_HTRD_REQUEST
);
proxy->res = qse_mbs_open (httpd->mmgr, 0, 256);
if (proxy->res == QSE_NULL) goto oops;
///////////////////////
return 1;
oops:
if (proxy->res)
{
qse_mbs_close (proxy->res);
proxy->res = QSE_NULL;
}
if (proxy->htrd)
{
qse_htrd_close (proxy->htrd);
proxy->htrd = QSE_NULL;
}
return (entask_error (
httpd, client, task, http_errnum,
&proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0;
}
qse_httpd_task_t* qse_httpd_entaskproxy (
@ -2362,9 +2632,23 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
const qse_mchar_t* host,
const qse_htre_t* req)
{
qse_httpd_task_t task;
task_proxy_arg_t arg;
arg.host = host;
arg.req = req;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_proxy;
task.fini = task_fini_proxy;
task.main = task_main_proxy;
task.ctx = &arg;
return qse_httpd_entask (
httpd, client, pred, &task,
QSE_SIZEOF(task_proxy_t) + ((qse_mbslen(host) + 1) * QSE_SIZEOF(*host))
);
}
#endif
/*------------------------------------------------------------------------*/

View File

@ -775,10 +775,6 @@ static int invoke_client_task (
}
}
/* locate an active client to the tail of the client list */
qse_gettime (&client->last_active); /* TODO: error check??? */
move_client_to_tail (httpd, client);
n = task->main (httpd, client, task);
qse_printf (QSE_T("task returend %d\n"), n);
if (n <= -1) return -1;
@ -943,6 +939,10 @@ static int perform_client_task (
}
else
{
/* locate an active client to the tail of the client list */
qse_gettime (&client->last_active); /* TODO: error check??? */
move_client_to_tail (httpd, client);
if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops;
}

View File

@ -430,10 +430,6 @@ struct mux_t
struct mux_ev_t* ptr;
qse_size_t capa;
} mev;
#if 0
qse_fma_t* fma;
#endif
};
#define MUX_EV_ALIGN 64
@ -455,13 +451,6 @@ static void* mux_open (qse_httpd_t* httpd)
return QSE_NULL;
}
#if 0
mux->fma = qse_fma_open (qse_getmmgr(httpd), QSE_NULL);
if (mux->fma == QSE_NULL)
{
}
#endif
return mux;
}
@ -486,28 +475,22 @@ static int mux_addhnd (
if (mask & QSE_HTTPD_MUX_READ) ev.events |= EPOLLIN;
if (mask & QSE_HTTPD_MUX_WRITE) ev.events |= EPOLLOUT;
if (ev.events == 0)
if (ev.events == 0 || handle.i <= -1)
{
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
return -1;
}
#if 0
mev = qse_httpd_allocmem (httpd, QSE_SIZEOF(*mev));
if (mev == QSE_NULL) return -1;
#endif
if (handle.i >= mux->mev.capa)
{
struct mux_ev_t* tmp;
qse_size_t tmpcapa;
tmpcapa = (((handle.i + MUX_EV_ALIGN - 1) / MUX_EV_ALIGN) * MUX_EV_ALIGN) + 1;
tmpcapa = (((handle.i + MUX_EV_ALIGN) / MUX_EV_ALIGN) * MUX_EV_ALIGN);
/* TODO: allocate this from fma ... */
tmp = qse_httpd_reallocmem (
httpd, mux->mev.ptr,
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa); /* TODO: round up handle.i ... */
QSE_SIZEOF(*mux->mev.ptr) * tmpcapa);
if (tmp == QSE_NULL) return -1;
mux->mev.ptr = tmp;
@ -521,11 +504,7 @@ static int mux_addhnd (
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;
}
if (tmp == QSE_NULL) return -1;
mux->ee.ptr = tmp;
mux->ee.capa = (mux->ee.capa + 1) * 2;
@ -544,7 +523,6 @@ static int mux_addhnd (
{
/* don't rollback ee.ptr */
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
/*qse_httpd_freemem (httpd, mev);*/
return -1;
}
@ -556,8 +534,6 @@ static int mux_delhnd (qse_httpd_t* httpd, void* vmux, qse_ubi_t handle)
{
struct mux_t* mux = (struct mux_t*)vmux;
/* TODO: delete mev associated with handle.i */
if (epoll_ctl (mux->fd, EPOLL_CTL_DEL, handle.i, QSE_NULL) <= -1)
{
qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
@ -597,8 +573,6 @@ static int mux_poll (qse_httpd_t* httpd, void* vmux, qse_ntime_t timeout)
}
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;
}
@ -971,7 +945,6 @@ if (qse_htre_getcontentlen(req) > 0)
qse_printf (QSE_T("CONTENT after discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req));
}
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
{
const qse_mchar_t* qpath = qse_htre_getqpathptr(req);
@ -1089,6 +1062,80 @@ oops:
return -1;
}
#if 0
static int proxy_request (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek)
{
const qse_mchar_t* qpath;
qpath = qse_htre_qpathptr (eq);
if (qpath[0] == QSE_MT('/'))
{
host = qse_htre_getheaderval (req, QSE_MT("Host"));
if (host == QSE_NULL)
{
qse_printf (QSE_T("Host not included....\n"));
goto oops;
}
}
else
{
const qse_mchar_t* host;
qse_parseuri ();
}
#if 0
if (peek)
{
if (req->attr.expect &&
(req->version.major > 1 ||
(req->version.major == 1 && req->version.minor >= 1)) &&
!content_received)
{
/* TODO: check method.... */
/* "expect" in the header, version 1.1 or higher,
* and no content received yet */
if (qse_mbscasecmp(req->attr.expect, QSE_MT("100-continue")) != 0)
{
if (qse_httpd_entaskerror (
httpd, client, QSE_NULL, 417, req) == QSE_NULL) return -1;
if (qse_httpd_entaskdisconnect (
httpd, client, QSE_NULL) == QSE_NULL) return -1;
}
else
{
/* TODO: determine if to return 100-continue or other errors */
if (qse_httpd_entaskcontinue (
httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
}
}
}
#endif
if (qse_htre_getqparamlen(req) > 0) qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparamptr(req));
task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, qpath, req);
if (task == QSE_NULL) goto oops;
if (!req->attr.keepalive)
{
if (!peek)
{
task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
if (task == QSE_NULL) goto oops;
}
}
return 0;
oops:
return -1;
}
#endif
static int peek_request (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
{