diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h index 146e7e9c..db66c88f 100644 --- a/qse/include/qse/cmn/nwad.h +++ b/qse/include/qse/cmn/nwad.h @@ -105,6 +105,12 @@ QSE_EXPORT void qse_clearnwad ( qse_nwad_type_t type ); +QSE_EXPORT void qse_setnwadport ( + qse_nwad_t* nwad, + qse_uint16_t port +); + + QSE_EXPORT int qse_mbstonwad ( const qse_mchar_t* mbs, qse_nwad_t* nwad diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index c2b9a35a..4b7cc51e 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -360,6 +360,8 @@ struct qse_httpd_task_trigger_t { int flags; /**< [IN] bitwise-ORed of #qse_httpd_task_trigger_flag_t enumerators*/ + + int cmask; /* client mask - QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ struct { int mask; /* QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c index 00f9fbee..6e56a470 100644 --- a/qse/lib/cmn/nwad.c +++ b/qse/lib/cmn/nwad.c @@ -52,6 +52,20 @@ void qse_clearnwad (qse_nwad_t* nwad, qse_nwad_type_t type) nwad->type = type; } +void qse_setnwadport (qse_nwad_t* nwad, qse_uint16_t port) +{ + switch (nwad->type) + { + case QSE_NWAD_IN4: + nwad->u.in4.port = port; + break; + + case QSE_NWAD_IN6: + nwad->u.in4.port = port; + break; + } +} + int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) { return qse_mbsntonwad (str, qse_mbslen(str), nwad); diff --git a/qse/lib/http/httpd-cgi.c b/qse/lib/http/httpd-cgi.c index aae9a7f6..56bad4be 100644 --- a/qse/lib/http/httpd-cgi.c +++ b/qse/lib/http/httpd-cgi.c @@ -233,7 +233,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) /* TODO: check the syntax of status value??? if not numeric??? */ QSE_MBSTONUM (nstatus, req->attr.status, &endptr, 10); - snprintf (buf, QSE_COUNTOF(buf), + snprintf (buf, QSE_COUNTOF(buf), QSE_MT("HTTP/%d.%d %d "), cgi->version.major, cgi->version.minor, @@ -561,7 +561,7 @@ else qse_printf (QSE_T("!!!CGI SNATCHING DONE\n")); /* since there is no more to read from the client side. * the relay trigger is not needed any more. */ - task->trigger.v[2].mask = 0; + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ; if (QSE_MBS_LEN(cgi->reqfwdbuf) > 0 && cgi->pio_inited && !(task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITE)) @@ -630,9 +630,6 @@ static void cgi_forward_client_input_to_script ( { /* a forwarding error has occurred previously. * clear the forwarding buffer */ -#if 0 -qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); -#endif qse_mbs_clear (cgi->reqfwdbuf); } else @@ -648,11 +645,6 @@ qse_printf (QSE_T("FORWARD: CLEARING REQCON FOR ERROR\n")); { forward: /* writable */ -#if 0 -qse_printf (QSE_T("FORWARD: @@@@@@@@@@WRITING[%.*hs]\n"), - (int)QSE_MBS_LEN(cgi->reqfwdbuf), - QSE_MBS_PTR(cgi->reqfwdbuf)); -#endif n = qse_pio_write ( &cgi->pio, QSE_PIO_IN, QSE_MBS_PTR(cgi->reqfwdbuf), @@ -703,19 +695,19 @@ to the head all the time.. grow the buffer to a certain limit. */ { done: /* there is nothing to read from the client side and - * there is nothing more to forward in the forwarding buffer. - * clear the relay and write triggers for the time being. - */ -#if 0 -qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO CGI\n")); -#endif + * there is nothing more to forward from the client-side to the peer + * in the forwarding buffer. */ QSE_ASSERT (cgi->req == QSE_NULL); /* mark the end of input to the child explicitly. */ qse_pio_end (&cgi->pio, QSE_PIO_IN); - task->trigger.v[1].mask = 0; /* pipe output to child */ - task->trigger.v[2].mask = 0; /* client-side */ + /* nothing more to write to the cgi script. so exclude + * the input pipe to the script from the mux */ + task->trigger.v[1].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; + + /* nothing to read from the client side. */ + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ; } } @@ -994,17 +986,20 @@ static int task_main_cgi_5 ( QSE_ASSERT (cgi->pio_inited); - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (cgi->reqfwdbuf) { - cgi_forward_client_input_to_script (httpd, task, 0); - } - else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) - { - cgi_forward_client_input_to_script (httpd, task, 1); + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) + { + cgi_forward_client_input_to_script (httpd, task, 0); + } + else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) + { + cgi_forward_client_input_to_script (httpd, task, 1); + } } - if (!(task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || - (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) + if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ + (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { if (cgi->buflen > 0) { @@ -1031,13 +1026,16 @@ static int task_main_cgi_4_nph ( QSE_ASSERT (cgi->nph); - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (cgi->reqfwdbuf) { - cgi_forward_client_input_to_script (httpd, task, 0); - } - else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) - { - cgi_forward_client_input_to_script (httpd, task, 1); + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) + { + cgi_forward_client_input_to_script (httpd, task, 0); + } + else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) + { + cgi_forward_client_input_to_script (httpd, task, 1); + } } if (task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) @@ -1051,7 +1049,7 @@ static int task_main_cgi_4_nph ( /* switch to the next phase */ task->main = task_main_cgi_5; task->trigger.v[0].mask = 0; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } } @@ -1073,17 +1071,20 @@ static int task_main_cgi_4 ( QSE_ASSERT (cgi->pio_inited); #if 0 -qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); +printf ("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", + task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (cgi->reqfwdbuf) { - cgi_forward_client_input_to_script (httpd, task, 0); - } - else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) - { - cgi_forward_client_input_to_script (httpd, task, 1); + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) + { + cgi_forward_client_input_to_script (httpd, task, 0); + } + else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) + { + cgi_forward_client_input_to_script (httpd, task, 1); + } } if (task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) @@ -1121,10 +1122,10 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger cgi->buf[cgi->buflen++] = QSE_MT('\n'); cgi->buf[cgi->buflen++] = QSE_MT('\r'); cgi->buf[cgi->buflen++] = QSE_MT('\n'); - + task->main = task_main_cgi_5; task->trigger.v[0].mask = 0; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } @@ -1169,7 +1170,7 @@ qse_printf (QSE_T("task_main_cgi_4 trigger[0].mask=%d trigger[1].mask=%d trigger /* switch to the next phase */ task->main = task_main_cgi_5; task->trigger.v[0].mask = 0; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } @@ -1207,23 +1208,26 @@ static int task_main_cgi_3 ( QSE_ASSERT (!cgi->nph); -#if 0 -qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); +#if 0 +printf ("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", + task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (cgi->reqfwdbuf) { - cgi_forward_client_input_to_script (httpd, task, 0); - } - else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) - { - cgi_forward_client_input_to_script (httpd, task, 1); + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) + { + cgi_forward_client_input_to_script (httpd, task, 0); + } + else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) + { + cgi_forward_client_input_to_script (httpd, task, 1); + } } /* send the partial reponse received with the initial line and headers * so long as the client-side handle is writable... */ - if (!(task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || - (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) + if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ + (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { count = MAX_SEND_SIZE; if (count >= cgi->res_left) count = cgi->res_left; @@ -1248,7 +1252,7 @@ qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger if ((cgi->resflags & CGI_RES_SCRIPT_LENGTH) && cgi->script_output_received >= cgi->script_output_length) - { + { /* if a cgi script specified the content length * and it has emitted as much as the length, * i don't wait for the script to finish. @@ -1257,12 +1261,12 @@ qse_printf (QSE_T("task_main_cgi_3 trigger[0].mask=%d trigger[1].mask=%d trigger * something extra after having done so. * however, a CGI script shouln't do that... */ task->main = task_main_cgi_5; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else { task->main = task_main_cgi_4; - task->trigger.v[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; } return 1; } @@ -1287,21 +1291,28 @@ static int task_main_cgi_2 ( QSE_ASSERT (cgi->pio_inited); #if 0 -qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); +printf ("task_main_cgi_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); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (cgi->reqfwdbuf) { - cgi_forward_client_input_to_script (httpd, task, 0); - } - else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) - { - cgi_forward_client_input_to_script (httpd, task, 1); + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) + { + /* client side is readable */ + cgi_forward_client_input_to_script (httpd, task, 0); + } + else if (task->trigger.v[1].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) + { + /* can write to the input pipe to the cgi script */ + cgi_forward_client_input_to_script (httpd, task, 1); + } } if (task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) { + /* can read from cgi's output pipe */ + n = qse_pio_read ( &cgi->pio, QSE_PIO_OUT, &cgi->buf[cgi->buflen], @@ -1347,14 +1358,10 @@ qse_printf (QSE_T("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d trigger cgi->res_ptr = QSE_MBS_PTR(cgi->res); cgi->res_left = QSE_MBS_LEN(cgi->res); -#if 0 -qse_printf (QSE_T("TRAILING DATA=[%.*hs]\n"), (int)QSE_MBS_LEN(cgi->res), QSE_MBS_PTR(cgi->res)); -#endif task->main = task_main_cgi_3; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } - } /* complete headers not seen yet. i need to be called again */ @@ -1380,8 +1387,7 @@ static int task_main_cgi ( * since i don't parse the header. so i have to close * the connection regardless of content-length or transfer-encoding * in the actual header. */ - if (qse_httpd_entaskdisconnect ( - httpd, client, task) == QSE_NULL) goto oops; + if (qse_httpd_entaskdisconnect (httpd, client, task) == QSE_NULL) goto oops; } else { @@ -1445,13 +1451,13 @@ static int task_main_cgi ( /* set the trigger that the main loop can use this * handle for multiplexing * - * it the output from the child is available, this task + * if the output from the child is available, this task * writes it back to the client. so add a trigger for * checking the data availability from the child process */ task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; task->trigger.v[0].handle = qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_OUT); task->trigger.v[1].handle = qse_pio_gethandleasubi (&cgi->pio, QSE_PIO_IN); - task->trigger.v[2].handle = client->handle; + task->trigger.cmask = 0; if (cgi->reqfwdbuf) { @@ -1462,7 +1468,7 @@ static int task_main_cgi ( { /* there are still things to forward from the client-side. * i can rely on this relay trigger for task invocation. */ - task->trigger.v[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; + task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ; } if (QSE_MBS_LEN(cgi->reqfwdbuf) > 0) diff --git a/qse/lib/http/httpd-file.c b/qse/lib/http/httpd-file.c index 1dd7ba1b..a7a57d1e 100644 --- a/qse/lib/http/httpd-file.c +++ b/qse/lib/http/httpd-file.c @@ -476,8 +476,9 @@ static int task_main_putfile_2 ( * QSE_NULL when snatching is over in putfile_snatch_client_input(). * i set a trigger so that the task is executed * while there is input from the client side */ - task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; - task->trigger.v[0].handle = client->handle; + /*task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; + task->trigger.v[0].handle = client->handle;*/ + task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ; return 1; /* trigger me when a client sends data */ } diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 72735d09..368f0a9c 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -23,6 +23,7 @@ #include "../cmn/mem.h" #include #include +#include typedef struct task_proxy_arg_t task_proxy_arg_t; struct task_proxy_arg_t @@ -49,7 +50,9 @@ struct task_proxy_t qse_htrd_t* peer_htrd; - const qse_mchar_t* peer_name; + qse_mchar_t* peer_name; + qse_uint16_t peer_port; + qse_httpd_peer_t peer; #define PROXY_PEER_OPEN (1 << 0) #define PROXY_PEER_CONNECTED (1 << 1) @@ -268,7 +271,7 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n")); /* since there is no more to read from the client side. * the relay trigger is not needed any more. */ - task->trigger.v[2].mask = 0; + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ; if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0 && (proxy->peer_status & PROXY_PEER_CONNECTED) && @@ -738,7 +741,7 @@ to the head all the time.. grow the buffer to a certain limit. */ * clear the read and write triggers. */ task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; /* peer */ - task->trigger.v[2].mask = 0; /* client-side */ + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ; /* client-side */ } } @@ -767,9 +770,29 @@ static int task_init_proxy ( proxy->peer.local = arg->rsrc->src.nwad; if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_STR) { + qse_mchar_t* colon; + proxy->flags |= PROXY_RESOL_PEER_NAME; - proxy->peer_name = (const qse_mchar_t*)(proxy + 1); - qse_mbscpy ((qse_mchar_t*)proxy->peer_name, arg->rsrc->dst.str); + proxy->peer_name = (qse_mchar_t*)(proxy + 1); + qse_mbscpy (proxy->peer_name, arg->rsrc->dst.str); + + colon = qse_mbschr (proxy->peer_name, QSE_MT(':')); + if (colon) + { + qse_mchar_t* endptr; + + /* handle a port number after the colon sign */ + *colon = QSE_MT('\0'); + QSE_MBSTONUM (proxy->peer_port, colon + 1, &endptr, 10); + + /* TODO: check if *endptr is QSE_T('\0')? */ + } + else + { + /*proxy->peer_port = 443;*/ + qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); + goto oops; + } } else { @@ -1014,10 +1037,10 @@ static int task_main_proxy_5 ( #if 0 printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n", - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); + task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) { /* if the client side is readable */ proxy_forward_client_input_to_peer (httpd, task, 0); @@ -1028,8 +1051,8 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask proxy_forward_client_input_to_peer (httpd, task, 1); } - if (!(task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || - (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) + if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ + (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { if (proxy->buflen > 0) { @@ -1063,10 +1086,10 @@ static int task_main_proxy_4 ( #if 1 printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n", - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); + task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) { proxy_forward_client_input_to_peer (httpd, task, 0); } @@ -1117,7 +1140,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask task->trigger.v[0].mask = 0; /* arrange to be called if the client side is writable */ - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; if (proxy->flags & PROXY_RAW) { @@ -1151,7 +1174,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask /* proxy has finished reading all */ task->main = task_main_proxy_5; task->trigger.v[0].mask = 0; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } } @@ -1188,10 +1211,10 @@ static int task_main_proxy_3 ( #if 0 qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n"), - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); + task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.cmask); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) { proxy_forward_client_input_to_peer (httpd, task, 0); } @@ -1200,8 +1223,8 @@ 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); } - if (!(task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || - (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) + if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ + (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { qse_ssize_t n; qse_size_t count; @@ -1230,20 +1253,27 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg if (proxy->res_pending <= 0) { + /* all data received from the peer so far(including those injected) + * have been sent back to the client-side */ + qse_mbs_clear (proxy->res); proxy->res_consumed = 0; if ((proxy->resflags & PROXY_RES_CLIENT_CHUNK) || ((proxy->resflags & PROXY_RES_PEER_LENGTH) && proxy->peer_output_received >= proxy->peer_output_length)) { + /* received all contents */ task->main = task_main_proxy_5; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else { - /* arrange to read the remaining contents from the peer */ + /* there are still more to read from the peer. + * arrange to read the remaining contents from the peer */ task->main = task_main_proxy_4; - task->trigger.v[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; + /* nothing to write in proxy->res. so clear WRITE from the + * client side */ + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; } return 1; } @@ -1259,11 +1289,11 @@ static int task_main_proxy_2 ( int http_errnum = 500; #if 0 -printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask=%d\n", - task->trigger.v[0].mask, task->trigger.v[1].mask, task->trigger.v[2].mask); +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); #endif - if (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READABLE) { /* client is readable */ proxy_forward_client_input_to_peer (httpd, task, 0); @@ -1274,8 +1304,8 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask proxy_forward_client_input_to_peer (httpd, task, 1); } - if (!(task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) || - (task->trigger.v[2].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) + if (/*!(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) ||*/ + (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { if (proxy->res_pending > 0) { @@ -1296,16 +1326,6 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask count = proxy->res_pending; if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; -#if 0 -qse_printf (QSE_T("[proxy_2 sending %d bytes (index %d)] ["), - (int)count, (int)proxy->res_consumed); -{ -int i; -for (i = 0; i < count; i++) qse_printf (QSE_T("%hc"), QSE_MBS_CHAR(proxy->res,proxy->res_consumed+i)); -} -qse_printf (QSE_T("]\n")); -#endif - n = httpd->opt.scb.client.send ( httpd, client, QSE_MBS_CPTR(proxy->res,proxy->res_consumed), @@ -1326,8 +1346,12 @@ qse_printf (QSE_T("]\n")); { /* '100 Continue' and payload received together * has all been relayed back. no need for writability - * check of the client side */ - task->trigger.v[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; + * check of the client side as there's nothing to write. + * when something is read from the peer and proxy->res + * becomes loaded, this cmask is added with WRITE + * in the 'if' block below that takes care of reading + * from the peer. */ + task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; } } } @@ -1373,7 +1397,7 @@ qse_printf (QSE_T("]\n")); * case. call qse_htrd_halt() for this. */ qse_htrd_halt (proxy->peer_htrd); task->main = task_main_proxy_3; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; return 1; } @@ -1408,24 +1432,27 @@ qse_printf (QSE_T("]\n")); { if (proxy->resflags & PROXY_RES_RECEIVED_RESCON) { + /* received the contents in full */ QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK); task->main = task_main_proxy_3; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else if (proxy->resflags & PROXY_RES_AWAIT_RESCON) { + /* waiting for contents */ QSE_ASSERT (proxy->resflags & PROXY_RES_CLIENT_CHUNK); - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else if (proxy->resflags & PROXY_RES_RECEIVED_RESHDR) { /* the actual response header has been received * with or without '100 continue'. you can * check it with proxy->resflags & PROXY_RES_RECEIVED_100 */ + if (proxy->resflags & PROXY_RES_CLIENT_CHUNK) { proxy->resflags |= PROXY_RES_AWAIT_RESCON; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else { @@ -1434,14 +1461,14 @@ qse_printf (QSE_T("TRAILING DATA=%d, [%hs]\n"), (int)QSE_MBS_LEN(proxy->res), QS #endif /* switch to the next phase */ task->main = task_main_proxy_3; - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } } else if (proxy->resflags & PROXY_RES_RECEIVED_100) { /* 100 continue has been received but * the actual response has not. */ - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; } else { @@ -1461,6 +1488,10 @@ oops: static int task_main_proxy_1 ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { + /* scheduling of this function is made in task_main_proxy() if + * the connection to the peer isn't established. this function should + * check the connection state to the peer. */ + task_proxy_t* proxy = (task_proxy_t*)task->ctx; int http_errnum = 500; @@ -1490,10 +1521,11 @@ static int task_main_proxy_1 ( { /* connected to the peer now */ proxy->peer_status |= PROXY_PEER_CONNECTED; - if (proxy->req) { - task->trigger.v[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; + /* need to read from the client-side as + * the content has not been received in full. */ + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_READ; } task->trigger.v[0].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; @@ -1523,7 +1555,7 @@ static int task_main_proxy_1 ( /* arrange to be called if the client side is writable. * it must write the injected response. */ - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->main = task_main_proxy_3; } else @@ -1546,16 +1578,13 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, QSE_ASSERT (proxy->flags & PROXY_RESOL_PEER_NAME); - task->trigger.flags &= ~QSE_HTTPD_TASK_TRIGGER_INACTIVE; - if (nwad) { /* resolved successfully */ proxy->flags &= ~PROXY_RESOL_PEER_NAME; proxy->peer.nwad = *nwad; -/*TODO: set port number .... */ -proxy->peer.nwad.u.in4.port = qse_hton16(80); + qse_setnwadport (&proxy->peer.nwad, qse_hton16(proxy->peer_port)); if (proxy->peer.local.type == QSE_NWAD_NX) proxy->peer.local.type = proxy->peer.nwad.type; @@ -1566,9 +1595,6 @@ proxy->peer.nwad.u.in4.port = qse_hton16(80); proxy->flags |= PROXY_INIT_FAILED | PROXY_UNKNOWN_PEER_NWAD; } -/* TODO: do something about this... */ -task->trigger.v[2].handle = proxy->client->handle; -task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; if (qse_httpd_activatetasktrigger (httpd, proxy->client, task) <= -1) { proxy->flags |= PROXY_INIT_FAILED; @@ -1600,11 +1626,6 @@ static int task_main_proxy ( return 1; } -/* TODO: do something abotu this */ -printf ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx\n"); -task->trigger.v[2].mask = 0; - - if (!(proxy->flags & PROXY_RAW)) { /* set up a http reader to read a response from the peer */ @@ -1641,23 +1662,25 @@ task->trigger.v[2].mask = 0; proxy->peer_status |= PROXY_PEER_OPEN; task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; task->trigger.v[0].handle = proxy->peer.handle; - task->trigger.v[2].handle = client->handle; + /*task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ;*/ + task->trigger.cmask = 0; if (n == 0) { -printf ("PEER 00000000000000000000\n"); /* peer not connected yet */ + /*task->trigger.cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ;*/ task->trigger.v[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->main = task_main_proxy_1; } else { /* peer connected already */ -printf ("PEER 111111111111111111111\n"); proxy->peer_status |= PROXY_PEER_CONNECTED; if (proxy->req) { - task->trigger.v[2].mask = QSE_HTTPD_TASK_TRIGGER_READ; + /* need to read from the client-side as + * the content has not been received in full. */ + task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ; } if (QSE_MBS_LEN(proxy->reqfwdbuf) > 0) @@ -1682,7 +1705,7 @@ printf ("PEER 111111111111111111111\n"); /* arrange to be called if the client side is writable. * it must write the injected response. */ - task->trigger.v[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->main = task_main_proxy_3; } else diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 244fbe66..d4b30f24 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -1979,7 +1979,10 @@ struct dns_ctx_t struct dns_req_t { - qse_uint16_t seq; +#define DNS_REQ_A_ERROR (1 << 0) +#define DNS_REQ_AAAA_ERROR (1 << 1) + int flags; + qse_uint16_t seqa, seqaaaa; qse_mchar_t* name; qse_uint8_t* dn; @@ -2274,20 +2277,22 @@ printf ("RECV....\n"); if (len >= QSE_SIZEOF(*hdr)) { - qse_uint16_t id, qdcount, ancount; + qse_uint16_t id, qdcount, ancount, xid; hdr = (dns_hdr_t*)buf; id = qse_ntoh16(hdr->id); qdcount = qse_ntoh16(hdr->qdcount); ancount = qse_ntoh16(hdr->ancount); + xid = (id >= QSE_COUNTOF(dc->reqs))? (id - QSE_COUNTOF(dc->reqs)): id; + printf ("%d qdcount %d ancount %d\n", id, qdcount, ancount); - if (id >= 0 && id < QSE_COUNTOF(dc->reqs) && hdr->qr && hdr->opcode == DNS_OPCODE_QUERY && qdcount >= 1) + if (id >= 0 && id < QSE_COUNTOF(dc->reqs) * 2 && hdr->qr && hdr->opcode == DNS_OPCODE_QUERY && qdcount >= 1) { qse_uint8_t* plptr = (qse_uint8_t*)(hdr + 1); qse_size_t pllen = len - QSE_SIZEOF(*hdr); qse_uint8_t i, dnlen; - dns_req_t* req = QSE_NULL; + dns_req_t* req = QSE_NULL, * preq = QSE_NULL; qse_size_t reclen; printf ("finding match req...\n"); @@ -2302,7 +2307,7 @@ printf ("1111111111111111111111\n"); if (!req) { dns_qdtrail_t* qdtrail = (dns_qdtrail_t*)(plptr + dnlen); - for (req = dc->reqs[id]; req; req = req->next) + for (preq = QSE_NULL, req = dc->reqs[xid]; req; preq = req, req = req->next) { printf ("checking req... %d %d\n",(int)req->dnlen, (int)dnlen); if (req->dnlen == dnlen && @@ -2322,13 +2327,13 @@ printf ("found matching req...\n"); } if (!req) goto done; - + if (hdr->rcode == DNS_RCODE_NOERROR && ancount > 0) { dns_antrail_t* antrail; qse_uint16_t qtype, anlen; -printf ("checking answers.... pllen => %d\n", pllen); +printf ("checking answers.... pllen => %d\n", (int)pllen); for (i = 0; i < ancount; i++) { if (pllen < 1) goto done; @@ -2340,7 +2345,6 @@ printf ("........... %d\n", dnlen); if (dnlen <= 0) goto done; /* invalid dn name */ } -printf ("111111111111111111111111111\n"); reclen = dnlen + QSE_SIZEOF(dns_antrail_t); if (pllen < reclen) goto done; @@ -2351,7 +2355,6 @@ printf ("111111111111111111111111111\n"); qtype = qse_ntoh16(antrail->qtype); anlen = qse_ntoh16(antrail->dlen); -printf ("XXXXXXXXXXXXXXXXXxx\n"); if (antrail->qclass == qse_hton16(DNS_QCLASS_IN)) { if (qtype == DNS_QTYPE_A && anlen == 4) @@ -2363,7 +2366,12 @@ printf ("XXXXXXXXXXXXXXXXXxx\n"); QSE_MEMCPY (&nwad.u.in4.addr, antrail + 1, 4); printf ("invoking resoll with ipv4 \n"); req->resol (httpd, req->name, &nwad, req->ctx); -/* TODO: delete req from dc ... */ + + /* delete the request from dc */ + if (preq) preq->next = req->next; + else dc->reqs[xid] = req->next; + qse_httpd_freemem (httpd, req); + goto done; } else if (qtype == DNS_QTYPE_AAAA || anlen == 16) @@ -2375,7 +2383,12 @@ printf ("invoking resoll with ipv4 \n"); QSE_MEMCPY (&nwad.u.in6.addr, antrail + 1, 16); printf ("invoking resoll with ipv6 \n"); req->resol (httpd, req->name, &nwad, req->ctx); -/* TODO:delete req from dc*/ + + /* delete the request from dc */ + if (preq) preq->next = req->next; + else dc->reqs[xid] = req->next; + qse_httpd_freemem (httpd, req); + goto done; } } @@ -2384,6 +2397,21 @@ printf ("invoking resoll with ipv6 \n"); pllen -= reclen; } } + else + { + if (id == req->seqa) req->flags |= DNS_REQ_A_ERROR; + else if (id == req->seqaaaa) req->flags |= DNS_REQ_AAAA_ERROR; + + if ((req->flags & (DNS_REQ_A_ERROR | DNS_REQ_AAAA_ERROR)) == (DNS_REQ_A_ERROR | DNS_REQ_AAAA_ERROR)) + { + req->resol (httpd, req->name, QSE_NULL, req->ctx); + + /* delete the request from dc */ + if (preq) preq->next = req->next; + else dc->reqs[xid] = req->next; + qse_httpd_freemem (httpd, req); + } + } /*req->resol (httpd, req->name, QSE_NULL, req->ctx);*//* TODO: handle this better */ } @@ -2413,7 +2441,8 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + (name_len + 1) + (name_len + 2)); if (req == QSE_NULL) return -1; - req->seq = seq; + req->seqa = seq; + req->seqaaaa = seq + QSE_COUNTOF(dc->reqs); /* this must not go beyond the qse_uint16_t max */ req->name = (qse_mchar_t*)(req + 1); req->dn = (qse_uint8_t*)(req->name + name_len + 1); @@ -2427,9 +2456,9 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t } req->resol = resol; req->ctx = ctx; - - req->qalen = init_dns_query (req->qa, QSE_SIZEOF(req->qa), name, DNS_QTYPE_A, seq); - req->qaaaalen = init_dns_query (req->qaaaa, QSE_SIZEOF(req->qaaaa), name, DNS_QTYPE_AAAA, seq); + + req->qalen = init_dns_query (req->qa, QSE_SIZEOF(req->qa), name, DNS_QTYPE_A, req->seqa); + req->qaaaalen = init_dns_query (req->qaaaa, QSE_SIZEOF(req->qaaaa), name, DNS_QTYPE_AAAA, req->seqaaaa); if (req->qalen <= -1 || req->qaaaalen <= -1) { qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); diff --git a/qse/lib/http/httpd.c b/qse/lib/http/httpd.c index 3997732e..b97994d4 100644 --- a/qse/lib/http/httpd.c +++ b/qse/lib/http/httpd.c @@ -727,34 +727,6 @@ qse_httpd_server_t* qse_httpd_getprevserver (qse_httpd_t* httpd, qse_httpd_serve /* ----------------------------------------------------------------------- */ -#if 0 -qse_httpd_dns_t* qse_httpd_attachdns (qse_httpd_t* httpd, qse_httpd_dns_dope_t* dns, qse_size_t xtnsize) -{ - qse_httpd_dns_t* dns; - - dns = qse_httpd_callocmem (httpd, QSE_SIZEOF(*dns) + xtnsize); - if (dns == QSE_NULL) return QSE_NULL; - - dns->type = QSE_HTTPD_SERVER; - /* copy the dns dope */ - dns->dope = *dope; - /* and correct some fields in case the dope contains invalid stuffs */ - dns->dope.flags &= ~QSE_HTTPD_SERVER_ACTIVE; - - /* chain the dns to the tail of the list */ - dns->prev = httpd->dns.list.tail; - dns->next = QSE_NULL; - if (httpd->dns.list.tail) - httpd->dns.list.tail->next = dns; - else - httpd->dns.list.head = dns; - httpd->dns.list.tail = dns; - httpd->dns.navail++; - - return dns; -} -#endif - static int activate_dns (qse_httpd_t* httpd) { if (httpd->opt.scb.dns.open (httpd, &httpd->dns) <= -1) return -1; @@ -767,7 +739,6 @@ static int activate_dns (qse_httpd_t* httpd) return -1; } - //httpd->dns = dns; return 0; } @@ -909,6 +880,19 @@ qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client- return 0; } +static void clear_trigger_mask_result (qse_httpd_task_t* task) +{ + qse_size_t i; + + task->trigger.cmask &= ~(QSE_HTTPD_TASK_TRIGGER_READABLE | + QSE_HTTPD_TASK_TRIGGER_WRITABLE); + for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) + { + task->trigger.v[i].mask &= ~(QSE_HTTPD_TASK_TRIGGER_READABLE | + QSE_HTTPD_TASK_TRIGGER_WRITABLE); + } +} + static int update_mux_for_current_task (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { qse_size_t i; @@ -917,11 +901,8 @@ static int update_mux_for_current_task (qse_httpd_t* httpd, qse_httpd_client_t* * that something can go wrong if the task handler plays * with the trigger field in an unexpected manner. */ - for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) - { - task->trigger.v[i].mask &= ~(QSE_HTTPD_TASK_TRIGGER_READABLE | - QSE_HTTPD_TASK_TRIGGER_WRITABLE); - } + + clear_trigger_mask_result (task); printf ("update_mux_for_current_task..............\n"); if (QSE_MEMCMP (&client->trigger, &task->trigger, QSE_SIZEOF(client->trigger)) != 0 || @@ -930,7 +911,6 @@ printf ("update_mux_for_current_task..............\n"); /* manipulate muxtiplexer settings if there are trigger changes */ int has_trigger = 0; - int expected_client_handle_mux_mask_from_trigger = 0; int expected_client_handle_mux_mask; int expected_client_handle_mux_status; @@ -996,15 +976,13 @@ printf ("ACTIVE TO ACTIVE....\n"); int expected_trigger_mux_mask = 0; int expected_trigger_mux_status = 0; + if (task->trigger.v[i].handle.i == client->handle.i) continue; /* TODO: no direct comparision */ + if (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ) { - if (task->trigger.v[i].handle.i != client->handle.i || !(client->status & CLIENT_MUTE)) - { - expected_trigger_mux_mask |= QSE_HTTPD_MUX_READ; - expected_trigger_mux_status |= CLIENT_TASK_TRIGGER_READ_IN_MUX(i); - } + expected_trigger_mux_mask |= QSE_HTTPD_MUX_READ; + expected_trigger_mux_status |= CLIENT_TASK_TRIGGER_READ_IN_MUX(i); } - if (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) { expected_trigger_mux_mask |= QSE_HTTPD_MUX_WRITE; @@ -1014,52 +992,52 @@ printf ("ACTIVE TO ACTIVE....\n"); if (expected_trigger_mux_mask) { has_trigger = 1; - - if (task->trigger.v[i].handle.i == client->handle.i) /* TODO: no direct comparsion */ - { - /* if the client handle is included in the trigger, - * delay its manipulation until the loop is over. - * instead, just remember what mask is requested */ - expected_client_handle_mux_mask_from_trigger |= expected_trigger_mux_mask; - } - else - { - if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, task->trigger.v[i].handle, expected_trigger_mux_mask, client) <= -1) - { - return -1; - } - client->status |= expected_trigger_mux_status; - } + if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, task->trigger.v[i].handle, expected_trigger_mux_mask, client) <= -1) return -1; + client->status |= expected_trigger_mux_status; } } - expected_client_handle_mux_mask = QSE_HTTPD_MUX_READ; - expected_client_handle_mux_status = CLIENT_HANDLE_READ_IN_MUX; + /* client-side handle is registered for both reading and + * writing when the task is executed for the first time. + * see update_mux_for_next_task() for this. + * + * starting from the second call, the client-side handle + * is registered for writing if it's explicitly requested. + * it's always registered for reading if not for CLIENT_MUTE. + * + * this means that QSE_HTTP_TASK_TRIGGER_READ set or clear + * in task->trigger.cmask is not honored. + */ - if (expected_client_handle_mux_mask_from_trigger) + expected_client_handle_mux_mask = 0; + expected_client_handle_mux_status = 0; + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE) { - expected_client_handle_mux_mask |= expected_client_handle_mux_mask_from_trigger; - if (expected_client_handle_mux_mask_from_trigger & QSE_HTTPD_MUX_WRITE) - expected_client_handle_mux_status |= CLIENT_HANDLE_READ_IN_MUX; - if (expected_client_handle_mux_mask_from_trigger & QSE_HTTPD_MUX_WRITE) - expected_client_handle_mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; - } - - if (!expected_client_handle_mux_status && !has_trigger) - { - /* if there is no trigger and the client handle is to be excluded - * from reading and writing, writing should be enabled. */ - expected_client_handle_mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; expected_client_handle_mux_mask |= QSE_HTTPD_MUX_WRITE; + expected_client_handle_mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; } if (client->status & CLIENT_MUTE) { - /* readking should be excluded from mux if the client-side has + /* reading should be excluded from mux if the client-side has * been closed */ client->status |= CLIENT_MUTE_DELETED; - expected_client_handle_mux_mask &= ~QSE_HTTPD_MUX_READ; - expected_client_handle_mux_status &= ~CLIENT_HANDLE_READ_IN_MUX; + } + else + { + if (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READ) + { + expected_client_handle_mux_mask |= QSE_HTTPD_MUX_READ; + expected_client_handle_mux_status |= CLIENT_HANDLE_READ_IN_MUX; + } + } + + if (!expected_client_handle_mux_mask && !has_trigger) + { + /* if there is no trigger and the client handle is to be excluded + * from reading and writing, writing should be enabled. */ + expected_client_handle_mux_mask |= QSE_HTTPD_MUX_WRITE; + expected_client_handle_mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; } if ((client->status & CLIENT_HANDLE_RW_IN_MUX) != expected_client_handle_mux_status) @@ -1067,9 +1045,11 @@ printf ("ACTIVE TO ACTIVE....\n"); httpd->opt.scb.mux.delhnd (httpd, httpd->mux, client->handle); client->status &= ~CLIENT_HANDLE_RW_IN_MUX; - QSE_ASSERT (expected_client_handle_mux_status & CLIENT_HANDLE_RW_IN_MUX); - if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, client->handle, expected_client_handle_mux_mask, client) <= -1) return -1; - client->status |= expected_client_handle_mux_status; + if (expected_client_handle_mux_mask) + { + if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, client->handle, expected_client_handle_mux_mask, client) <= -1) return -1; + client->status |= expected_client_handle_mux_status; + } } /* save the task trigger information */ @@ -1079,59 +1059,30 @@ printf ("ACTIVE TO ACTIVE....\n"); return 0; } -static int update_mux_for_new_task (qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - /* this task is the first task to activate. - * - * the client handle should be in mux for reading at this phase. - * a new task should be invoked at least once regardless of the - * data availablility(read) on the client side. arrange to invoke - * this task so long as the client-side handle is writable as well - * as when data is available for reading. */ - - int expected_mux_mask; - int expected_mux_status; - - QSE_ASSERT (client->status & CLIENT_HANDLE_RW_IN_MUX); - - expected_mux_mask = QSE_HTTPD_MUX_READ | QSE_HTTPD_MUX_WRITE; - expected_mux_status = CLIENT_HANDLE_RW_IN_MUX; - - if ((client->status & CLIENT_HANDLE_RW_IN_MUX) != expected_mux_status) - { - /* no updating is needed if the client handle is in mux for - * both reading and writing. if not, the handle must be - * re-registered for both reading and writing. */ - - httpd->opt.scb.mux.delhnd (httpd, httpd->mux, client->handle); - client->status &= ~CLIENT_HANDLE_RW_IN_MUX; - - #if 0 - printf ("MUX ADDHND CLIENT RW(ENTASK) %d\n", client->handle.i); - #endif - - QSE_ASSERT (expected_mux_status & CLIENT_HANDLE_RW_IN_MUX); - if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, client->handle, expected_mux_mask, client) <= -1) return -1; - client->status |= expected_mux_status; - } - - return 0; -} - static int update_mux_for_next_task (qse_httpd_t* httpd, qse_httpd_client_t* client) { + /* A new task should be invoked at least once regardless of the + * data availablility(read) on the client side. Arrange to invoke + * this task so long as the client-side handle is readable or writable. */ + + qse_httpd_task_t* task; int expected_mux_mask; int expected_mux_status; + int expected_trigger_cmask; +printf ("update_mux_for_next_task\n"); expected_mux_mask = QSE_HTTPD_MUX_READ; expected_mux_status = CLIENT_HANDLE_READ_IN_MUX; + expected_trigger_cmask = QSE_HTTPD_TASK_TRIGGER_READ; - if (client->task.head) + task = client->task.head; + if (task) { /* there is a pending task. arrange to trigger it as if it is * just entasked. */ expected_mux_mask |= QSE_HTTPD_MUX_WRITE; expected_mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; + expected_trigger_cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; if (client->status & CLIENT_MUTE) { @@ -1139,11 +1090,13 @@ static int update_mux_for_next_task (qse_httpd_t* httpd, qse_httpd_client_t* cli * from the side any more. so exclude reading */ expected_mux_mask &= ~QSE_HTTPD_MUX_READ; expected_mux_status &= ~CLIENT_HANDLE_READ_IN_MUX; + expected_trigger_cmask &= ~QSE_HTTPD_TASK_TRIGGER_READ; } } else { - /* there is no pending task to invoke */ + /* there is no pending task to invoke. */ + if (client->status & CLIENT_MUTE) { /* and this client has closed connection previously. @@ -1164,6 +1117,7 @@ static int update_mux_for_next_task (qse_httpd_t* httpd, qse_httpd_client_t* cli client->status |= expected_mux_status; } + if (task) task->trigger.cmask = expected_trigger_cmask; return 0; } @@ -1173,11 +1127,13 @@ static int invoke_client_task ( { qse_httpd_task_t* task; qse_size_t i; - int n, trigger_fired, client_handle_writable; + int n, trigger_fired; /* TODO: handle comparison callback ... */ if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */ { + /* keep reading from the client-side as long as + * it's readable. */ if (!(client->status & CLIENT_MUTE) && read_from_client (httpd, client) <= -1) { @@ -1189,45 +1145,59 @@ static int invoke_client_task ( } } - /* this client doesn't have any task */ task = client->task.head; if (task == QSE_NULL) { + /* this client doesn't have any task */ if (client->status & CLIENT_MUTE) { - /* handle this delayed client disconnection */ + /* handle the delayed client disconnection */ return -1; } - return 0; } trigger_fired = 0; - client_handle_writable = 0; - for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) + clear_trigger_mask_result (task); + if (handle.i == client->handle.i) /* TODO: no direct comparison */ { - task->trigger.v[i].mask &= ~(QSE_HTTPD_TASK_TRIGGER_READABLE | - QSE_HTTPD_TASK_TRIGGER_WRITABLE); - - if (task->trigger.v[i].handle.i == handle.i) /* TODO: no direct comparision */ + if (mask & QSE_HTTPD_MUX_READ) { - if (mask & QSE_HTTPD_MUX_READ) + /*QSE_ASSERT (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_READ);*/ + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_READABLE; + trigger_fired = 1; + } + if (mask & QSE_HTTPD_MUX_WRITE) + { + /*QSE_ASSERT (task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITE);*/ + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; + trigger_fired = 1; + } + } + else + { + for (i = 0; i < QSE_COUNTOF(task->trigger.v); i++) + { + if (task->trigger.v[i].handle.i == handle.i) /* TODO: no direct comparision */ { - QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ); - trigger_fired = 1; - task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE; - } - if (mask & QSE_HTTPD_MUX_WRITE) - { - QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE); - trigger_fired = 1; - task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; - if (handle.i == client->handle.i) client_handle_writable = 1; /* TODO: no direct comparison */ + if (mask & QSE_HTTPD_MUX_READ) + { + QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_READ); + task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_READABLE; + trigger_fired = 1; + } + if (mask & QSE_HTTPD_MUX_WRITE) + { + QSE_ASSERT (task->trigger.v[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE); + task->trigger.v[i].mask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; + trigger_fired = 1; + } } } } - if (trigger_fired && !client_handle_writable) + + if (trigger_fired && !(task->trigger.cmask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)) { /* the task is invoked for triggers. * check if the client handle is writable */ @@ -1240,6 +1210,10 @@ static int invoke_client_task ( * performing the actual task */ return 0; } + + /* WRITABLE can be set without WRITE as this is the result of + * the additional writability check. */ + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITABLE; } n = task->main (httpd, client, task); @@ -1253,7 +1227,7 @@ static int invoke_client_task ( /* update the multiplexer settings */ n = update_mux_for_next_task (httpd, client); - /* reset the task trigger */ + /* reset the task trigger remembered */ QSE_MEMSET (&client->trigger, 0, QSE_SIZEOF(client->trigger)); } else if (n > 0) @@ -1375,16 +1349,9 @@ qse_httpd_task_t* qse_httpd_entask ( } else if (new_task->prev == QSE_NULL) { - - /* this task is the first task to activate. - * - * the client handle should be in mux for reading at this phase. - * a new task should be invoked at least once regardless of the - * data availablility(read) on the client side. arrange to invoke - * this task so long as the client-side handle is writable as well - * as when data is available for reading. */ + /* this task is the first task to activate. */ - if (update_mux_for_new_task (httpd, client) <= -1) + if (update_mux_for_next_task (httpd, client) <= -1) { /*purge_client (httpd, client);*/ client->status |= CLIENT_BAD; @@ -1641,12 +1608,35 @@ printf ("dns_send.........................\n"); int qse_httpd_activatetasktrigger (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { + int x, org_cmask; + +printf ("activate ..$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$..\n"); + /* don't do anything if it's active */ + if (!(task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE)) return 0; + +printf ("activate reakly....\n"); + /* when task trigger is inactive, no handle are registered + * into mux. update_mux_for_current_task adds the client handle + * to mux for reading only if writing is not requested explicitly. + * if no data is available for reading, the task can never be + * called after activation. so let's request writing here. + */ + QSE_ASSERT (!(client->status & CLIENT_HANDLE_RW_IN_MUX)); + org_cmask = task->trigger.cmask; + task->trigger.cmask |= QSE_HTTPD_TASK_TRIGGER_WRITE; + task->trigger.flags &= ~QSE_HTTPD_TASK_TRIGGER_INACTIVE; - return update_mux_for_current_task (httpd, client, task); + + x = update_mux_for_current_task (httpd, client, task); + + task->trigger.cmask = org_cmask; + return x; } int qse_httpd_inactivatetasktrigger (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { + if (task->trigger.flags & QSE_HTTPD_TASK_TRIGGER_INACTIVE) return 0; + task->trigger.flags |= QSE_HTTPD_TASK_TRIGGER_INACTIVE; return update_mux_for_current_task (httpd, client, task); } diff --git a/qse/lib/http/httpd.h b/qse/lib/http/httpd.h index 2f69966a..3151ed39 100644 --- a/qse/lib/http/httpd.h +++ b/qse/lib/http/httpd.h @@ -143,6 +143,18 @@ qse_httpd_task_t* qse_httpd_entask_nomod ( int keepalive ); +int qse_httpd_activatetasktrigger ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* task +); + +int qse_httpd_inactivatetasktrigger ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* task +); + #ifdef __cplusplus } #endif