diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c index 3dbfc5e6..7ea28f1a 100644 --- a/qse/cmd/http/httpd.c +++ b/qse/cmd/http/httpd.c @@ -2008,7 +2008,7 @@ int qse_main (int argc, qse_achar_t* argv[]) #endif #if defined(_WIN32) - WSACleanup (); + WSACleanup (); #endif return ret; diff --git a/qse/include/qse/cmn/tmr.h b/qse/include/qse/cmn/tmr.h index 7be152c5..a5bc2fb3 100644 --- a/qse/include/qse/cmn/tmr.h +++ b/qse/include/qse/cmn/tmr.h @@ -57,6 +57,9 @@ struct qse_tmr_event_t #define QSE_TMR_INVALID ((qse_size_t)-1) +#define QSE_TMR_SIZE(tmr) ((tmr)->size) +#define QSE_TMR_CAPA(tmr) ((tmr)->capa); + #ifdef __cplusplus extern "C" { #endif diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index ac1a1cc6..7acb2058 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -423,7 +423,6 @@ struct qse_httpd_client_t qse_ntime_t last_active; qse_size_t tmr_idle; - qse_size_t tmr_dns; qse_httpd_client_t* prev; qse_httpd_client_t* next; diff --git a/qse/include/qse/http/stdhttpd.h b/qse/include/qse/http/stdhttpd.h index 56ecba55..9ca640d2 100644 --- a/qse/include/qse/http/stdhttpd.h +++ b/qse/include/qse/http/stdhttpd.h @@ -142,6 +142,16 @@ enum qse_httpd_serverstd_opt_t }; typedef enum qse_httpd_serverstd_opt_t qse_httpd_serverstd_opt_t; +#define QSE_HTTPD_DNSSTD_DEFAULT_TMOUT 10 + +struct qse_httpd_dnsstd_t +{ + qse_nwad_t nwad; + qse_ntime_t tmout; +}; + +typedef struct qse_httpd_dnsstd_t qse_httpd_dnsstd_t; + #if defined(__cplusplus) extern "C" { #endif @@ -196,8 +206,8 @@ QSE_EXPORT void* qse_httpd_getserverstdxtn ( ); QSE_EXPORT int qse_httpd_loopstd ( - qse_httpd_t* httpd, - const qse_nwad_t* dnsnwad + qse_httpd_t* httpd, + const qse_httpd_dnsstd_t* dns ); #ifdef __cplusplus diff --git a/qse/include/qse/macros.h b/qse/include/qse/macros.h index 83e96378..2b5ebb8b 100644 --- a/qse/include/qse/macros.h +++ b/qse/include/qse/macros.h @@ -287,32 +287,6 @@ # define QSE_STRUCT_FIELD(id,value) value #endif -#ifdef NDEBUG -# define QSE_ASSERT(expr) ((void)0) -# define QSE_ASSERTX(expr,desc) ((void)0) -#else -# ifdef __cplusplus - extern "C" { -# endif - QSE_EXPORT void qse_assert_failed ( - const qse_char_t* expr, const qse_char_t* desc, - const qse_char_t* file, qse_size_t line); -# ifdef __cplusplus - } -# endif - -# define QSE_ASSERT(expr) (void)((expr) || \ - (qse_assert_failed (QSE_T(#expr), QSE_NULL, QSE_T(__FILE__), __LINE__), 0)) -# define QSE_ASSERTX(expr,desc) (void)((expr) || \ - (qse_assert_failed (QSE_T(#expr), QSE_T(desc), QSE_T(__FILE__), __LINE__), 0)) -#endif - -#ifdef __cplusplus -# define QSE_BEGIN_NAMESPACE(x) namespace x { -# define QSE_END_NAMESPACE(x) } -# define QSE_BEGIN_NAMESPACE2(x,y) namespace x { namespace y { -# define QSE_END_NAMESPACE2(y,x) }} -#endif /** * The QSE_XTN() macro is a convenience macro to retrieve the pointer to @@ -321,4 +295,39 @@ */ #define QSE_XTN(obj) ((void*)(obj + 1)) +/* ---------------------------------------------------------------------- + * ASSERTION + * ---------------------------------------------------------------------- */ + +#ifdef NDEBUG +# define QSE_ASSERT(expr) ((void)0) +# define QSE_ASSERTX(expr,desc) ((void)0) +#else + +# define QSE_ASSERT(expr) (void)((expr) || \ + (qse_assert_failed (QSE_T(#expr), QSE_NULL, QSE_T(__FILE__), __LINE__), 0)) +# define QSE_ASSERTX(expr,desc) (void)((expr) || \ + (qse_assert_failed (QSE_T(#expr), QSE_T(desc), QSE_T(__FILE__), __LINE__), 0)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif +QSE_EXPORT void qse_assert_failed ( + const qse_char_t* expr, const qse_char_t* desc, + const qse_char_t* file, qse_size_t line); +#ifdef __cplusplus +} +#endif + +/* ---------------------------------------------------------------------- + * C++ NAMESPACE + * ---------------------------------------------------------------------- */ +#ifdef __cplusplus +# define QSE_BEGIN_NAMESPACE(x) namespace x { +# define QSE_END_NAMESPACE(x) } +# define QSE_BEGIN_NAMESPACE2(x,y) namespace x { namespace y { +# define QSE_END_NAMESPACE2(y,x) }} +#endif + #endif diff --git a/qse/lib/cmn/assert.c b/qse/lib/cmn/assert.c index 587cba08..628470f4 100644 --- a/qse/lib/cmn/assert.c +++ b/qse/lib/cmn/assert.c @@ -20,9 +20,6 @@ #include #include - -#if !defined(NDEBUG) - #include #include "mem.h" @@ -253,5 +250,3 @@ done: #endif } -#endif - diff --git a/qse/lib/cmn/tmr.c b/qse/lib/cmn/tmr.c index 12d6c266..d38511da 100644 --- a/qse/lib/cmn/tmr.c +++ b/qse/lib/cmn/tmr.c @@ -85,9 +85,11 @@ void* qse_tmr_getxtn (qse_tmr_t* tmr) void qse_tmr_clear (qse_tmr_t* tmr) { tmr->size = 0; + +/* TOOD: use tmr_remove for notification.... */ } -static qse_size_t sift_up (qse_tmr_t* tmr, qse_size_t index) +static qse_size_t sift_up (qse_tmr_t* tmr, qse_size_t index, int notify) { qse_size_t parent; @@ -109,15 +111,18 @@ static qse_size_t sift_up (qse_tmr_t* tmr, qse_size_t index) } while (index > 0 && YOUNGER_THAN(&item, &tmr->event[parent])); + /* we send no notification if the item is added with qse_tmr_insert() + * or updated with qse_tmr_update(). the caller of the funnctions must + * reply on the return value. */ tmr->event[index] = item; - if (index != old_index) + if (notify && index != old_index) tmr->event[index].updater (tmr, old_index, index, tmr->event[index].ctx); } return index; } -static qse_size_t sift_down (qse_tmr_t* tmr, qse_size_t index) +static qse_size_t sift_down (qse_tmr_t* tmr, qse_size_t index, int notify) { qse_size_t base = tmr->size / 2; @@ -152,7 +157,7 @@ static qse_size_t sift_down (qse_tmr_t* tmr, qse_size_t index) while (index < base); tmr->event[index] = item; - if (index != old_index) + if (notify && index != old_index) tmr->event[index].updater (tmr, old_index, index, tmr->event[index].ctx); } @@ -165,22 +170,24 @@ void qse_tmr_remove (qse_tmr_t* tmr, qse_size_t index) QSE_ASSERT (index < tmr->size); +printf ("tmr_remove.....>>>>>>>>>>>>size=>%d index=>%d\n", (int)tmr->size, (int)index); item = tmr->event[index]; tmr->event[index].updater (tmr, index, QSE_TMR_INVALID, tmr->event[index].ctx); + tmr->size = tmr->size - 1; - if (tmr->size > 0) + if (tmr->size > 0 && index != tmr->size) { tmr->event[index] = tmr->event[tmr->size]; tmr->event[index].updater (tmr, tmr->size, index, tmr->event[index].ctx); - YOUNGER_THAN(&tmr->event[index], &item)? sift_up(tmr, index): sift_down(tmr, index); + YOUNGER_THAN(&tmr->event[index], &item)? sift_up(tmr, index, 1): sift_down(tmr, index, 1); } } - qse_size_t qse_tmr_insert (qse_tmr_t* tmr, const qse_tmr_event_t* event) { qse_size_t index = tmr->size; +printf ("tmr_insert ......size => %d\n", (int)tmr->size); if (index >= tmr->capa) { qse_tmr_event_t* tmp; @@ -196,7 +203,7 @@ qse_size_t qse_tmr_insert (qse_tmr_t* tmr, const qse_tmr_event_t* event) tmr->size = tmr->size + 1; tmr->event[index] = *event; - return sift_up (tmr, index); + return sift_up (tmr, index, 0); } qse_size_t qse_tmr_update (qse_tmr_t* tmr, qse_size_t index, const qse_tmr_event_t* event) @@ -205,7 +212,7 @@ qse_size_t qse_tmr_update (qse_tmr_t* tmr, qse_size_t index, const qse_tmr_event item = tmr->event[index]; tmr->event[index] = *event; - return YOUNGER_THAN(event, &item)? sift_up (tmr, index): sift_down (tmr, index); + return YOUNGER_THAN(event, &item)? sift_up (tmr, index, 0): sift_down (tmr, index, 0); } qse_size_t qse_tmr_fire (qse_tmr_t* tmr, const qse_ntime_t* tm) @@ -245,5 +252,7 @@ int qse_tmr_gettmout (qse_tmr_t* tmr, const qse_ntime_t* tm, qse_ntime_t* tmout) qse_subtime (&tmr->event[0].when, &now, tmout); if (tmout->sec < 0) qse_cleartime (tmout); + + return 0; } diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index a1fb7492..8741ef25 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -542,7 +542,7 @@ struct httpd_xtn_t SSL_CTX* ssl_ctx; #endif qse_httpd_ecb_t ecb; - qse_nwad_t dnsnwad; + qse_httpd_dnsstd_t dns; }; #if defined(HAVE_SSL) @@ -612,9 +612,10 @@ static void fini_xtn_ssl (httpd_xtn_t* xtn) static void cleanup_standard_httpd (qse_httpd_t* httpd) { -#if defined(HAVE_SSL) httpd_xtn_t* xtn; xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); + +#if defined(HAVE_SSL) if (xtn->ssl_ctx) fini_xtn_ssl (xtn); #endif } @@ -656,6 +657,7 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd) typedef int sock_t; # define SOCK_INIT -1 #endif + #if !defined(HAVE_SOCKLEN_T) typedef int socklen_t; #endif @@ -2140,6 +2142,9 @@ struct dns_req_t int qalen; int qaaaalen; + dns_ctx_t* dc; + qse_size_t tmr_tmout; + dns_req_t* next; }; @@ -2265,7 +2270,7 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) /* TODO: add static cache entries from /etc/hosts */ - nwad = httpd_xtn->dnsnwad; + nwad = httpd_xtn->dns.nwad; if (nwad.type == QSE_NWAD_NX) { qse_sio_t* sio; @@ -2361,6 +2366,15 @@ oops: #endif } +static void dns_remove_tmr_tmout (dns_req_t* req) +{ + if (req->tmr_tmout != QSE_TMR_INVALID) + { + qse_tmr_remove (req->dc->httpd->tmr, req->tmr_tmout); + req->tmr_tmout = QSE_TMR_INVALID; + } +} + static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns) { dns_ctx_t* dc = (dns_ctx_t*)dns->ctx; @@ -2372,6 +2386,7 @@ static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns) while (dc->reqs[i]) { next_req = dc->reqs[i]->next; + dns_remove_tmr_tmout (dc->reqs[i]); qse_httpd_freemem (httpd, dc->reqs[i]); dc->reqs[i] = next_req; } @@ -2520,7 +2535,7 @@ printf ("DNS_RECV....\n"); 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) * 2 && hdr->qr && hdr->opcode == DNS_OPCODE_QUERY && qdcount >= 1) + if (xid >= 0 && xid < QSE_COUNTOF(dc->reqs) && 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); @@ -2603,11 +2618,11 @@ printf ("invoking resoll with ipv4 \n"); nwad.type = QSE_NWAD_IN6; QSE_MEMCPY (&nwad.u.in6.addr, antrail + 1, 16); printf ("invoking resoll with ipv6 \n"); - } if (nwad.type != QSE_NWAD_NX) { + dns_remove_tmr_tmout (req); req->resol (httpd, req->name, &nwad, req->ctx); /* detach the request off dc->reqs */ @@ -2626,7 +2641,6 @@ printf ("invoking resoll with ipv6 \n"); } } - /* no good answer have been found */ if (id == req->seqa) req->flags |= DNS_REQ_A_NX; else if (id == req->seqaaaa) req->flags |= DNS_REQ_AAAA_NX; @@ -2634,7 +2648,7 @@ printf ("invoking resoll with ipv6 \n"); if ((req->flags & (DNS_REQ_A_NX | DNS_REQ_AAAA_NX)) == (DNS_REQ_A_NX | DNS_REQ_AAAA_NX)) { /* both ipv4 and ipv6 address are unresolvable */ - + dns_remove_tmr_tmout (req); req->resol (httpd, req->name, QSE_NULL, req->ctx); /* detach the request off dc->reqs */ @@ -2645,21 +2659,65 @@ printf ("invoking resoll with ipv6 \n"); dns_cache_answer (dc, req, QSE_NULL, DNS_MIN_TTL); } } - } done: return 0; } +static void tmr_dns_tmout_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx) +{ + dns_req_t* req = (dns_req_t*)ctx; + +printf (">>tmr_dns_tmout_updated %d %d\n", (int)req->tmr_tmout, (int)old_index); + QSE_ASSERT (req->tmr_tmout == old_index); + req->tmr_tmout = new_index; +} + +static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx) +{ + /* destory the unanswered request if timed out */ + dns_req_t* req = (dns_req_t*)ctx; + dns_req_t* preq, * xreq; + qse_uint16_t xid; + +printf ("dns timed out....\n"); + xid = req->seqa; + QSE_ASSERT (xid >= 0 && QSE_COUNTOF(req->dc->reqs)); +/* TODO: doubly linked list??? speed up ??? */ + for (preq = QSE_NULL, xreq = req->dc->reqs[xid]; xreq; preq = xreq, xreq = xreq->next) + { + if (req == xreq) break; + } + + QSE_ASSERT (req == xreq); + /* detach the request off dc->reqs */ + if (preq) preq->next = req->next; + else req->dc->reqs[xid] = req->next; + + QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID); + + /* dns timed out. report that name resolution failed */ + req->resol (req->dc->httpd, req->name, QSE_NULL, req->ctx); + + /* i don't cache the items that have timed out */ + qse_httpd_freemem (req->dc->httpd, req); + +} + static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t* name, qse_httpd_resol_t resol, void* ctx) { - qse_uint32_t seq; dns_ctx_t* dc = (dns_ctx_t*)dns->ctx; + httpd_xtn_t* httpd_xtn = qse_httpd_getxtn (httpd); + + qse_uint32_t seq; dns_req_t* req; qse_size_t name_len; dns_ans_t* ans; + qse_tmr_event_t tmout_event; + +printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); ans = dns_get_answer_from_cache (dc, name); if (ans) { @@ -2712,17 +2770,37 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t return -1; } - if ((req->qalen > 0 && sendto (dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qalen) || - (req->qaaaalen > 0 && sendto (dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qaaaalen)) + qse_gettime (&tmout_event.when); + qse_addtime (&tmout_event.when, &httpd_xtn->dns.tmout, &tmout_event.when); + tmout_event.ctx = req; + tmout_event.handler = tmr_dns_tmout_handle; + tmout_event.updater = tmr_dns_tmout_updated; + +printf ("ABOUT TO REGISTER TMR_TMOUT...\n"); + req->tmr_tmout = qse_tmr_insert (httpd->tmr, &tmout_event); + if (req->tmr_tmout == QSE_TMR_INVALID) { qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); qse_httpd_freemem (httpd, req); return -1; } +printf ("???? initial tmr_tmout => %d\n", (int)req->tmr_tmout); + if ((req->qalen > 0 && sendto (dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qalen) || + (req->qaaaalen > 0 && sendto (dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qaaaalen)) + { + qse_tmr_remove (httpd->tmr, req->tmr_tmout); + req->tmr_tmout = QSE_TMR_INVALID; + qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); + qse_httpd_freemem (httpd, req); + return -1; + } + + req->dc = dc; req->next = dc->reqs[seq]; dc->reqs[seq] = req; +printf ("DNS REALLY SENT>>>>>>>>>>>>>>>>>>>>>>>\n"); return 0; } @@ -3980,14 +4058,19 @@ void* qse_httpd_getserverstdxtn (qse_httpd_t* httpd, qse_httpd_server_t* server) /* ------------------------------------------------------------------- */ -int qse_httpd_loopstd (qse_httpd_t* httpd, const qse_nwad_t* dnsnwad) +int qse_httpd_loopstd (qse_httpd_t* httpd, const qse_httpd_dnsstd_t* dns) { httpd_xtn_t* httpd_xtn = qse_httpd_getxtn (httpd); - if (dnsnwad) - httpd_xtn->dnsnwad = *dnsnwad; + if (dns) + { + httpd_xtn->dns = *dns; + } else - httpd_xtn->dnsnwad.type = QSE_NWAD_NX; + { + httpd_xtn->dns.nwad.type = QSE_NWAD_NX; + httpd_xtn->dns.tmout.sec = QSE_HTTPD_DNSSTD_DEFAULT_TMOUT; + } return qse_httpd_loop (httpd); } diff --git a/qse/lib/http/httpd.c b/qse/lib/http/httpd.c index 4681dcf9..383e3a05 100644 --- a/qse/lib/http/httpd.c +++ b/qse/lib/http/httpd.c @@ -383,10 +383,11 @@ static qse_htrd_recbs_t htrd_recbs = /* ----------------------------------------------------------------------- */ static void tmr_idle_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx); -static void check_if_client_is_idle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx); +static void tmr_idle_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx); static void mark_bad_client (qse_httpd_client_t* client) { + /* you can call this function multiple times */ if (!(client->status & CLIENT_BAD)) { client->status |= CLIENT_BAD; @@ -418,11 +419,9 @@ static qse_httpd_client_t* new_client (qse_httpd_t* httpd, qse_httpd_client_t* t qse_gettime (&idle_event.when); qse_addtime (&idle_event.when, &httpd->opt.idle_limit, &idle_event.when); idle_event.ctx = client; - idle_event.handler = check_if_client_is_idle; + idle_event.handler = tmr_idle_handle; idle_event.updater = tmr_idle_updated; -/*TODO: */ client->tmr_dns = QSE_TMR_INVALID; - client->tmr_idle = qse_tmr_insert (httpd->tmr, &idle_event); if (client->tmr_idle == QSE_TMR_INVALID) { @@ -488,12 +487,6 @@ qse_printf (QSE_T("Debug: CLOSING SOCKET %d\n"), client->handle.i); client->tmr_idle = QSE_TMR_INVALID; } - if (client->tmr_dns != QSE_TMR_INVALID) - { - qse_tmr_remove (httpd->tmr, client->tmr_dns); - client->tmr_dns = QSE_TMR_INVALID; - } - qse_httpd_freemem (httpd, client); } @@ -627,13 +620,13 @@ printf ("MUX ADDHND CLIENT READ %d\n", client->handle.i); static void tmr_idle_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx) { -printf ("tmr_idle updated %d %d\n", (int)old_index, (int)new_index); qse_httpd_client_t* client = (qse_httpd_client_t*)ctx; +printf ("tmr_idle updated old_index %d new_index %d tmr_idle %d\n", (int)old_index, (int)new_index, (int)client->tmr_idle); QSE_ASSERT (client->tmr_idle == old_index); client->tmr_idle = new_index; } -static void check_if_client_is_idle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx) +static void tmr_idle_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx) { qse_httpd_client_t* client = (qse_httpd_client_t*)ctx; @@ -656,7 +649,7 @@ printf ("client is idle purging....\n"); idle_event.when = *now; qse_addtime (&idle_event.when, &client->server->httpd->opt.idle_limit, &idle_event.when); idle_event.ctx = client; - idle_event.handler = check_if_client_is_idle; + idle_event.handler = tmr_idle_handle; idle_event.updater = tmr_idle_updated; /* the timer must have been deleted when this callback is called. */ @@ -1474,6 +1467,8 @@ int qse_httpd_loop (qse_httpd_t* httpd) QSE_ASSERTX (httpd->client.list.head == QSE_NULL, "No client should exist when this loop is started"); + QSE_ASSERT (QSE_TMR_SIZE(httpd->tmr) == 0); + if (httpd->server.list.head == QSE_NULL) { httpd->errnum = QSE_HTTPD_EINVAL; @@ -1552,7 +1547,8 @@ int qse_httpd_loop (qse_httpd_t* httpd) if (httpd->dnsactive) deactivate_dns (httpd); httpd->opt.scb.mux.close (httpd, httpd->mux); - qse_tmr_clear (httpd->tmr); + + QSE_ASSERT (QSE_TMR_SIZE(httpd->tmr) == 0); return xret; }