handled dns timeout in httpd

This commit is contained in:
hyung-hwan 2014-08-05 09:55:00 +00:00
parent f1a77eb311
commit ccb6ddcefd
9 changed files with 177 additions and 73 deletions

View File

@ -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

View File

@ -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;

View File

@ -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
@ -197,7 +207,7 @@ QSE_EXPORT void* qse_httpd_getserverstdxtn (
QSE_EXPORT int qse_httpd_loopstd (
qse_httpd_t* httpd,
const qse_nwad_t* dnsnwad
const qse_httpd_dnsstd_t* dns
);
#ifdef __cplusplus

View File

@ -287,10 +287,29 @@
# define QSE_STRUCT_FIELD(id,value) value
#endif
/**
* The QSE_XTN() macro is a convenience macro to retrieve the pointer to
* extension space located at the end of an object. The type of the object
* should be known in advance for it to work properly.
*/
#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
@ -301,12 +320,9 @@
}
#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
/* ----------------------------------------------------------------------
* C++ NAMESPACE
* ---------------------------------------------------------------------- */
#ifdef __cplusplus
# define QSE_BEGIN_NAMESPACE(x) namespace x {
# define QSE_END_NAMESPACE(x) }
@ -314,11 +330,4 @@
# define QSE_END_NAMESPACE2(y,x) }}
#endif
/**
* The QSE_XTN() macro is a convenience macro to retrieve the pointer to
* extension space located at the end of an object. The type of the object
* should be known in advance for it to work properly.
*/
#define QSE_XTN(obj) ((void*)(obj + 1))
#endif

View File

@ -20,9 +20,6 @@
#include <qse/types.h>
#include <qse/macros.h>
#if !defined(NDEBUG)
#include <qse/cmn/sio.h>
#include "mem.h"
@ -253,5 +250,3 @@ done:
#endif
}
#endif

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}