improved dns handling and added some code for url rewriting
This commit is contained in:
parent
4f4f42ae4f
commit
ae45071b5e
@ -1920,7 +1920,7 @@ static int httpd_main (int argc, qse_char_t* argv[])
|
||||
setup_signal_handlers ();
|
||||
|
||||
qse_httpd_getopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_LOGACT | QSE_HTTPD_DNSNOAAAA;
|
||||
trait |= QSE_HTTPD_CGIERRTONUL | QSE_HTTPD_LOGACT | QSE_HTTPD_DNSNOAAAA; /* TODO: make NOAAAA configurable */
|
||||
qse_httpd_setopt (httpd, QSE_HTTPD_TRAIT, &trait);
|
||||
|
||||
tmout.sec = 10;
|
||||
|
@ -34,6 +34,7 @@ typedef struct qse_httpd_mate_t qse_httpd_mate_t;
|
||||
typedef struct qse_httpd_server_t qse_httpd_server_t;
|
||||
typedef struct qse_httpd_client_t qse_httpd_client_t;
|
||||
typedef struct qse_httpd_dns_t qse_httpd_dns_t;
|
||||
typedef struct qse_httpd_urs_t qse_httpd_urs_t;
|
||||
|
||||
enum qse_httpd_errnum_t
|
||||
{
|
||||
@ -132,6 +133,13 @@ typedef void (*qse_httpd_resol_t) (
|
||||
void* ctx
|
||||
);
|
||||
|
||||
typedef void (*qse_httpd_rewrite_t) (
|
||||
qse_httpd_t* httpd,
|
||||
const qse_mchar_t* url,
|
||||
const qse_mchar_t* new_url,
|
||||
void* ctx
|
||||
);
|
||||
|
||||
typedef struct qse_httpd_scb_t qse_httpd_scb_t;
|
||||
struct qse_httpd_scb_t
|
||||
{
|
||||
@ -255,6 +263,14 @@ struct qse_httpd_scb_t
|
||||
int (*recv) (qse_httpd_t* httpd, qse_httpd_dns_t* dns);
|
||||
int (*send) (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t* name, qse_httpd_resol_t resol, void* ctx);
|
||||
} dns;
|
||||
|
||||
struct
|
||||
{
|
||||
int (*open) (qse_httpd_t* httpd, qse_httpd_urs_t* urs);
|
||||
void (*close) (qse_httpd_t* httpd, qse_httpd_urs_t* urs);
|
||||
int (*recv) (qse_httpd_t* httpd, qse_httpd_urs_t* urs);
|
||||
int (*send) (qse_httpd_t* httpd, qse_httpd_urs_t* urs, const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, void* ctx);
|
||||
} urs;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -387,7 +403,8 @@ enum qse_httpd_mate_type_t
|
||||
{
|
||||
QSE_HTTPD_SERVER,
|
||||
QSE_HTTPD_CLIENT,
|
||||
QSE_HTTPD_DNS
|
||||
QSE_HTTPD_DNS,
|
||||
QSE_HTTPD_URS
|
||||
};
|
||||
typedef enum qse_httpd_mate_type_t qse_httpd_mate_type_t;
|
||||
|
||||
@ -486,6 +503,17 @@ struct qse_httpd_dns_t
|
||||
qse_ubi_t handle;
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
struct qse_httpd_urs_t
|
||||
{
|
||||
/* PRIVATE == */
|
||||
QSE_HTTPD_MATE_HDR;
|
||||
|
||||
/* == PUBLIC == */
|
||||
qse_ubi_t handle;
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
@ -142,6 +142,7 @@ enum qse_httpd_serverstd_opt_t
|
||||
};
|
||||
typedef enum qse_httpd_serverstd_opt_t qse_httpd_serverstd_opt_t;
|
||||
|
||||
#define QSE_HTTPD_DNSSTD_DEFAULT_PORT 53
|
||||
#define QSE_HTTPD_DNSSTD_DEFAULT_TMOUT 3
|
||||
#define QSE_HTTPD_DNSSTD_DEFAULT_RESENDS 2
|
||||
#define QSE_HTTPD_DNSSTD_DEFAULT_CACHE_TTL 120
|
||||
@ -160,6 +161,18 @@ struct qse_httpd_dnsstd_t
|
||||
|
||||
typedef struct qse_httpd_dnsstd_t qse_httpd_dnsstd_t;
|
||||
|
||||
#define QSE_HTTPD_URSSTD_DEFAULT_PORT 94
|
||||
#define QSE_HTTPD_URSSTD_DEFAULT_TMOUT 10
|
||||
#define QSE_HTTPD_URSSTD_DEFAULT_RESENDS 0
|
||||
|
||||
struct qse_httpd_ursstd_t
|
||||
{
|
||||
qse_nwad_t nwad;
|
||||
qse_ntime_t tmout;
|
||||
qse_uint32_t resends;
|
||||
};
|
||||
typedef struct qse_httpd_ursstd_t qse_httpd_ursstd_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -543,6 +543,7 @@ struct httpd_xtn_t
|
||||
#endif
|
||||
qse_httpd_ecb_t ecb;
|
||||
qse_httpd_dnsstd_t dns;
|
||||
qse_httpd_ursstd_t urs;
|
||||
};
|
||||
|
||||
#if defined(HAVE_SSL)
|
||||
@ -2009,6 +2010,14 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
static qse_size_t hash_string (const qse_mchar_t *str)
|
||||
{
|
||||
qse_size_t h = 0;
|
||||
while (*str) h = ((h << 5) + h) ^ *str++;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
#define DNS_MAX_DN_LEN 255 /* full domain name length in binary form (i.e. 3xyz2eu0) */
|
||||
@ -2017,6 +2026,8 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
#define DNS_MIN_TTL 10
|
||||
#define DNS_MAX_TTL 120 /* TODO: make these configurable... */
|
||||
|
||||
#define DNS_SEQ_RANGE_SIZE ((QSE_TYPE_MAX(qse_uint16_t) / 2) - 2)
|
||||
|
||||
typedef struct dns_ctx_t dns_ctx_t;
|
||||
typedef struct dns_req_t dns_req_t;
|
||||
typedef struct dns_ans_t dns_ans_t;
|
||||
@ -2109,7 +2120,6 @@ struct dns_antrail_t
|
||||
};
|
||||
#include <qse/unpack.h>
|
||||
|
||||
|
||||
struct dns_ctx_t
|
||||
{
|
||||
qse_httpd_t* httpd;
|
||||
@ -2119,8 +2129,13 @@ struct dns_ctx_t
|
||||
int skadlen;
|
||||
|
||||
qse_uint16_t seq;
|
||||
dns_req_t* reqs[1024]; /* TOOD: choose the right size */
|
||||
dns_ans_t* anss[1024];
|
||||
dns_req_t* reqs[2048]; /* TOOD: choose the right size or make it configurable. must be < DNS_SEQ_RANGE_SIZE */
|
||||
dns_ans_t* anss[2048];
|
||||
qse_uint16_t req_count; /* the number of pending requests */
|
||||
|
||||
qse_uint16_t n_qcin; /* DNS_QCLASS_IN in network byte order */
|
||||
qse_uint16_t n_qta; /* DNS_QTYPE_A in network byte order */
|
||||
qse_uint16_t n_qtaaaa; /* DNS_QTYPE_AAAA in network byte order */
|
||||
};
|
||||
|
||||
struct dns_req_t
|
||||
@ -2148,11 +2163,18 @@ struct dns_req_t
|
||||
int resends;
|
||||
|
||||
dns_req_t* next;
|
||||
dns_req_t* prev;
|
||||
};
|
||||
|
||||
struct dns_ans_t
|
||||
{
|
||||
/* the name part must be the same as dns_req_t */
|
||||
qse_mchar_t* name;
|
||||
|
||||
/* the total size of data fields below must not be greater than
|
||||
* the total size of data fields of dns_req_t excluding name.
|
||||
* this condition is required for reusing the dns_req_t chunk
|
||||
* when caching an answer without allocating another chunk. */
|
||||
qse_nwad_t nwad;
|
||||
qse_int64_t age;
|
||||
qse_uint32_t ttl;
|
||||
@ -2270,6 +2292,9 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
|
||||
dc->httpd = httpd;
|
||||
dc->dns = dns;
|
||||
dc->n_qcin = qse_hton16(DNS_QCLASS_IN);
|
||||
dc->n_qta = qse_hton16(DNS_QTYPE_A);
|
||||
dc->n_qtaaaa = qse_hton16(DNS_QTYPE_AAAA);
|
||||
|
||||
/* TODO: add static cache entries from /etc/hosts */
|
||||
|
||||
@ -2314,7 +2339,7 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
}
|
||||
|
||||
if (qse_getnwadport(&nwad) == 0)
|
||||
qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DEFAULT_DNS_PORT));
|
||||
qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DNSSTD_DEFAULT_PORT));
|
||||
|
||||
dc->skadlen = qse_nwadtoskad (&nwad, &dc->skad);
|
||||
if (dc->skadlen <= -1)
|
||||
@ -2359,6 +2384,7 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
|
||||
dns->handle.i = fd;
|
||||
dns->ctx = dc;
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
@ -2392,9 +2418,12 @@ static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
dns_remove_tmr_tmout (dc->reqs[i]);
|
||||
qse_httpd_freemem (httpd, dc->reqs[i]);
|
||||
dc->reqs[i] = next_req;
|
||||
dc->req_count--;
|
||||
}
|
||||
}
|
||||
|
||||
QSE_ASSERT (dc->req_count == 0);
|
||||
|
||||
for (i = 0; i < QSE_COUNTOF(dc->anss); i++)
|
||||
{
|
||||
dns_ans_t* next_ans;
|
||||
@ -2406,25 +2435,11 @@ static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
closesocket (dns->handle.i);
|
||||
#elif defined(__OS2__)
|
||||
soclose (dns->handle.i);
|
||||
#elif defined(__DOS__)
|
||||
/* TODO: */
|
||||
#else
|
||||
QSE_CLOSE (dns->handle.i);
|
||||
#endif
|
||||
|
||||
close_socket (dns->handle.i);
|
||||
qse_httpd_freemem (httpd, dns->ctx);
|
||||
}
|
||||
|
||||
static unsigned long dns_hash_name (const qse_mchar_t *str)
|
||||
{
|
||||
qse_size_t h = 0;
|
||||
while (*str) h = ((h << 5) + h) ^ *str++;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* nwad, qse_uint32_t ttl)
|
||||
{
|
||||
@ -2441,6 +2456,10 @@ static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* n
|
||||
qse_gettime (&now);
|
||||
|
||||
ans = (dns_ans_t*)req; /* shadow the request with an answer */
|
||||
|
||||
/* reuse the data fields of the request except the name field.
|
||||
* from here downwards, the data fields of the request are invalid. */
|
||||
|
||||
if (nwad) ans->nwad = *nwad; /* positive */
|
||||
else ans->nwad.type = QSE_NWAD_NX; /* negative */
|
||||
ans->age = now.sec; /* the granularity of a second should be good enough */
|
||||
@ -2449,7 +2468,7 @@ static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* n
|
||||
else if (ttl > DNS_MAX_TTL) ttl = DNS_MAX_TTL;
|
||||
|
||||
ans->ttl = ttl;
|
||||
hid = dns_hash_name (req->name) % QSE_COUNTOF(dc->anss);
|
||||
hid = hash_string (req->name) % QSE_COUNTOF(dc->anss);
|
||||
|
||||
prv = QSE_NULL;
|
||||
cur = dc->anss[hid];
|
||||
@ -2477,7 +2496,7 @@ static dns_ans_t* dns_get_answer_from_cache (dns_ctx_t* dc, const qse_mchar_t* n
|
||||
qse_size_t hid;
|
||||
qse_ntime_t now;
|
||||
|
||||
hid = dns_hash_name (name) % QSE_COUNTOF(dc->anss);
|
||||
hid = hash_string(name) % QSE_COUNTOF(dc->anss);
|
||||
|
||||
qse_gettime (&now);
|
||||
|
||||
@ -2518,6 +2537,19 @@ static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
|
||||
qse_ssize_t len;
|
||||
dns_hdr_t* hdr;
|
||||
|
||||
qse_uint16_t id, qdcount, ancount, i;
|
||||
qse_uint8_t* plptr;
|
||||
qse_size_t pllen;
|
||||
dns_qdtrail_t* qdtrail;
|
||||
dns_antrail_t* antrail;
|
||||
qse_uint16_t anlen;
|
||||
|
||||
dns_req_t* req = QSE_NULL;
|
||||
qse_uint16_t xid = QSE_COUNTOF(dc->reqs);
|
||||
qse_nwad_t nwad;
|
||||
qse_nwad_t* resolved_nwad = QSE_NULL;
|
||||
int cache_ttl = 0;
|
||||
|
||||
printf ("DNS_RECV....\n");
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (httpd);
|
||||
@ -2527,69 +2559,80 @@ printf ("DNS_RECV....\n");
|
||||
|
||||
/* TODO: check if fromaddr matches the dc->skad... */
|
||||
|
||||
if (len >= QSE_SIZEOF(*hdr))
|
||||
{
|
||||
qse_uint16_t id, qdcount, ancount, xid;
|
||||
if (len < QSE_SIZEOF(*hdr)) goto done; /* packet too small */
|
||||
|
||||
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;
|
||||
|
||||
if (xid >= 0 && xid < QSE_COUNTOF(dc->reqs) && hdr->qr && hdr->opcode == DNS_OPCODE_QUERY && qdcount >= 1)
|
||||
if (!hdr->qr || hdr->opcode != DNS_OPCODE_QUERY || qdcount <= 0)
|
||||
{
|
||||
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, * preq = QSE_NULL;
|
||||
qse_size_t reclen;
|
||||
/* not a response to a query */
|
||||
goto done;
|
||||
}
|
||||
|
||||
ancount = qse_ntoh16(hdr->ancount);
|
||||
id = qse_ntoh16(hdr->id);
|
||||
xid = (id >= DNS_SEQ_RANGE_SIZE)? (id - DNS_SEQ_RANGE_SIZE): id;
|
||||
xid = xid % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
plptr = (qse_uint8_t*)(hdr + 1);
|
||||
pllen = len - QSE_SIZEOF(*hdr);
|
||||
|
||||
/* inspect the question section */
|
||||
for (i = 0; i < qdcount; i++)
|
||||
{
|
||||
qse_size_t reclen;
|
||||
qse_uint8_t dnlen;
|
||||
|
||||
dnlen = dn_length (plptr, pllen);
|
||||
if (dnlen <= 0) goto done; /* invalid dn name */
|
||||
|
||||
reclen = dnlen + QSE_SIZEOF(dns_qdtrail_t);
|
||||
if (pllen < reclen) goto done;
|
||||
if (pllen < reclen) goto done; /* weird packet */
|
||||
|
||||
if (!req)
|
||||
{
|
||||
dns_qdtrail_t* qdtrail = (dns_qdtrail_t*)(plptr + dnlen);
|
||||
for (preq = QSE_NULL, req = dc->reqs[xid]; req; preq = req, req = req->next)
|
||||
qdtrail = (dns_qdtrail_t*)(plptr + dnlen);
|
||||
|
||||
if (qdtrail->qclass == dc->n_qcin &&
|
||||
(qdtrail->qtype == dc->n_qta || qdtrail->qtype == dc->n_qtaaaa))
|
||||
{
|
||||
if (req->dnlen == dnlen &&
|
||||
QSE_MEMCMP (req->dn, plptr, req->dnlen) == 0 &&
|
||||
qdtrail->qclass == qse_hton16(DNS_QCLASS_IN) &&
|
||||
(qdtrail->qtype == qse_hton16(DNS_QTYPE_A) || qdtrail->qtype == qse_hton16(DNS_QTYPE_AAAA)))
|
||||
for (req = dc->reqs[xid]; req; req = req->next)
|
||||
{
|
||||
/* found a matching request */
|
||||
if ((id == req->seqa || id == req->seqaaaa) &&
|
||||
req->dnlen == dnlen && QSE_MEMCMP (req->dn, plptr, req->dnlen) == 0)
|
||||
{
|
||||
/* found a match. note that the test here is a bit loose
|
||||
* in that it doesn't really check if the original question
|
||||
* was A or AAAA. it is possible that it can process an AAAA answer
|
||||
* for an A question and vice versa. i don't care if someone
|
||||
* exploits this and sends a fake response*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plptr += reclen;
|
||||
pllen -= reclen;
|
||||
}
|
||||
|
||||
if (!req) goto done; /* no matching request for the question */
|
||||
|
||||
if (hdr->rcode == DNS_RCODE_NOERROR && ancount > 0)
|
||||
{
|
||||
dns_antrail_t* antrail;
|
||||
qse_uint16_t qtype, anlen;
|
||||
if (hdr->rcode != DNS_RCODE_NOERROR || ancount <= 0) goto done; /* no good answers */
|
||||
|
||||
/* inspect the answer section */
|
||||
for (i = 0; i < ancount; i++)
|
||||
{
|
||||
if (pllen < 1) goto done;
|
||||
qse_size_t reclen;
|
||||
qse_uint8_t dnlen;
|
||||
|
||||
if (pllen < 1) goto done; /* weird length */
|
||||
|
||||
if (*plptr > 63) dnlen = 2;
|
||||
else
|
||||
{
|
||||
dnlen = dn_length (plptr, pllen);
|
||||
if (dnlen <= 0) goto done; /* invalid dn name */
|
||||
if (dnlen <= 0) return 0; /* invalid dn name */
|
||||
}
|
||||
|
||||
reclen = dnlen + QSE_SIZEOF(dns_antrail_t);
|
||||
@ -2599,55 +2642,39 @@ printf ("DNS_RECV....\n");
|
||||
reclen += qse_ntoh16(antrail->dlen);
|
||||
if (pllen < reclen) goto done;
|
||||
|
||||
qtype = qse_ntoh16(antrail->qtype);
|
||||
anlen = qse_ntoh16(antrail->dlen);
|
||||
|
||||
if (qse_ntoh16(antrail->qclass) == DNS_QCLASS_IN)
|
||||
if (antrail->qclass == dc->n_qcin)
|
||||
{
|
||||
qse_nwad_t nwad;
|
||||
|
||||
nwad.type = QSE_NWAD_NX;
|
||||
|
||||
if (qtype == DNS_QTYPE_A && anlen == 4)
|
||||
if (antrail->qtype == dc->n_qta && anlen == 4)
|
||||
{
|
||||
QSE_MEMSET (&nwad, 0, QSE_SIZEOF(nwad));
|
||||
nwad.type = QSE_NWAD_IN4;
|
||||
QSE_MEMCPY (&nwad.u.in4.addr, antrail + 1, 4);
|
||||
printf ("invoking resoll with ipv4 \n");
|
||||
}
|
||||
else if (qtype == DNS_QTYPE_AAAA && anlen == 16)
|
||||
else if (antrail->qtype == dc->n_qtaaaa && anlen == 16)
|
||||
{
|
||||
QSE_MEMSET (&nwad, 0, QSE_SIZEOF(nwad));
|
||||
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)
|
||||
{
|
||||
int ttl;
|
||||
cache_ttl = httpd_xtn->dns.cache_ttl;
|
||||
if (cache_ttl > qse_ntoh32(antrail->ttl)) cache_ttl = qse_ntoh32(antrail->ttl);
|
||||
if (cache_ttl < httpd_xtn->dns.cache_minttl) cache_ttl = httpd_xtn->dns.cache_minttl;
|
||||
|
||||
dns_remove_tmr_tmout (req);
|
||||
req->resol (httpd, req->name, &nwad, req->ctx);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (preq) preq->next = req->next;
|
||||
else dc->reqs[xid] = req->next;
|
||||
|
||||
/*qse_httpd_freemem (httpd, req);*/
|
||||
ttl = httpd_xtn->dns.cache_ttl;
|
||||
if (ttl > qse_ntoh32(antrail->ttl)) ttl = qse_ntoh32(antrail->ttl);
|
||||
if (ttl < httpd_xtn->dns.cache_minttl) ttl = httpd_xtn->dns.cache_minttl;
|
||||
dns_cache_answer (dc, req, &nwad, ttl);
|
||||
|
||||
goto done;
|
||||
resolved_nwad = &nwad;
|
||||
goto resolved;
|
||||
}
|
||||
}
|
||||
|
||||
plptr += reclen;
|
||||
pllen -= reclen;
|
||||
}
|
||||
}
|
||||
|
||||
/* no good answer have been found */
|
||||
if (id == req->seqa) req->flags |= DNS_REQ_A_NX;
|
||||
@ -2656,24 +2683,35 @@ 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 */
|
||||
if (preq) preq->next = req->next;
|
||||
else dc->reqs[xid] = req->next;
|
||||
|
||||
/*qse_httpd_freemem (httpd, req);*/
|
||||
dns_cache_answer (dc, req, QSE_NULL, httpd_xtn->dns.cache_negttl);
|
||||
}
|
||||
}
|
||||
cache_ttl = httpd_xtn->dns.cache_negttl;
|
||||
resolved_nwad = QSE_NULL;
|
||||
goto resolved;
|
||||
}
|
||||
|
||||
done:
|
||||
/* is there anything to do here? */
|
||||
return 0;
|
||||
|
||||
resolved:
|
||||
QSE_ASSERT (req != QSE_NULL);
|
||||
QSE_ASSERT (xid >= 0 && xid < QSE_COUNTOF(dc->reqs));
|
||||
|
||||
dns_remove_tmr_tmout (req);
|
||||
req->resol (httpd, req->name, resolved_nwad, req->ctx);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
/* cache the negative answer instead of destroying it */
|
||||
dns_cache_answer (dc, req, resolved_nwad, cache_ttl);
|
||||
dc->req_count--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmr_dns_tmout_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx)
|
||||
static void tmr_dns_tmout_update (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx)
|
||||
{
|
||||
dns_req_t* req = (dns_req_t*)ctx;
|
||||
|
||||
@ -2687,34 +2725,36 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void*
|
||||
/* destory the unanswered request if timed out */
|
||||
|
||||
dns_req_t* req = (dns_req_t*)ctx;
|
||||
dns_req_t* preq, * xreq;
|
||||
dns_ctx_t* dc = req->dc;
|
||||
qse_uint16_t xid;
|
||||
|
||||
/* when this handler is called, the event should be removed from the timer */
|
||||
/* when this handler is called, the event must be removed from the timer */
|
||||
QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID);
|
||||
|
||||
/* TODO: resend?? + reschedule?? */
|
||||
/* ---------------------------------------------------------------
|
||||
* resend
|
||||
*---------------------------------------------------------------- */
|
||||
if (req->resends > 0)
|
||||
{
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
qse_tmr_event_t tmout_event;
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (req->dc->httpd);
|
||||
httpd_xtn = qse_httpd_getxtn (dc->httpd);
|
||||
|
||||
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;
|
||||
tmout_event.updater = tmr_dns_tmout_update;
|
||||
|
||||
if ((!(req->flags & DNS_REQ_A_NX) && req->qalen > 0 && sendto (req->dc->dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&req->dc->skad, req->dc->skadlen) != req->qalen) ||
|
||||
(!(req->flags & DNS_REQ_AAAA_NX) && req->qaaaalen > 0 && sendto (req->dc->dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&req->dc->skad, req->dc->skadlen) != req->qaaaalen))
|
||||
if ((!(req->flags & DNS_REQ_A_NX) && req->qalen > 0 && sendto (dc->dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qalen) ||
|
||||
(!(req->flags & DNS_REQ_AAAA_NX) && req->qaaaalen > 0 && sendto (dc->dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qaaaalen))
|
||||
{
|
||||
/* error. fall thru */
|
||||
/* resend failed. fall thru and destroy the request*/
|
||||
}
|
||||
else
|
||||
{
|
||||
req->tmr_tmout = qse_tmr_insert (req->dc->httpd->tmr, &tmout_event);
|
||||
req->tmr_tmout = qse_tmr_insert (dc->httpd->tmr, &tmout_event);
|
||||
if (req->tmr_tmout != QSE_TMR_INVALID)
|
||||
{
|
||||
req->resends--;
|
||||
@ -2723,27 +2763,27 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void*
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/* ---------------------------------------------------------------
|
||||
* dns timed out + no resend
|
||||
*---------------------------------------------------------------- */
|
||||
|
||||
/* this request that timed out must be inside the request list */
|
||||
QSE_ASSERT (req == xreq);
|
||||
/* it's safe to use req->seqa to find the hash index
|
||||
* because seqa is always set regardless of A or AAAA */
|
||||
xid = req->seqa % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (preq) preq->next = req->next;
|
||||
else req->dc->reqs[xid] = req->next;
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
/* dns timed out. report that name resolution failed */
|
||||
req->resol (req->dc->httpd, req->name, QSE_NULL, req->ctx);
|
||||
req->resol (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);
|
||||
qse_httpd_freemem (dc->httpd, req);
|
||||
|
||||
/* decrement the number of pending requests */
|
||||
dc->req_count--;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -2752,6 +2792,7 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
|
||||
qse_uint32_t seq;
|
||||
qse_uint16_t xid;
|
||||
dns_req_t* req;
|
||||
qse_size_t name_len;
|
||||
dns_ans_t* ans;
|
||||
@ -2760,6 +2801,7 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t
|
||||
httpd_xtn = qse_httpd_getxtn (httpd);
|
||||
|
||||
printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
|
||||
ans = dns_get_answer_from_cache (dc, name);
|
||||
if (ans)
|
||||
{
|
||||
@ -2767,10 +2809,18 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq = dc->seq;
|
||||
seq = (seq + 1) % QSE_COUNTOF(dc->reqs);
|
||||
if (dc->req_count >= QSE_COUNTOF(dc->reqs))
|
||||
{
|
||||
/* too many pending requests */
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
seq = ((qse_uint32_t)dc->seq + 1) % DNS_SEQ_RANGE_SIZE;
|
||||
dc->seq = seq;
|
||||
|
||||
xid = seq % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
name_len = qse_mbslen(name);
|
||||
|
||||
/* dn is at most as long as the source length + 2.
|
||||
@ -2779,8 +2829,10 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + (name_len + 1) + (name_len + 2));
|
||||
if (req == QSE_NULL) return -1;
|
||||
|
||||
/* seqa is between 0 and DNS_SEQ_RANGE_SIZE - 1 inclusive.
|
||||
* seqaaaa is between DNS_SEQ_RANGE_SIZE and DNS_SEQ_RANGE_SIZE * 2 - 1 inclusive. */
|
||||
req->seqa = seq;
|
||||
req->seqaaaa = seq + QSE_COUNTOF(dc->reqs); /* this must not go beyond the qse_uint16_t max */
|
||||
req->seqaaaa = seq + DNS_SEQ_RANGE_SIZE; /* this must not go beyond QSE_TYPE_MAX(qse_uint16_t) */
|
||||
req->name = (qse_mchar_t*)(req + 1);
|
||||
req->dn = (qse_uint8_t*)(req->name + name_len + 1);
|
||||
|
||||
@ -2816,12 +2868,12 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
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;
|
||||
tmout_event.updater = tmr_dns_tmout_update;
|
||||
|
||||
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_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
qse_httpd_freemem (httpd, req);
|
||||
return -1;
|
||||
}
|
||||
@ -2837,14 +2889,443 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* NOTE:
|
||||
* if the sequence number is repeated before it timed out or resolved,
|
||||
* the newer request gets chained together with the older one.
|
||||
* it may not be so easy to determine which request to match an incoming
|
||||
* response.
|
||||
*/
|
||||
req->dc = dc;
|
||||
req->next = dc->reqs[seq];
|
||||
dc->reqs[seq] = req;
|
||||
|
||||
/* link the request to the front of the chain */
|
||||
if (dc->reqs[xid]) dc->reqs[xid]->prev = req;
|
||||
req->next = dc->reqs[xid];
|
||||
dc->reqs[xid] = req;
|
||||
|
||||
/* increment the number of pending requests */
|
||||
dc->req_count++;
|
||||
|
||||
printf ("DNS REALLY SENT>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
#define URS_SEQ_RANGE_SIZE (QSE_TYPE_MAX(qse_uint16_t) - 2)
|
||||
#define URS_MAX_URL_LEN 50000
|
||||
|
||||
typedef struct urs_hdr_t urs_hdr_t;
|
||||
typedef struct urs_pkt_t urs_pkt_t;
|
||||
typedef struct urs_ctx_t urs_ctx_t;
|
||||
typedef struct urs_req_t urs_req_t;
|
||||
|
||||
#include <qse/pack1.h>
|
||||
struct urs_hdr_t
|
||||
{
|
||||
qse_uint16_t seq; /* in network-byte order */
|
||||
qse_uint16_t rcode; /* response code */
|
||||
qse_uint32_t qusum;/* checksum of url in the request */
|
||||
qse_uint16_t len; /* url length in network-byte order */
|
||||
};
|
||||
|
||||
struct urs_pkt_t
|
||||
{
|
||||
struct urs_hdr_t hdr;
|
||||
qse_mchar_t url[1];
|
||||
};
|
||||
#include <qse/unpack.h>
|
||||
|
||||
struct urs_ctx_t
|
||||
{
|
||||
qse_httpd_t* httpd;
|
||||
qse_httpd_urs_t* urs;
|
||||
|
||||
qse_skad_t skad;
|
||||
int skadlen;
|
||||
|
||||
qse_uint16_t seq; /* TODO: change to uint32_t??? */
|
||||
urs_req_t* reqs[1024]; /* TOOD: choose the right size */
|
||||
qse_uint16_t req_count;
|
||||
|
||||
qse_uint8_t rcvbuf[URS_MAX_URL_LEN + QSE_SIZEOF(urs_pkt_t)];
|
||||
};
|
||||
|
||||
struct urs_req_t
|
||||
{
|
||||
qse_uint16_t seq; /* in host-byte order */
|
||||
qse_uint32_t pktlen;
|
||||
urs_pkt_t* pkt;
|
||||
|
||||
qse_httpd_rewrite_t rewrite;
|
||||
void* ctx;
|
||||
|
||||
urs_ctx_t* dc;
|
||||
qse_size_t tmr_tmout;
|
||||
int resends;
|
||||
|
||||
urs_req_t* prev;
|
||||
urs_req_t* next;
|
||||
};
|
||||
|
||||
#if 0
|
||||
int init_urs_query (qse_uint8_t* buf, qse_size_t len, const qse_mchar_t* name, qse_uint16_t seq)
|
||||
{
|
||||
urs_hdr_t* hdr;
|
||||
urs_qdtrail_t* qdtrail;
|
||||
qse_size_t x;
|
||||
|
||||
if (len < QSE_SIZEOF(*hdr)) return -1;
|
||||
|
||||
QSE_MEMSET (buf, 0, len);
|
||||
hdr = (urs_hdr_t*)buf;
|
||||
hdr->id = qse_hton16(seq);
|
||||
hdr->opcode = URS_OPCODE_QUERY;
|
||||
hdr->rd = 1; /* recursion desired*/
|
||||
hdr->qdcount = qse_hton16(1); /* 1 question */
|
||||
|
||||
len -= QSE_SIZEOF(*hdr);
|
||||
|
||||
x = to_dn (name, (qse_uint8_t*)(hdr + 1), len);
|
||||
if (x <= 0) return -1;
|
||||
len -= x;
|
||||
|
||||
if (len < QSE_SIZEOF(*qdtrail)) return -1;
|
||||
qdtrail = (urs_qdtrail_t*)((qse_uint8_t*)(hdr + 1) + x);
|
||||
|
||||
qdtrail->qtype = qse_hton16(qtype);
|
||||
qdtrail->qclass = qse_hton16(URS_QCLASS_IN);
|
||||
return QSE_SIZEOF(*hdr) + x + QSE_SIZEOF(*qdtrail);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int urs_open (qse_httpd_t* httpd, qse_httpd_urs_t* urs)
|
||||
{
|
||||
#if defined(__DOS__)
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||
return -1;
|
||||
#else
|
||||
sock_t fd = SOCK_INIT;
|
||||
int flag;
|
||||
qse_nwad_t nwad;
|
||||
urs_ctx_t* dc;
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (httpd);
|
||||
|
||||
dc = (urs_ctx_t*) qse_httpd_callocmem (httpd, QSE_SIZEOF(urs_ctx_t));
|
||||
if (dc == NULL) goto oops;
|
||||
|
||||
dc->httpd = httpd;
|
||||
dc->urs = urs;
|
||||
|
||||
nwad = httpd_xtn->urs.nwad;
|
||||
if (nwad.type == QSE_NWAD_NX)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (qse_getnwadport(&nwad) == 0)
|
||||
qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_URSSTD_DEFAULT_PORT));
|
||||
|
||||
dc->skadlen = qse_nwadtoskad (&nwad, &dc->skad);
|
||||
if (dc->skadlen <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
qse_httpd_act_t msg;
|
||||
qse_size_t pos;
|
||||
msg.code = QSE_HTTPD_CATCH_MDBGMSG;
|
||||
pos = qse_mbsxcpy (msg.u.mdbgmsg, QSE_COUNTOF(msg.u.mdbgmsg), "ursserver set to ");
|
||||
qse_nwadtombs (&nwad, &msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, QSE_NWADTOMBS_ALL);
|
||||
httpd->opt.rcb.logact (httpd, &msg);
|
||||
}
|
||||
|
||||
fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (!is_valid_socket(fd))
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* TODO: set socket send/recv buffer size. it's needed as urs may be long */
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
flag = fcntl (fd, F_GETFD);
|
||||
if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
#if defined(SO_REUSEADDR)
|
||||
flag = 1;
|
||||
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void*)&flag, QSE_SIZEOF(flag));
|
||||
#endif
|
||||
|
||||
#if defined(SO_REUSEPORT)
|
||||
flag = 1;
|
||||
setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag));
|
||||
#endif
|
||||
|
||||
if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops;
|
||||
|
||||
urs->handle.i = fd;
|
||||
urs->ctx = dc;
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (is_valid_socket(fd)) close_socket (fd);
|
||||
if (dc) qse_httpd_freemem (httpd, dc);
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void urs_remove_tmr_tmout (urs_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 urs_close (qse_httpd_t* httpd, qse_httpd_urs_t* urs)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
qse_size_t i;
|
||||
|
||||
for (i = 0; i < QSE_COUNTOF(dc->reqs); i++)
|
||||
{
|
||||
urs_req_t* next_req;
|
||||
while (dc->reqs[i])
|
||||
{
|
||||
next_req = dc->reqs[i]->next;
|
||||
urs_remove_tmr_tmout (dc->reqs[i]);
|
||||
qse_httpd_freemem (httpd, dc->reqs[i]);
|
||||
dc->reqs[i] = next_req;
|
||||
dc->req_count--;
|
||||
}
|
||||
}
|
||||
|
||||
QSE_ASSERT (dc->req_count == 0);
|
||||
|
||||
close_socket (urs->handle.i);
|
||||
qse_httpd_freemem (httpd, urs->ctx);
|
||||
}
|
||||
|
||||
|
||||
static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
|
||||
qse_skad_t fromaddr;
|
||||
socklen_t fromlen;
|
||||
|
||||
qse_uint16_t xid;
|
||||
qse_ssize_t len;
|
||||
urs_pkt_t* pkt;
|
||||
urs_req_t* req;
|
||||
|
||||
printf ("URS_RECV....\n");
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (httpd);
|
||||
|
||||
fromlen = QSE_SIZEOF(fromaddr);
|
||||
len = recvfrom (urs->handle.i, dc->rcvbuf, QSE_SIZEOF(dc->rcvbuf) - 1, 0, (struct sockaddr*)&fromaddr, &fromlen);
|
||||
|
||||
/* TODO: check if fromaddr matches the dc->skad... */
|
||||
|
||||
pkt = (urs_pkt_t*)dc->rcvbuf;
|
||||
if (len >= QSE_SIZEOF(pkt->hdr) && len >= QSE_SIZEOF(pkt->hdr) + qse_ntoh16(pkt->hdr.len))
|
||||
{
|
||||
xid = qse_ntoh16(pkt->hdr.seq) % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
for (req = dc->reqs[xid]; req; req = req->next)
|
||||
{
|
||||
if (req->pkt->hdr.seq == pkt->hdr.seq && req->pkt->hdr.qusum == pkt->hdr.qusum)
|
||||
{
|
||||
pkt->url[qse_ntoh16(pkt->hdr.len)] = QSE_MT('\0');
|
||||
|
||||
urs_remove_tmr_tmout (req);
|
||||
req->rewrite (httpd, req->pkt->url, pkt->url, req->ctx);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
qse_httpd_freemem (httpd, req);
|
||||
dc->req_count--;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmr_urs_tmout_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx)
|
||||
{
|
||||
urs_req_t* req = (urs_req_t*)ctx;
|
||||
|
||||
printf (">>tmr_urs_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_urs_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx)
|
||||
{
|
||||
/* destory the unanswered request if timed out */
|
||||
|
||||
urs_req_t* req = (urs_req_t*)ctx;
|
||||
urs_ctx_t* dc = req->dc;
|
||||
qse_uint16_t xid;
|
||||
|
||||
/* when this handler is called, the event should be removed from the timer */
|
||||
QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* resend
|
||||
*---------------------------------------------------------------- */
|
||||
if (req->resends > 0)
|
||||
{
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
qse_tmr_event_t tmout_event;
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (dc->httpd);
|
||||
|
||||
qse_gettime (&tmout_event.when);
|
||||
qse_addtime (&tmout_event.when, &httpd_xtn->urs.tmout, &tmout_event.when);
|
||||
tmout_event.ctx = req;
|
||||
tmout_event.handler = tmr_urs_tmout_handle;
|
||||
tmout_event.updater = tmr_urs_tmout_updated;
|
||||
|
||||
if (sendto (dc->urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen)
|
||||
{
|
||||
/* error. fall thru */
|
||||
}
|
||||
else
|
||||
{
|
||||
req->tmr_tmout = qse_tmr_insert (dc->httpd->tmr, &tmout_event);
|
||||
if (req->tmr_tmout != QSE_TMR_INVALID)
|
||||
{
|
||||
req->resends--;
|
||||
return; /* resend ok */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf ("urs timed out....\n");
|
||||
/* ---------------------------------------------------------------
|
||||
* timed out + no resend
|
||||
*---------------------------------------------------------------- */
|
||||
xid = req->seq % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
/* urs timed out. report that name resolution failed */
|
||||
req->rewrite (dc->httpd, req->pkt->url, QSE_NULL, req->ctx);
|
||||
|
||||
/* i don't cache the items that have timed out */
|
||||
qse_httpd_freemem (dc->httpd, req);
|
||||
dc->req_count--;
|
||||
}
|
||||
|
||||
static int urs_send (qse_httpd_t* httpd, qse_httpd_urs_t* urs, const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, void* ctx)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
httpd_xtn_t* httpd_xtn;
|
||||
|
||||
qse_uint16_t xid;
|
||||
qse_uint32_t seq;
|
||||
urs_req_t* req;
|
||||
qse_size_t url_len;
|
||||
qse_tmr_event_t tmout_event;
|
||||
|
||||
httpd_xtn = qse_httpd_getxtn (httpd);
|
||||
|
||||
printf ("URS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
|
||||
if (dc->req_count >= QSE_COUNTOF(dc->reqs))
|
||||
{
|
||||
/* too many pending requests */
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
url_len = qse_mbslen(url);
|
||||
if (url_len > URS_MAX_URL_LEN) /* TODO: change the limit */
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
seq = ((qse_uint32_t)dc->seq + 1) % URS_SEQ_RANGE_SIZE;
|
||||
dc->seq = seq;
|
||||
|
||||
xid = seq % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + url_len + QSE_SIZEOF(urs_pkt_t));
|
||||
if (req == QSE_NULL) return -1;
|
||||
|
||||
req->seq = seq;
|
||||
req->pkt = (urs_pkt_t*)(req + 1);
|
||||
req->pkt->hdr.seq = qse_hton16(seq);
|
||||
req->pkt->hdr.len = qse_hton16(url_len);
|
||||
req->pkt->hdr.qusum = hash_string (url);
|
||||
qse_mbscpy (req->pkt->url, url);
|
||||
req->pktlen = QSE_SIZEOF(urs_pkt_t) + url_len - 1; /* to exclude the terminating '\0' */
|
||||
|
||||
req->rewrite = rewrite;
|
||||
req->ctx = ctx;
|
||||
|
||||
qse_gettime (&tmout_event.when);
|
||||
qse_addtime (&tmout_event.when, &httpd_xtn->urs.tmout, &tmout_event.when);
|
||||
tmout_event.ctx = req;
|
||||
tmout_event.handler = tmr_urs_tmout_handle;
|
||||
tmout_event.updater = tmr_urs_tmout_updated;
|
||||
|
||||
req->tmr_tmout = qse_tmr_insert (httpd->tmr, &tmout_event);
|
||||
if (req->tmr_tmout == QSE_TMR_INVALID)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
qse_httpd_freemem (httpd, req);
|
||||
return -1;
|
||||
}
|
||||
req->resends = httpd_xtn->urs.resends;
|
||||
|
||||
if (sendto (urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen)
|
||||
{
|
||||
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;
|
||||
|
||||
/* link the request to the front of the chain */
|
||||
if (dc->reqs[xid]) dc->reqs[xid]->prev = req;
|
||||
req->next = dc->reqs[xid];
|
||||
dc->reqs[xid] = req;
|
||||
|
||||
/* increment the number of pending requests */
|
||||
dc->req_count++;
|
||||
|
||||
printf ("URS REALLY SENT>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
#if 0
|
||||
static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
|
||||
@ -3164,7 +3645,13 @@ static qse_httpd_scb_t httpd_system_callbacks =
|
||||
{ dns_open,
|
||||
dns_close,
|
||||
dns_recv,
|
||||
dns_send }
|
||||
dns_send },
|
||||
|
||||
/* urs */
|
||||
{ urs_open,
|
||||
urs_close,
|
||||
urs_recv,
|
||||
urs_send }
|
||||
};
|
||||
|
||||
static qse_httpd_rcb_t httpd_request_callbacks =
|
||||
|
@ -382,7 +382,7 @@ 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 tmr_idle_update (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, 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)
|
||||
@ -420,7 +420,7 @@ static qse_httpd_client_t* new_client (qse_httpd_t* httpd, qse_httpd_client_t* t
|
||||
qse_addtime (&idle_event.when, &httpd->opt.idle_limit, &idle_event.when);
|
||||
idle_event.ctx = client;
|
||||
idle_event.handler = tmr_idle_handle;
|
||||
idle_event.updater = tmr_idle_updated;
|
||||
idle_event.updater = tmr_idle_update;
|
||||
|
||||
client->tmr_idle = qse_tmr_insert (httpd->tmr, &idle_event);
|
||||
if (client->tmr_idle == QSE_TMR_INVALID)
|
||||
@ -618,7 +618,7 @@ 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)
|
||||
static void tmr_idle_update (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx)
|
||||
{
|
||||
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);
|
||||
@ -650,7 +650,7 @@ printf ("client is idle purging....\n");
|
||||
qse_addtime (&idle_event.when, &client->server->httpd->opt.idle_limit, &idle_event.when);
|
||||
idle_event.ctx = client;
|
||||
idle_event.handler = tmr_idle_handle;
|
||||
idle_event.updater = tmr_idle_updated;
|
||||
idle_event.updater = tmr_idle_update;
|
||||
|
||||
/* the timer must have been deleted when this callback is called. */
|
||||
QSE_ASSERT (client->tmr_idle == QSE_TMR_INVALID);
|
||||
@ -833,6 +833,29 @@ static void deactivate_dns (qse_httpd_t* httpd)
|
||||
httpd->opt.scb.mux.delhnd (httpd, httpd->mux, httpd->dns.handle);
|
||||
httpd->opt.scb.dns.close (httpd, &httpd->dns);
|
||||
}
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int activate_urs (qse_httpd_t* httpd)
|
||||
{
|
||||
/* TODO: how to disable URS??? */
|
||||
if (httpd->opt.scb.urs.open (httpd, &httpd->urs) <= -1) return -1;
|
||||
|
||||
httpd->urs.type = QSE_HTTPD_URS;
|
||||
|
||||
if (httpd->opt.scb.mux.addhnd (httpd, httpd->mux, httpd->urs.handle, QSE_HTTPD_MUX_READ, &httpd->urs) <= -1)
|
||||
{
|
||||
httpd->opt.scb.urs.close (httpd, &httpd->urs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void deactivate_urs (qse_httpd_t* httpd)
|
||||
{
|
||||
httpd->opt.scb.mux.delhnd (httpd, httpd->mux, httpd->urs.handle);
|
||||
httpd->opt.scb.urs.close (httpd, &httpd->urs);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
@ -1384,6 +1407,16 @@ static int perform_dns (qse_httpd_t* httpd, void* mux, qse_ubi_t handle, int mas
|
||||
return httpd->opt.scb.dns.recv (httpd, dns);
|
||||
}
|
||||
|
||||
static int perform_urs (qse_httpd_t* httpd, void* mux, qse_ubi_t handle, int mask, void* cbarg)
|
||||
{
|
||||
qse_httpd_urs_t* urs = (qse_httpd_urs_t*)cbarg;
|
||||
|
||||
QSE_ASSERT (mask & QSE_HTTPD_MUX_READ);
|
||||
QSE_ASSERT (&httpd->urs == urs);
|
||||
|
||||
return httpd->opt.scb.urs.recv (httpd, urs);
|
||||
}
|
||||
|
||||
static void purge_bad_clients (qse_httpd_t* httpd)
|
||||
{
|
||||
qse_httpd_client_t* client;
|
||||
@ -1450,6 +1483,9 @@ static int dispatch_mux (
|
||||
|
||||
case QSE_HTTPD_DNS:
|
||||
return perform_dns (httpd, mux, handle, mask, cbarg);
|
||||
|
||||
case QSE_HTTPD_URS:
|
||||
return perform_urs (httpd, mux, handle, mask, cbarg);
|
||||
}
|
||||
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
@ -1501,6 +1537,18 @@ int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
}
|
||||
else httpd->dnsactive = 1;
|
||||
|
||||
if (activate_urs (httpd) <= -1)
|
||||
{
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
|
||||
{
|
||||
qse_httpd_act_t msg;
|
||||
msg.code = QSE_HTTPD_CATCH_MWARNMSG;
|
||||
qse_mbscpy (msg.u.mwarnmsg, QSE_MT("cannot activate urs"));
|
||||
httpd->opt.rcb.logact (httpd, &msg);
|
||||
}
|
||||
}
|
||||
else httpd->ursactive = 1;
|
||||
|
||||
if (activate_servers (httpd) <= -1)
|
||||
{
|
||||
if (httpd->dnsactive) deactivate_dns (httpd);
|
||||
@ -1544,6 +1592,7 @@ int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
purge_client_list (httpd);
|
||||
deactivate_servers (httpd);
|
||||
|
||||
if (httpd->ursactive) deactivate_urs (httpd);
|
||||
if (httpd->dnsactive) deactivate_dns (httpd);
|
||||
|
||||
httpd->opt.scb.mux.close (httpd, httpd->mux);
|
||||
@ -1684,7 +1733,7 @@ printf ("DNS_SEND.........................\n");
|
||||
#if 0
|
||||
int qse_httpd_rewriteurl (qse_httpd_t* httpd, const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, void* ctx)
|
||||
{
|
||||
return httpd->opt.scb.url.send (httpd, &httpd->dns, name, resol, ctx);
|
||||
return httpd->opt.scb.urs.send (httpd, &httpd->dns, name, resol, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#define QSE_HTTPD_DEFAULT_PORT 80
|
||||
#define QSE_HTTPD_DEFAULT_SECURE_PORT 443
|
||||
#define QSE_HTTPD_DEFAULT_DNS_PORT 53
|
||||
|
||||
struct qse_httpd_t
|
||||
{
|
||||
qse_mmgr_t* mmgr;
|
||||
@ -47,6 +47,7 @@ struct qse_httpd_t
|
||||
int stopreq: 1;
|
||||
int impedereq: 1;
|
||||
int dnsactive: 1;
|
||||
int ursactive: 1;
|
||||
|
||||
qse_mchar_t sname[128]; /* server name for the server header */
|
||||
qse_mchar_t gtbuf[10][64]; /* GMT time buffers */
|
||||
@ -81,6 +82,7 @@ struct qse_httpd_t
|
||||
|
||||
void* mux;
|
||||
qse_httpd_dns_t dns;
|
||||
qse_httpd_urs_t urs;
|
||||
};
|
||||
|
||||
/* qse_httpd_real_task_t is a private type to hide some private fields
|
||||
|
Loading…
Reference in New Issue
Block a user