diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c
index edb6ae93..2c230cb1 100644
--- a/qse/cmd/http/httpd.c
+++ b/qse/cmd/http/httpd.c
@@ -1937,7 +1937,13 @@ static int httpd_main (int argc, qse_char_t* argv[])
if (g_debug) rcb.logact = logact_httpd; /* i don't remember old logging handler */
qse_httpd_setopt (httpd, QSE_HTTPD_RCB, &rcb);
- ret = qse_httpd_loopstd (httpd, QSE_NULL);
+/* TODO: read from configuration... */
+{
+qse_httpd_ursstd_t urs;
+qse_memset (&urs, 0, QSE_SIZEOF(urs));
+qse_mbstonwad ("[::1]:97", &urs.nwad);
+ ret = qse_httpd_loopstd (httpd, QSE_NULL, &urs);
+}
restore_signal_handlers ();
g_httpd = QSE_NULL;
diff --git a/qse/include/qse/cmn/tmr.h b/qse/include/qse/cmn/tmr.h
index a5bc2fb3..59519a28 100644
--- a/qse/include/qse/cmn/tmr.h
+++ b/qse/include/qse/cmn/tmr.h
@@ -25,6 +25,7 @@
typedef struct qse_tmr_t qse_tmr_t;
typedef struct qse_tmr_event_t qse_tmr_event_t;
+typedef qse_size_t qse_tmr_index_t;
typedef void (*qse_tmr_handler_t) (
qse_tmr_t* tmr,
@@ -33,10 +34,10 @@ typedef void (*qse_tmr_handler_t) (
);
typedef void (*qse_tmr_updater_t) (
- qse_tmr_t* tmr,
- qse_size_t old_index,
- qse_size_t new_index,
- void* ctx
+ qse_tmr_t* tmr,
+ qse_tmr_index_t old_index,
+ qse_tmr_index_t new_index,
+ void* ctx
);
struct qse_tmr_t
@@ -55,7 +56,7 @@ struct qse_tmr_event_t
qse_tmr_updater_t updater;
};
-#define QSE_TMR_INVALID ((qse_size_t)-1)
+#define QSE_TMR_INVALID_INDEX ((qse_size_t)-1)
#define QSE_TMR_SIZE(tmr) ((tmr)->size)
#define QSE_TMR_CAPA(tmr) ((tmr)->capa);
@@ -99,23 +100,23 @@ QSE_EXPORT void qse_tmr_clear (
/**
* The qse_tmr_insert() function schedules a new event.
*
- * \return #QSE_TMR_INVALID on failure, valid index on success.
+ * \return #QSE_TMR_INVALID_INDEX on failure, valid index on success.
*/
-QSE_EXPORT qse_size_t qse_tmr_insert (
+QSE_EXPORT qse_tmr_index_t qse_tmr_insert (
qse_tmr_t* tmr,
const qse_tmr_event_t* event
);
QSE_EXPORT qse_size_t qse_tmr_update (
qse_tmr_t* tmr,
- qse_size_t index,
+ qse_tmr_index_t index,
const qse_tmr_event_t* event
);
QSE_EXPORT void qse_tmr_remove (
- qse_tmr_t* tmr,
- qse_size_t index
+ qse_tmr_t* tmr,
+ qse_tmr_index_t index
);
QSE_EXPORT qse_size_t qse_tmr_fire (
diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h
index ab27f268..8030ce14 100644
--- a/qse/include/qse/http/httpd.h
+++ b/qse/include/qse/http/httpd.h
@@ -59,6 +59,7 @@ enum qse_httpd_errnum_t
QSE_HTTPD_EDISCON, /* client disconnnected */
QSE_HTTPD_EBADREQ, /* bad request */
QSE_HTTPD_ENODNS, /* dns service not activated */
+ QSE_HTTPD_ENOURS, /* urs service not activated */
QSE_HTTPD_ETASK
};
typedef enum qse_httpd_errnum_t qse_httpd_errnum_t;
@@ -261,7 +262,8 @@ struct qse_httpd_scb_t
int (*open) (qse_httpd_t* httpd, qse_httpd_dns_t* dns);
void (*close) (qse_httpd_t* httpd, qse_httpd_dns_t* dns);
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);
+ 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
@@ -269,7 +271,8 @@ struct qse_httpd_scb_t
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);
+ int (*send) (qse_httpd_t* httpd, qse_httpd_urs_t* urs,
+ const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, void* ctx);
} urs;
};
@@ -439,7 +442,7 @@ struct qse_httpd_client_t
qse_httpd_task_trigger_t trigger;
qse_ntime_t last_active;
- qse_size_t tmr_idle;
+ qse_tmr_index_t tmr_idle;
qse_httpd_client_t* prev;
qse_httpd_client_t* next;
@@ -552,14 +555,18 @@ struct qse_httpd_rsrc_cgi_t
enum qse_httpd_rsrc_proxy_flag_t
{
- QSE_HTTPD_RSRC_PROXY_RAW = (1 << 0),
- QSE_HTTPD_RSRC_PROXY_DST_STR = (1 << 1)
+ QSE_HTTPD_RSRC_PROXY_RAW = (1 << 0),
+ QSE_HTTPD_RSRC_PROXY_DST_STR = (1 << 1),
+ QSE_HTTPD_RSRC_PROXY_TRANSPARENT = (1 << 2),
+ QSE_HTTPD_RSRC_PROXY_URS = (1 << 3) /* url rewriting enabled */
};
typedef struct qse_httpd_rsrc_proxy_t qse_httpd_rsrc_proxy_t;
struct qse_httpd_rsrc_proxy_t
{
int flags; /* bitwise-ORed of qse_httpd_rsrc_proxy_flag_t enumerators */
+
+ const qse_mchar_t* host; /* host name part that were in the original request url */
union
{
qse_nwad_t nwad;
@@ -990,7 +997,6 @@ QSE_EXPORT qse_mchar_t* qse_httpd_escapehtml (
const qse_mchar_t* str
);
-
QSE_EXPORT int qse_httpd_resolname (
qse_httpd_t* httpd,
const qse_mchar_t* name,
@@ -998,6 +1004,13 @@ QSE_EXPORT int qse_httpd_resolname (
void* ctx
);
+QSE_EXPORT int qse_httpd_rewriteurl (
+ qse_httpd_t* ttpd,
+ const qse_mchar_t* url,
+ qse_httpd_rewrite_t rewrite,
+ void* ctx
+);
+
#ifdef __cplusplus
}
diff --git a/qse/include/qse/http/stdhttpd.h b/qse/include/qse/http/stdhttpd.h
index fd63ab9e..10892ee4 100644
--- a/qse/include/qse/http/stdhttpd.h
+++ b/qse/include/qse/http/stdhttpd.h
@@ -228,7 +228,8 @@ QSE_EXPORT void* qse_httpd_getserverstdxtn (
QSE_EXPORT int qse_httpd_loopstd (
qse_httpd_t* httpd,
- const qse_httpd_dnsstd_t* dns
+ const qse_httpd_dnsstd_t* dns,
+ const qse_httpd_ursstd_t* urs
);
#ifdef __cplusplus
diff --git a/qse/lib/cmn/tmr.c b/qse/lib/cmn/tmr.c
index 9c265164..175ad5a9 100644
--- a/qse/lib/cmn/tmr.c
+++ b/qse/lib/cmn/tmr.c
@@ -55,20 +55,25 @@ void qse_tmr_close (qse_tmr_t* tmr)
int qse_tmr_init (qse_tmr_t* tmr, qse_mmgr_t* mmgr, qse_size_t capa)
{
+ qse_tmr_event_t* tmp;
+
QSE_MEMSET (tmr, 0, QSE_SIZEOF(*tmr));
if (capa <= 0) capa = 1;
- tmr->event = QSE_MMGR_ALLOC (mmgr, capa * QSE_SIZEOF(*tmr->event));
- if (tmr->event == QSE_NULL) return -1;
+ tmp = QSE_MMGR_ALLOC (mmgr, capa * QSE_SIZEOF(*tmp));
+ if (tmp == QSE_NULL) return -1;
tmr->mmgr = mmgr;
tmr->capa = capa;
+ tmr->event = tmp;
+
return 0;
}
void qse_tmr_fini (qse_tmr_t* tmr)
{
+ qse_tmr_clear (tmr);
if (tmr->event) QSE_MMGR_FREE (tmr->mmgr, tmr->event);
}
@@ -84,12 +89,10 @@ 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.... */
+ while (tmr->size > 0) qse_tmr_remove (tmr, 0);
}
-static qse_size_t sift_up (qse_tmr_t* tmr, qse_size_t index, int notify)
+static qse_tmr_index_t sift_up (qse_tmr_t* tmr, qse_tmr_index_t index, int notify)
{
qse_size_t parent;
@@ -122,7 +125,7 @@ static qse_size_t sift_up (qse_tmr_t* tmr, qse_size_t index, int notify)
return index;
}
-static qse_size_t sift_down (qse_tmr_t* tmr, qse_size_t index, int notify)
+static qse_tmr_index_t sift_down (qse_tmr_t* tmr, qse_tmr_index_t index, int notify)
{
qse_size_t base = tmr->size / 2;
@@ -164,14 +167,14 @@ static qse_size_t sift_down (qse_tmr_t* tmr, qse_size_t index, int notify)
return index;
}
-void qse_tmr_remove (qse_tmr_t* tmr, qse_size_t index)
+void qse_tmr_remove (qse_tmr_t* tmr, qse_tmr_index_t index)
{
qse_tmr_event_t item;
QSE_ASSERT (index < tmr->size);
item = tmr->event[index];
- tmr->event[index].updater (tmr, index, QSE_TMR_INVALID, tmr->event[index].ctx);
+ tmr->event[index].updater (tmr, index, QSE_TMR_INVALID_INDEX, tmr->event[index].ctx);
tmr->size = tmr->size - 1;
if (tmr->size > 0 && index != tmr->size)
@@ -182,9 +185,9 @@ void qse_tmr_remove (qse_tmr_t* tmr, qse_size_t index)
}
}
-qse_size_t qse_tmr_insert (qse_tmr_t* tmr, const qse_tmr_event_t* event)
+qse_tmr_index_t qse_tmr_insert (qse_tmr_t* tmr, const qse_tmr_event_t* event)
{
- qse_size_t index = tmr->size;
+ qse_tmr_index_t index = tmr->size;
if (index >= tmr->capa)
{
@@ -192,8 +195,8 @@ qse_size_t qse_tmr_insert (qse_tmr_t* tmr, const qse_tmr_event_t* event)
qse_size_t new_capa;
new_capa = tmr->capa * 2;
- tmp = QSE_MMGR_REALLOC (tmr->mmgr, tmr->event, new_capa);
- if (tmp == QSE_NULL) return QSE_TMR_INVALID;
+ tmp = QSE_MMGR_REALLOC (tmr->mmgr, tmr->event, new_capa * QSE_SIZEOF(*tmp));
+ if (tmp == QSE_NULL) return QSE_TMR_INVALID_INDEX;
tmr->event = tmp;
tmr->capa = new_capa;
diff --git a/qse/lib/http/Makefile.am b/qse/lib/http/Makefile.am
index 92da738e..603cb218 100644
--- a/qse/lib/http/Makefile.am
+++ b/qse/lib/http/Makefile.am
@@ -17,6 +17,8 @@ libqsehttp_la_SOURCES = \
httpd-file.c \
httpd-proxy.c \
httpd-std.c \
+ httpd-std-dns.h \
+ httpd-std-urs.h \
httpd-task.c \
httpd-text.c \
upxd.c
diff --git a/qse/lib/http/Makefile.in b/qse/lib/http/Makefile.in
index be457266..ffadb49a 100644
--- a/qse/lib/http/Makefile.in
+++ b/qse/lib/http/Makefile.in
@@ -338,6 +338,8 @@ libqsehttp_la_SOURCES = \
httpd-file.c \
httpd-proxy.c \
httpd-std.c \
+ httpd-std-dns.h \
+ httpd-std-urs.h \
httpd-task.c \
httpd-text.c \
upxd.c
diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c
index be615266..ba4dafa9 100644
--- a/qse/lib/http/httpd-proxy.c
+++ b/qse/lib/http/httpd-proxy.c
@@ -37,12 +37,15 @@ struct task_proxy_t
{
#define PROXY_INIT_FAILED (1 << 0)
#define PROXY_RAW (1 << 1)
-#define PROXY_RESOLVE_PEER_NAME (1 << 2)
-#define PROXY_PEER_NAME_RESOLVED (1 << 3)
-#define PROXY_PEER_NAME_UNRESOLVED (1 << 4)
-#define PROXY_X_FORWARDED_FOR (1 << 5)
-#define PROXY_VIA (1 << 6)
-#define PROXY_VIA_RETURNING (1 << 7)
+#define PROXY_TRANSPARENT (1 << 2)
+#define PROXY_RESOLVE_PEER_NAME (1 << 3)
+#define PROXY_PEER_NAME_RESOLVED (1 << 4)
+#define PROXY_PEER_NAME_UNRESOLVED (1 << 5)
+#define PROXY_REWRITE_URL (1 << 6)
+#define PROXY_URL_REWRITTEN (1 << 7)
+#define PROXY_X_FORWARDED_FOR (1 << 8) /* X-Forwarded-For added */
+#define PROXY_VIA (1 << 9) /* Via added to the request */
+#define PROXY_VIA_RETURNING (1 << 10) /* Via added to the response */
int flags;
qse_httpd_t* httpd;
qse_httpd_client_t* client;
@@ -50,8 +53,8 @@ struct task_proxy_t
int method;
qse_http_version_t version;
int keepalive; /* taken from the request */
- int raw;
+ qse_mchar_t* url_to_rewrite;
qse_mchar_t* pseudonym;
qse_htrd_t* peer_htrd;
@@ -66,8 +69,9 @@ struct task_proxy_t
#define PROXY_REQ_FWDERR (1 << 0)
#define PROXY_REQ_FWDCHUNKED (1 << 1)
int reqflags;
- qse_htre_t* req; /* original client request associated with this */
+ qse_htre_t* req; /* set to original client request associated with this if necessary */
qse_mbs_t* reqfwdbuf; /* content from the request */
+ const qse_mchar_t* host;
qse_mbs_t* res;
qse_size_t res_consumed;
@@ -234,8 +238,7 @@ static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key,
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
-
- if (!(proxy->flags & PROXY_X_FORWARDED_FOR))
+ if (!(proxy->flags & (PROXY_TRANSPARENT | PROXY_X_FORWARDED_FOR)))
{
if (qse_mbscasecmp (key, QSE_MT("X-Forwarded-For")) == 0)
{
@@ -246,7 +249,7 @@ static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key,
qse_mchar_t extra[128];
proxy->flags |= PROXY_X_FORWARDED_FOR;
- qse_nwadtombs (&proxy->client->remote_addr, extra, QSE_COUNTOF(extra), QSE_NWADTOMBS_ALL);
+ qse_nwadtombs (&proxy->client->remote_addr, extra, QSE_COUNTOF(extra), QSE_NWADTOMBS_ADDR);
return proxy_add_header_to_buffer_with_extra_data (proxy, proxy->reqfwdbuf, key, val, QSE_MT(", %hs"), extra);
}
@@ -903,6 +906,41 @@ static int task_init_proxy (
}
if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_RAW) proxy->flags |= PROXY_RAW;
+ if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_TRANSPARENT) proxy->flags |= PROXY_TRANSPARENT;
+
+ if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_URS)
+ {
+#if 0
+ const qse_mchar_t* qpath;
+ const qse_mchar_t* metnam;
+ const qse_htre_hdrval_t* hosthv;
+ qse_mchar_t cliaddrbuf[128];
+
+ /* URL client-ip/client-fqdn ident method */
+ qpath = qse_htre_getqpath(htreq);
+ method = qse_htre_getqmethodtype(htreq);
+ metnam = qse_httpmethodtombs(method);
+ hosthv = qse_htre_getheaderval(htreq, QSE_MT("Host"));
+ if (hosthv) printf ("hosthv -> %s\n", hosthv->ptr);
+ qse_nwadtombs (&client->remote_addr, cliaddrbuf, QSE_COUNTOF(cliaddrbuf), QSE_NWADTOMBS_ADDR);
+#endif
+
+ /* enable url rewriting */
+ proxy->flags |= PROXY_REWRITE_URL;
+
+#if 0
+ /* TODO: build URL TO REWRITE */
+ if (method == QSE_HTTP_CONNECT)
+ url_len = qse_mbsxfmt (QSE_NULL, 0, QSE_MT("%s %s/- - %s"), qpath, cliaddrbuf, metnam);
+ else if (host)
+ url_len = qse_mbsxfmt (QSE_NULL, 0, QSE_MT("http://%s%s %s/- - %s"), host, qpath, cliaddrbuf, metnam);
+ else if (hosthv)
+ url_len = qse_mbsxfmt (QSE_NULL, 0, QSE_MT("http://%s%s %s/- - %s"), hosthv->ptr, qpath, cliaddrbuf, metnam);
+ else
+ url_len = qse_mbsxfmt (QSE_NULL, 0, QSE_MT("%s %s/- - %s"), qpath, cliaddrbuf, metnam);
+#endif
+ }
+
proxy->peer.local = arg->rsrc->src.nwad;
if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_STR)
{
@@ -938,7 +976,6 @@ static int task_init_proxy (
else proxy->peer.local.type = arg->rsrc->dst.type;*/
proxy->req = QSE_NULL;
-
/* --------------------------------------------------------------------
* TODO: compose headers to send to peer and push them to fwdbuf...
* TODO: also change the content length check logic below...
@@ -950,6 +987,7 @@ static int task_init_proxy (
proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
if (proxy->reqfwdbuf == QSE_NULL) goto oops;
+ proxy->host = arg->rsrc->host;
if (proxy->flags & PROXY_RAW)
{
/* TODO: when connect is attempted, no keep-alive must be hornored.
@@ -985,7 +1023,7 @@ static int task_init_proxy (
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
- if (!(proxy->flags & PROXY_X_FORWARDED_FOR))
+ if (!(proxy->flags & (PROXY_TRANSPARENT | PROXY_X_FORWARDED_FOR)))
{
/* X-Forwarded-For is not added by proxy_capture_client_header()
* above. I don't care if it's included in the trailer. */
@@ -993,7 +1031,7 @@ static int task_init_proxy (
proxy->flags |= PROXY_X_FORWARDED_FOR;
- qse_nwadtombs (&proxy->client->remote_addr, extra, QSE_COUNTOF(extra), QSE_NWADTOMBS_ALL);
+ qse_nwadtombs (&proxy->client->remote_addr, extra, QSE_COUNTOF(extra), QSE_NWADTOMBS_ADDR);
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("X-Forwarded-For: ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, extra) == (qse_size_t)-1 ||
@@ -1144,7 +1182,7 @@ static int task_init_proxy (
{
/* set up a callback to be called when the request content
* is fed to the htrd reader. qse_htre_addcontent() that
- * htrd calls invokes this callback. */
+ * htrd calls invokes this callback. */
proxy->req = arg->req;
qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task);
}
@@ -1311,7 +1349,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask
if (proxy->peer_output_received < proxy->peer_output_length)
{
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
- log_proxy_error (proxy, "proxy premature eof - ");
+ log_proxy_error (proxy, "proxy premature eof(content) - ");
return -1;
}
}
@@ -1594,9 +1632,8 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
{
/* end of output from peer before it has seen a header.
* the proxy peer must be bad. */
-
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
- log_proxy_error (proxy, "proxy premature eof - ");
+ log_proxy_error (proxy, "proxy premature eof(header) - ");
if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) http_errnum = 502;
goto oops;
@@ -1618,7 +1655,7 @@ printf ("task_main_proxy_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n",
/* premature eof from the peer */
if (httpd->opt.trait & QSE_HTTPD_LOGACT)
- log_proxy_error (proxy, "proxy premature eof - ");
+ log_proxy_error (proxy, "proxy no content(chunked) - ");
goto oops;
}
}
@@ -1826,6 +1863,21 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name,
printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX PEER NAME RESOLVED.....\n");
}
+static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const qse_mchar_t* new_url, void* ctx)
+{
+ qse_httpd_task_t* task = (qse_httpd_task_t*)ctx;
+ task_proxy_t* proxy = (task_proxy_t*)task->ctx;
+
+/* TODO: HANDLE THIS PROPERLY */
+ proxy->flags |= PROXY_INIT_FAILED;
+printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN ....\n");
+
+ if (qse_httpd_activatetasktrigger (httpd, proxy->client, task) <= -1)
+ {
+ proxy->flags |= PROXY_INIT_FAILED;
+ }
+}
+
static int task_main_proxy (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
@@ -1840,19 +1892,18 @@ static int task_main_proxy (
goto oops;
}
-#if 0
if (proxy->flags & PROXY_REWRITE_URL)
{
- if (qse_httpd_rewriteurl (httpd, proxy->url, on_url_rewritten, task) <= -1) goto oops;
+ /* note that url_to_rewrite is URL + extra information. */
+ if (qse_httpd_rewriteurl (httpd, proxy->url_to_rewrite, on_url_rewritten, task) <= -1) goto oops;
if (proxy->flags & PROXY_INIT_FAILED) goto oops;
- if ((proxy->flags & PROXY_RESOL_REWRITE_URL) &&
+ if ((proxy->flags & PROXY_REWRITE_URL) &&
qse_httpd_inactivatetasktrigger (httpd, client, task) <= -1) goto oops;
return 1;
}
-#endif
if (proxy->flags & PROXY_RESOLVE_PEER_NAME)
{
@@ -2000,7 +2051,7 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
arg.rsrc = proxy;
arg.req = req;
-
+
if (proxy->pseudonym)
xtnsize += qse_mbslen (proxy->pseudonym) + 1;
else
@@ -2009,7 +2060,6 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
if (proxy->flags & QSE_HTTPD_RSRC_PROXY_DST_STR)
xtnsize += qse_mbslen (proxy->dst.str) + 1;
-
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_proxy;
task.fini = task_fini_proxy;
diff --git a/qse/lib/http/httpd-std-dns.h b/qse/lib/http/httpd-std-dns.h
new file mode 100644
index 00000000..1c41c3c1
--- /dev/null
+++ b/qse/lib/http/httpd-std-dns.h
@@ -0,0 +1,915 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2014 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+/*
+ * This file holds dns support code and is included by httpd-std.c
+ */
+
+#define DNS_MAX_DN_LEN 255 /* full domain name length in binary form (i.e. 3xyz2eu0) */
+#define DNS_MAX_MSG_LEN 512 /* basic dns only. no EDNS0. so 512 at most */
+
+#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;
+typedef struct dns_hdr_t dns_hdr_t;
+typedef struct dns_qdtrail_t dns_qdtrail_t;
+typedef struct dns_antrail_t dns_antrail_t;
+
+enum
+{
+ DNS_OPCODE_QUERY = 0,
+ DNS_OPCODE_IQUERY = 1,
+ DNS_OPCODE_STATUS = 2,
+ DNS_OPCODE_NOTIFY = 4,
+ DNS_OPCODE_UPDATE = 5,
+
+ DNS_RCODE_NOERROR = 0,
+ DNS_RCODE_FORMERR = 1,
+ DNS_RCODE_SERVFAIL = 2,
+ DNS_RCODE_NXDOMAIN = 3,
+ DNS_RCODE_NOTIMPL = 4,
+ DNS_RCODE_REFUSED = 5,
+
+ DNS_QTYPE_A = 1,
+ DNS_QTYPE_NS = 2,
+ DNS_QTYPE_CNAME = 5,
+ DNS_QTYPE_SOA = 6,
+ DNS_QTYPE_PTR = 12,
+ DNS_QTYPE_MX = 15,
+ DNS_QTYPE_TXT = 16,
+ DNS_QTYPE_AAAA = 28,
+ DNS_QTYPE_OPT = 41,
+ DNS_QTYPE_ANY = 255,
+
+ DNS_QCLASS_IN = 1, /* internet */
+ DNS_QCLASS_CH = 3, /* chaos */
+ DNS_QCLASS_HS = 4, /* hesiod */
+ DNS_QCLASS_NONE = 254,
+ DNS_QCLASS_ANY = 255
+};
+
+#include
+struct dns_hdr_t
+{
+ qse_uint16_t id;
+
+#if defined(QSE_ENDIAN_BIG)
+ qse_uint16_t qr: 1; /* question or response */
+ qse_uint16_t opcode: 4;
+ qse_uint16_t aa: 1; /* authoritative answer */
+ qse_uint16_t tc: 1; /* truncated message */
+ qse_uint16_t rd: 1; /* recursion desired */
+
+ qse_uint16_t ra: 1; /* recursion available */
+ qse_uint16_t z: 1;
+ qse_uint16_t ad: 1;
+ qse_uint16_t cd: 1;
+ qse_uint16_t rcode: 4;
+#else
+ qse_uint16_t rd: 1;
+ qse_uint16_t tc: 1;
+ qse_uint16_t aa: 1;
+ qse_uint16_t opcode: 4;
+ qse_uint16_t qr: 1;
+
+ qse_uint16_t rcode: 4;
+ qse_uint16_t cd: 1;
+ qse_uint16_t ad: 1;
+ qse_uint16_t z: 1;
+ qse_uint16_t ra: 1;
+#endif
+
+ qse_uint16_t qdcount; /* questions */
+ qse_uint16_t ancount; /* answers */
+ qse_uint16_t nscount; /* name servers */
+ qse_uint16_t arcount; /* additional resource */
+};
+
+struct dns_qdtrail_t
+{
+ qse_uint16_t qtype;
+ qse_uint16_t qclass;
+};
+
+struct dns_antrail_t
+{
+ qse_uint16_t qtype;
+ qse_uint16_t qclass;
+ qse_uint32_t ttl;
+ qse_uint16_t dlen; /* data length */
+};
+#include
+
+struct dns_ctx_t
+{
+ qse_httpd_t* httpd;
+ qse_httpd_dns_t* dns;
+
+ qse_skad_t skad;
+ int skadlen;
+
+ qse_uint16_t seq;
+ 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
+{
+ qse_mchar_t* name;
+
+#define DNS_REQ_A_NX (1 << 0)
+#define DNS_REQ_AAAA_NX (1 << 1)
+ int flags;
+ qse_uint16_t seqa, seqaaaa;
+
+ qse_uint8_t* dn;
+ qse_size_t dnlen;
+
+ qse_httpd_resol_t resol;
+ void* ctx;
+
+ qse_uint8_t qa[DNS_MAX_DN_LEN + QSE_SIZEOF(dns_hdr_t) + QSE_SIZEOF(dns_qdtrail_t)];
+ qse_uint8_t qaaaa[DNS_MAX_DN_LEN + QSE_SIZEOF(dns_hdr_t) + QSE_SIZEOF(dns_qdtrail_t)];
+ int qalen;
+ int qaaaalen;
+
+ dns_ctx_t* dc;
+ qse_tmr_index_t tmr_tmout;
+ 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;
+ dns_ans_t* next;
+};
+
+#define DN_AT_END(ptr) (ptr[0] == QSE_MT('\0') || (ptr[0] == QSE_MT('.') && ptr[1] == QSE_MT('\0')))
+
+static qse_size_t to_dn (const qse_mchar_t* str, qse_uint8_t* buf, qse_size_t bufsz)
+{
+ qse_uint8_t* bp = buf, * be = buf + bufsz;
+
+ QSE_ASSERT (QSE_SIZEOF(qse_uint8_t) == QSE_SIZEOF(qse_mchar_t));
+
+ if (!DN_AT_END(str))
+ {
+ qse_uint8_t* lp;
+ qse_size_t len;
+ const qse_mchar_t* seg;
+ const qse_mchar_t* cur = str - 1;
+
+ do
+ {
+ if (bp < be) lp = bp++;
+ else lp = QSE_NULL;
+
+ seg = ++cur;
+ while (*cur != QSE_MT('\0') && *cur != QSE_MT('.'))
+ {
+ if (bp < be) *bp++ = *cur;
+ cur++;
+ }
+ len = cur - seg;
+ if (len <= 0 || len > 63) return 0;
+
+ if (lp) *lp = (qse_uint8_t)len;
+ }
+ while (!DN_AT_END(cur));
+ }
+
+ if (bp < be) *bp++ = 0;
+ return bp - buf;
+}
+
+static qse_size_t dn_length (qse_uint8_t* ptr, qse_size_t len)
+{
+ qse_uint8_t* curptr;
+ qse_size_t curlen, seglen;
+
+ curptr = ptr;
+ curlen = len;
+
+ do
+ {
+ if (curlen <= 0) return 0;
+
+ seglen = *curptr++;
+ curlen = curlen - 1;
+ if (seglen == 0) break;
+ else if (seglen > curlen || seglen > 63) return 0;
+
+ curptr += seglen;
+ curlen -= seglen;
+ }
+ while (1);
+
+ return curptr - ptr;
+}
+
+int init_dns_query (qse_uint8_t* buf, qse_size_t len, const qse_mchar_t* name, int qtype, qse_uint16_t seq)
+{
+ dns_hdr_t* hdr;
+ dns_qdtrail_t* qdtrail;
+ qse_size_t x;
+
+ if (len < QSE_SIZEOF(*hdr)) return -1;
+
+ QSE_MEMSET (buf, 0, len);
+ hdr = (dns_hdr_t*)buf;
+ hdr->id = qse_hton16(seq);
+ hdr->opcode = DNS_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 = (dns_qdtrail_t*)((qse_uint8_t*)(hdr + 1) + x);
+
+ qdtrail->qtype = qse_hton16(qtype);
+ qdtrail->qclass = qse_hton16(DNS_QCLASS_IN);
+ return QSE_SIZEOF(*hdr) + x + QSE_SIZEOF(*qdtrail);
+}
+
+static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
+{
+#if defined(__DOS__)
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
+ return -1;
+#else
+ sock_t fd = SOCK_INIT;
+ int flag;
+ qse_nwad_t nwad;
+ dns_ctx_t* dc;
+ httpd_xtn_t* httpd_xtn;
+
+ httpd_xtn = qse_httpd_getxtn (httpd);
+
+ dc = (dns_ctx_t*) qse_httpd_callocmem (httpd, QSE_SIZEOF(dns_ctx_t));
+ if (dc == NULL) goto oops;
+
+ 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 */
+
+ nwad = httpd_xtn->dns.nwad;
+ if (nwad.type == QSE_NWAD_NX)
+ {
+ qse_sio_t* sio;
+ #if defined(_WIN32)
+ /* TODO: windns.h dnsapi.lib DnsQueryConfig... */
+ #elif defined(__OS2__)
+ /* TODO: */
+ #else
+ /* TODO: read /etc/resolv.conf???? */
+ #endif
+
+ sio = qse_sio_open (qse_httpd_getmmgr(httpd), 0, QSE_T("/etc/resolv.conf"), QSE_SIO_READ);
+ if (sio)
+ {
+ qse_mchar_t buf[128];
+ qse_ssize_t len;
+ qse_mcstr_t tok;
+ qse_mchar_t* ptr;
+ qse_mchar_t* end;
+
+ while (1)
+ {
+ len = qse_sio_getmbsn (sio, buf, QSE_COUNTOF(buf));
+ if (len <= 0) break;
+
+ end = buf + len;
+ ptr = buf;
+
+ ptr = qse_mbsxtok (ptr, end - ptr, QSE_MT(" \t"), &tok);
+ if (ptr && qse_mbsxcmp (tok.ptr, tok.len, QSE_MT("nameserver")) == 0)
+ {
+ ptr = qse_mbsxtok (ptr, end - ptr, QSE_MT(" \t"), &tok);
+ if (qse_mbsntonwad (tok.ptr, tok.len, &nwad) >= 0) break;
+ }
+ }
+ qse_sio_close (sio);
+ }
+ }
+
+ if (qse_getnwadport(&nwad) == 0)
+ qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DNSSTD_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), "nameserver 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;
+ }
+
+ #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;
+
+ dns->handle.i = fd;
+ dns->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 dns_remove_tmr_tmout (dns_req_t* req)
+{
+ if (req->tmr_tmout != QSE_TMR_INVALID_INDEX)
+ {
+ qse_httpd_removetimerevent (req->dc->httpd, req->tmr_tmout);
+ req->tmr_tmout = QSE_TMR_INVALID_INDEX;
+ }
+}
+
+static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
+{
+ dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
+ qse_size_t i;
+
+ for (i = 0; i < QSE_COUNTOF(dc->reqs); i++)
+ {
+ dns_req_t* next_req;
+ 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;
+ dc->req_count--;
+ }
+ }
+
+ QSE_ASSERT (dc->req_count == 0);
+
+ for (i = 0; i < QSE_COUNTOF(dc->anss); i++)
+ {
+ dns_ans_t* next_ans;
+ while (dc->anss[i])
+ {
+ next_ans = dc->anss[i]->next;
+ qse_httpd_freemem (httpd, dc->anss[i]);
+ dc->anss[i] = next_ans;
+ }
+ }
+
+ close_socket (dns->handle.i);
+ qse_httpd_freemem (httpd, dns->ctx);
+}
+
+
+
+static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* nwad, qse_uint32_t ttl)
+{
+ dns_ans_t* ans, * prv, * cur;
+ qse_size_t hid;
+ qse_ntime_t now;
+
+/* TODO: implement the maximum number of entries in cache... */
+
+ /* i use the given request as a space to hold an answer.
+ * the following assertion must be met for this to work */
+ QSE_ASSERT (QSE_SIZEOF(dns_req_t) >= QSE_SIZEOF(dns_ans_t));
+
+ 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 */
+
+ if (ttl < DNS_MIN_TTL) ttl = DNS_MIN_TTL; /* TODO: use configured value */
+ else if (ttl > DNS_MAX_TTL) ttl = DNS_MAX_TTL;
+
+ ans->ttl = ttl;
+ hid = hash_string (req->name) % QSE_COUNTOF(dc->anss);
+
+ prv = QSE_NULL;
+ cur = dc->anss[hid];
+ while (cur)
+ {
+ if (qse_mbscasecmp(cur->name, ans->name) == 0)
+ {
+ ans->next = cur->next;
+ if (prv) prv->next = ans;
+ else dc->anss[hid] = ans;
+ qse_httpd_freemem (dc->httpd, cur);
+ return;
+ }
+
+ prv = cur;
+ cur = cur->next;
+ }
+ ans->next = dc->anss[hid];
+ dc->anss[hid] = ans;
+}
+
+static dns_ans_t* dns_get_answer_from_cache (dns_ctx_t* dc, const qse_mchar_t* name)
+{
+ dns_ans_t* prv, * cur;
+ qse_size_t hid;
+ qse_ntime_t now;
+
+ hid = hash_string(name) % QSE_COUNTOF(dc->anss);
+
+ qse_gettime (&now);
+
+ prv = QSE_NULL;
+ cur = dc->anss[hid];
+ while (cur)
+ {
+ if (qse_mbscasecmp(cur->name, name) == 0)
+ {
+ if (cur->age + cur->ttl < now.sec)
+ {
+ /* entry expired. evict the entry from the cache */
+ if (prv) prv->next = cur->next;
+ else dc->anss[hid] = cur->next;
+ qse_httpd_freemem (dc->httpd, cur);
+ break;
+ }
+
+ return cur;
+ }
+
+ prv = cur;
+ cur = cur->next;
+ }
+
+ return QSE_NULL;
+}
+
+static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
+{
+ dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
+ httpd_xtn_t* httpd_xtn;
+
+ qse_skad_t fromaddr;
+ socklen_t fromlen;
+
+ qse_uint8_t buf[DNS_MAX_MSG_LEN];
+ 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);
+
+ fromlen = QSE_SIZEOF(fromaddr);
+ len = recvfrom (dns->handle.i, buf, QSE_SIZEOF(buf), 0, (struct sockaddr*)&fromaddr, &fromlen);
+
+/* TODO: check if fromaddr matches the dc->skad... */
+
+ if (len < QSE_SIZEOF(*hdr)) goto done; /* packet too small */
+
+ hdr = (dns_hdr_t*)buf;
+ qdcount = qse_ntoh16(hdr->qdcount);
+
+ if (!hdr->qr || hdr->opcode != DNS_OPCODE_QUERY || qdcount <= 0)
+ {
+ /* 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; /* weird packet */
+
+ if (!req)
+ {
+ qdtrail = (dns_qdtrail_t*)(plptr + dnlen);
+
+ if (qdtrail->qclass == dc->n_qcin &&
+ (qdtrail->qtype == dc->n_qta || qdtrail->qtype == dc->n_qtaaaa))
+ {
+ for (req = dc->reqs[xid]; req; req = req->next)
+ {
+ 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) goto done; /* no good answers */
+
+ /* inspect the answer section */
+ for (i = 0; i < ancount; i++)
+ {
+ 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) return 0; /* invalid dn name */
+ }
+
+ reclen = dnlen + QSE_SIZEOF(dns_antrail_t);
+ if (pllen < reclen) goto done;
+
+ antrail = (dns_antrail_t*)(plptr + dnlen);
+ reclen += qse_ntoh16(antrail->dlen);
+ if (pllen < reclen) goto done;
+
+ anlen = qse_ntoh16(antrail->dlen);
+
+ if (antrail->qclass == dc->n_qcin)
+ {
+ nwad.type = QSE_NWAD_NX;
+
+ 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);
+ }
+ 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);
+ }
+
+ if (nwad.type != QSE_NWAD_NX)
+ {
+ 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;
+
+ 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;
+ else if (id == req->seqaaaa) req->flags |= DNS_REQ_AAAA_NX;
+
+ 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 */
+ 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_update (qse_tmr_t* tmr, qse_tmr_index_t old_index, qse_tmr_index_t new_index, void* ctx)
+{
+ dns_req_t* req = (dns_req_t*)ctx;
+
+printf (">>tmr_dns_tmout_updated req->>%p\n", req);
+printf (">>tmr_dns_tmout_updated existing->%d, old->%d new->%d\n", (int)req->tmr_tmout, (int)old_index, (int)new_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_ctx_t* dc = req->dc;
+ qse_uint16_t xid;
+
+printf (">>tmr_dns_tmout_handle req->>%p\n", req);
+ /* when this handler is called, the event must be removed from the timer */
+ QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID_INDEX);
+
+ /* ---------------------------------------------------------------
+ * 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->dns.tmout, &tmout_event.when);
+ tmout_event.ctx = req;
+ tmout_event.handler = tmr_dns_tmout_handle;
+ tmout_event.updater = tmr_dns_tmout_update;
+
+ 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))
+ {
+ /* resend failed. fall thru and destroy the request*/
+ }
+ else
+ {
+ QSE_ASSERT (tmr == dc->httpd->tmr);
+ if (qse_httpd_inserttimerevent (dc->httpd, &tmout_event, &req->tmr_tmout) >= 0)
+ {
+ req->resends--;
+ return; /* resend ok */
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------
+ * dns timed out + no resend
+ *---------------------------------------------------------------- */
+
+ /* 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 (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 (dc->httpd, req->name, QSE_NULL, req->ctx);
+
+ /* i don't cache the items that have timed out */
+ 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)
+{
+ dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
+ httpd_xtn_t* httpd_xtn;
+
+ qse_uint32_t seq;
+ qse_uint16_t xid;
+ dns_req_t* req = QSE_NULL;
+ qse_size_t name_len;
+ dns_ans_t* ans;
+ qse_tmr_event_t tmout_event;
+
+ httpd_xtn = qse_httpd_getxtn (httpd);
+
+printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ ans = dns_get_answer_from_cache (dc, name);
+ if (ans)
+ {
+ resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx);
+ return 0;
+ }
+
+ if (dc->req_count >= QSE_COUNTOF(dc->reqs))
+ {
+ /* too many pending requests */
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF);
+ goto oops;
+ }
+
+ 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.
+ * a.bb.ccc => 1a2bb3ccc0 => +2
+ * a.bb.ccc. => 1a2bb3ccc0 => +1 */
+ req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + (name_len + 1) + (name_len + 2));
+ if (req == QSE_NULL) goto oops;
+
+ req->tmr_tmout = QSE_TMR_INVALID_INDEX;
+
+ /* 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 + 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);
+
+ qse_mbscpy (req->name, name);
+ req->dnlen = to_dn (name, req->dn, name_len + 2);
+ if (req->dnlen <= 0)
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
+ goto oops;
+ }
+ req->resol = resol;
+ req->ctx = ctx;
+
+ if (!(httpd->opt.trait & QSE_HTTPD_DNSNOA))
+ req->qalen = init_dns_query (req->qa, QSE_SIZEOF(req->qa), name, DNS_QTYPE_A, req->seqa);
+ else
+ req->flags |= DNS_REQ_A_NX;
+
+ if (!(httpd->opt.trait & QSE_HTTPD_DNSNOAAAA))
+ req->qaaaalen = init_dns_query (req->qaaaa, QSE_SIZEOF(req->qaaaa), name, DNS_QTYPE_AAAA, req->seqaaaa);
+ else
+ req->flags |= DNS_REQ_AAAA_NX;
+
+ if (req->qalen <= -1 || req->qaaaalen <= -1)
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
+ goto oops;
+ }
+
+ req->resends = httpd_xtn->dns.resends;
+
+ 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_update;
+ if (qse_httpd_inserttimerevent (httpd, &tmout_event, &req->tmr_tmout) <= -1) goto oops;
+
+ 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_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
+ goto oops;
+ }
+
+ /* 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;
+
+ /* 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;
+
+oops:
+ if (req)
+ {
+ dns_remove_tmr_tmout (req);
+ qse_httpd_freemem (httpd, req);
+ }
+ return -1;
+}
diff --git a/qse/lib/http/httpd-std-urs.h b/qse/lib/http/httpd-std-urs.h
new file mode 100644
index 00000000..faeccb3e
--- /dev/null
+++ b/qse/lib/http/httpd-std-urs.h
@@ -0,0 +1,411 @@
+/*
+ * $Id$
+ *
+ Copyright 2006-2014 Chung, Hyung-Hwan.
+ This file is part of QSE.
+
+ QSE is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ QSE is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with QSE. If not, see .
+ */
+
+/*
+ * This file holds url rewriting support code and is included by httpd-std.c
+ */
+
+#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
+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
+
+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)];
+ qse_uint8_t fmtbuf[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_tmr_index_t tmr_tmout;
+ int resends;
+
+ urs_req_t* prev;
+ urs_req_t* next;
+};
+
+
+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_INDEX)
+ {
+ qse_httpd_removetimerevent (req->dc->httpd, req->tmr_tmout);
+ req->tmr_tmout = QSE_TMR_INVALID_INDEX;
+ }
+}
+
+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_update (qse_tmr_t* tmr, qse_tmr_index_t old_index, qse_tmr_index_t new_index, void* ctx)
+{
+ urs_req_t* req = (urs_req_t*)ctx;
+
+printf (">>tmr_urs_tmout_updated existing=%d old=%d new=%d\n", (int)req->tmr_tmout, (int)old_index, (int)new_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_INDEX);
+
+ /* ---------------------------------------------------------------
+ * 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_update;
+
+ if (sendto (dc->urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen)
+ {
+ /* error. fall thru */
+ }
+ else
+ {
+ QSE_ASSERT (tmr == dc->httpd->tmr);
+ if (qse_httpd_inserttimerevent (dc->httpd, &tmout_event, &req->tmr_tmout) >= 0)
+ {
+ 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_NULL;
+ 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);
+ goto oops;
+ }
+
+ url_len = qse_mbslen(url);
+ if (url_len > URS_MAX_URL_LEN) /* TODO: change the limit */
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
+ goto oops;
+ }
+
+ 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) goto oops;
+
+ req->tmr_tmout = QSE_TMR_INVALID_INDEX;
+ 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);
+
+ /* -1 to exclude the terminating '\0' as urs_pkt_t has url[1]. */
+ req->pktlen = QSE_SIZEOF(urs_pkt_t) + url_len - 1;
+
+ req->rewrite = rewrite;
+ req->ctx = ctx;
+ req->resends = httpd_xtn->urs.resends;
+
+ 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_update;
+ if (qse_httpd_inserttimerevent (httpd, &tmout_event, &req->tmr_tmout) <= -1) goto oops;
+
+ if (sendto (urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen)
+ {
+ qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
+ goto oops;
+ }
+
+ 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;
+
+oops:
+ if (req)
+ {
+ urs_remove_tmr_tmout (req);
+ qse_httpd_freemem (httpd, req);
+ }
+ return -1;
+}
+
diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c
index 4d8d66c5..8e90f980 100644
--- a/qse/lib/http/httpd-std.c
+++ b/qse/lib/http/httpd-std.c
@@ -334,42 +334,39 @@ static qse_httpd_errnum_t fioerr_to_errnum (qse_fio_errnum_t e)
static qse_httpd_errnum_t direrr_to_errnum (qse_dir_errnum_t e)
{
- switch (e)
- {
- case QSE_DIR_ENOMEM:
- return QSE_HTTPD_ENOMEM;
+ switch (e)
+ {
+ case QSE_DIR_ENOMEM:
+ return QSE_HTTPD_ENOMEM;
- case QSE_DIR_EINVAL:
- return QSE_HTTPD_EINVAL;
+ case QSE_DIR_EINVAL:
+ return QSE_HTTPD_EINVAL;
- case QSE_DIR_EACCES:
- return QSE_HTTPD_EACCES;
+ case QSE_DIR_EACCES:
+ return QSE_HTTPD_EACCES;
- case QSE_DIR_ENOENT:
- return QSE_HTTPD_ENOENT;
+ case QSE_DIR_ENOENT:
+ return QSE_HTTPD_ENOENT;
- case QSE_DIR_EEXIST:
- return QSE_HTTPD_EEXIST;
+ case QSE_DIR_EEXIST:
+ return QSE_HTTPD_EEXIST;
- case QSE_DIR_EINTR:
- return QSE_HTTPD_EINTR;
+ case QSE_DIR_EINTR:
+ return QSE_HTTPD_EINTR;
- case QSE_DIR_EPIPE:
- return QSE_HTTPD_EPIPE;
+ case QSE_DIR_EPIPE:
+ return QSE_HTTPD_EPIPE;
- case QSE_DIR_EAGAIN:
- return QSE_HTTPD_EAGAIN;
+ case QSE_DIR_EAGAIN:
+ return QSE_HTTPD_EAGAIN;
- default:
- return QSE_HTTPD_ESYSERR;
- }
+ default:
+ return QSE_HTTPD_ESYSERR;
+ }
}
-
-
/* ------------------------------------------------------------------- */
-
static QSE_INLINE qse_ssize_t __send_file (
qse_httpd_t* httpd, int out_fd, qse_ubi_t in_fd,
qse_foff_t* offset, qse_size_t count)
@@ -2010,1321 +2007,6 @@ 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) */
-#define DNS_MAX_MSG_LEN 512 /* basic dns only. no EDNS0. so 512 at most */
-
-#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;
-typedef struct dns_hdr_t dns_hdr_t;
-typedef struct dns_qdtrail_t dns_qdtrail_t;
-typedef struct dns_antrail_t dns_antrail_t;
-
-enum
-{
- DNS_OPCODE_QUERY = 0,
- DNS_OPCODE_IQUERY = 1,
- DNS_OPCODE_STATUS = 2,
- DNS_OPCODE_NOTIFY = 4,
- DNS_OPCODE_UPDATE = 5,
-
- DNS_RCODE_NOERROR = 0,
- DNS_RCODE_FORMERR = 1,
- DNS_RCODE_SERVFAIL = 2,
- DNS_RCODE_NXDOMAIN = 3,
- DNS_RCODE_NOTIMPL = 4,
- DNS_RCODE_REFUSED = 5,
-
- DNS_QTYPE_A = 1,
- DNS_QTYPE_NS = 2,
- DNS_QTYPE_CNAME = 5,
- DNS_QTYPE_SOA = 6,
- DNS_QTYPE_PTR = 12,
- DNS_QTYPE_MX = 15,
- DNS_QTYPE_TXT = 16,
- DNS_QTYPE_AAAA = 28,
- DNS_QTYPE_OPT = 41,
- DNS_QTYPE_ANY = 255,
-
- DNS_QCLASS_IN = 1, /* internet */
- DNS_QCLASS_CH = 3, /* chaos */
- DNS_QCLASS_HS = 4, /* hesiod */
- DNS_QCLASS_NONE = 254,
- DNS_QCLASS_ANY = 255
-};
-
-#include
-struct dns_hdr_t
-{
- qse_uint16_t id;
-
-#if defined(QSE_ENDIAN_BIG)
- qse_uint16_t qr: 1; /* question or response */
- qse_uint16_t opcode: 4;
- qse_uint16_t aa: 1; /* authoritative answer */
- qse_uint16_t tc: 1; /* truncated message */
- qse_uint16_t rd: 1; /* recursion desired */
-
- qse_uint16_t ra: 1; /* recursion available */
- qse_uint16_t z: 1;
- qse_uint16_t ad: 1;
- qse_uint16_t cd: 1;
- qse_uint16_t rcode: 4;
-#else
- qse_uint16_t rd: 1;
- qse_uint16_t tc: 1;
- qse_uint16_t aa: 1;
- qse_uint16_t opcode: 4;
- qse_uint16_t qr: 1;
-
- qse_uint16_t rcode: 4;
- qse_uint16_t cd: 1;
- qse_uint16_t ad: 1;
- qse_uint16_t z: 1;
- qse_uint16_t ra: 1;
-#endif
-
- qse_uint16_t qdcount; /* questions */
- qse_uint16_t ancount; /* answers */
- qse_uint16_t nscount; /* name servers */
- qse_uint16_t arcount; /* additional resource */
-};
-
-struct dns_qdtrail_t
-{
- qse_uint16_t qtype;
- qse_uint16_t qclass;
-};
-
-struct dns_antrail_t
-{
- qse_uint16_t qtype;
- qse_uint16_t qclass;
- qse_uint32_t ttl;
- qse_uint16_t dlen; /* data length */
-};
-#include
-
-struct dns_ctx_t
-{
- qse_httpd_t* httpd;
- qse_httpd_dns_t* dns;
-
- qse_skad_t skad;
- int skadlen;
-
- qse_uint16_t seq;
- 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
-{
- qse_mchar_t* name;
-
-#define DNS_REQ_A_NX (1 << 0)
-#define DNS_REQ_AAAA_NX (1 << 1)
- int flags;
- qse_uint16_t seqa, seqaaaa;
-
- qse_uint8_t* dn;
- qse_size_t dnlen;
-
- qse_httpd_resol_t resol;
- void* ctx;
-
- qse_uint8_t qa[DNS_MAX_DN_LEN + QSE_SIZEOF(dns_hdr_t) + QSE_SIZEOF(dns_qdtrail_t)];
- qse_uint8_t qaaaa[DNS_MAX_DN_LEN + QSE_SIZEOF(dns_hdr_t) + QSE_SIZEOF(dns_qdtrail_t)];
- int qalen;
- int qaaaalen;
-
- dns_ctx_t* dc;
- qse_size_t tmr_tmout;
- 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;
- dns_ans_t* next;
-};
-
-#define DN_AT_END(ptr) (ptr[0] == QSE_MT('\0') || (ptr[0] == QSE_MT('.') && ptr[1] == QSE_MT('\0')))
-
-static qse_size_t to_dn (const qse_mchar_t* str, qse_uint8_t* buf, qse_size_t bufsz)
-{
- qse_uint8_t* bp = buf, * be = buf + bufsz;
-
- QSE_ASSERT (QSE_SIZEOF(qse_uint8_t) == QSE_SIZEOF(qse_mchar_t));
-
- if (!DN_AT_END(str))
- {
- qse_uint8_t* lp;
- qse_size_t len;
- const qse_mchar_t* seg;
- const qse_mchar_t* cur = str - 1;
-
- do
- {
- if (bp < be) lp = bp++;
- else lp = QSE_NULL;
-
- seg = ++cur;
- while (*cur != QSE_MT('\0') && *cur != QSE_MT('.'))
- {
- if (bp < be) *bp++ = *cur;
- cur++;
- }
- len = cur - seg;
- if (len <= 0 || len > 63) return 0;
-
- if (lp) *lp = (qse_uint8_t)len;
- }
- while (!DN_AT_END(cur));
- }
-
- if (bp < be) *bp++ = 0;
- return bp - buf;
-}
-
-static qse_size_t dn_length (qse_uint8_t* ptr, qse_size_t len)
-{
- qse_uint8_t* curptr;
- qse_size_t curlen, seglen;
-
- curptr = ptr;
- curlen = len;
-
- do
- {
- if (curlen <= 0) return 0;
-
- seglen = *curptr++;
- curlen = curlen - 1;
- if (seglen == 0) break;
- else if (seglen > curlen || seglen > 63) return 0;
-
- curptr += seglen;
- curlen -= seglen;
- }
- while (1);
-
- return curptr - ptr;
-}
-
-int init_dns_query (qse_uint8_t* buf, qse_size_t len, const qse_mchar_t* name, int qtype, qse_uint16_t seq)
-{
- dns_hdr_t* hdr;
- dns_qdtrail_t* qdtrail;
- qse_size_t x;
-
- if (len < QSE_SIZEOF(*hdr)) return -1;
-
- QSE_MEMSET (buf, 0, len);
- hdr = (dns_hdr_t*)buf;
- hdr->id = qse_hton16(seq);
- hdr->opcode = DNS_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 = (dns_qdtrail_t*)((qse_uint8_t*)(hdr + 1) + x);
-
- qdtrail->qtype = qse_hton16(qtype);
- qdtrail->qclass = qse_hton16(DNS_QCLASS_IN);
- return QSE_SIZEOF(*hdr) + x + QSE_SIZEOF(*qdtrail);
-}
-
-static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
-{
-#if defined(__DOS__)
- qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
- return -1;
-#else
- sock_t fd = SOCK_INIT;
- int flag;
- qse_nwad_t nwad;
- dns_ctx_t* dc;
- httpd_xtn_t* httpd_xtn;
-
- httpd_xtn = qse_httpd_getxtn (httpd);
-
- dc = (dns_ctx_t*) qse_httpd_callocmem (httpd, QSE_SIZEOF(dns_ctx_t));
- if (dc == NULL) goto oops;
-
- 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 */
-
- nwad = httpd_xtn->dns.nwad;
- if (nwad.type == QSE_NWAD_NX)
- {
- qse_sio_t* sio;
- #if defined(_WIN32)
- /* TODO: windns.h dnsapi.lib DnsQueryConfig... */
- #elif defined(__OS2__)
- /* TODO: */
- #else
- /* TODO: read /etc/resolv.conf???? */
- #endif
-
- sio = qse_sio_open (qse_httpd_getmmgr(httpd), 0, QSE_T("/etc/resolv.conf"), QSE_SIO_READ);
- if (sio)
- {
- qse_mchar_t buf[128];
- qse_ssize_t len;
- qse_mcstr_t tok;
- qse_mchar_t* ptr;
- qse_mchar_t* end;
-
- while (1)
- {
- len = qse_sio_getmbsn (sio, buf, QSE_COUNTOF(buf));
- if (len <= 0) break;
-
- end = buf + len;
- ptr = buf;
-
- ptr = qse_mbsxtok (ptr, end - ptr, QSE_MT(" \t"), &tok);
- if (ptr && qse_mbsxcmp (tok.ptr, tok.len, QSE_MT("nameserver")) == 0)
- {
- ptr = qse_mbsxtok (ptr, end - ptr, QSE_MT(" \t"), &tok);
- if (qse_mbsntonwad (tok.ptr, tok.len, &nwad) >= 0) break;
- }
- }
- qse_sio_close (sio);
- }
- }
-
- if (qse_getnwadport(&nwad) == 0)
- qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DNSSTD_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), "nameserver 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;
- }
-
- #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;
-
- dns->handle.i = fd;
- dns->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 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;
- qse_size_t i;
-
- for (i = 0; i < QSE_COUNTOF(dc->reqs); i++)
- {
- dns_req_t* next_req;
- 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;
- dc->req_count--;
- }
- }
-
- QSE_ASSERT (dc->req_count == 0);
-
- for (i = 0; i < QSE_COUNTOF(dc->anss); i++)
- {
- dns_ans_t* next_ans;
- while (dc->anss[i])
- {
- next_ans = dc->anss[i]->next;
- qse_httpd_freemem (httpd, dc->anss[i]);
- dc->anss[i] = next_ans;
- }
- }
-
- close_socket (dns->handle.i);
- qse_httpd_freemem (httpd, dns->ctx);
-}
-
-
-
-static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* nwad, qse_uint32_t ttl)
-{
- dns_ans_t* ans, * prv, * cur;
- qse_size_t hid;
- qse_ntime_t now;
-
-/* TODO: implement the maximum number of entries in cache... */
-
- /* i use the given request as a space to hold an answer.
- * the following assertion must be met for this to work */
- QSE_ASSERT (QSE_SIZEOF(dns_req_t) >= QSE_SIZEOF(dns_ans_t));
-
- 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 */
-
- if (ttl < DNS_MIN_TTL) ttl = DNS_MIN_TTL; /* TODO: use configured value */
- else if (ttl > DNS_MAX_TTL) ttl = DNS_MAX_TTL;
-
- ans->ttl = ttl;
- hid = hash_string (req->name) % QSE_COUNTOF(dc->anss);
-
- prv = QSE_NULL;
- cur = dc->anss[hid];
- while (cur)
- {
- if (qse_mbscasecmp(cur->name, ans->name) == 0)
- {
- ans->next = cur->next;
- if (prv) prv->next = ans;
- else dc->anss[hid] = ans;
- qse_httpd_freemem (dc->httpd, cur);
- return;
- }
-
- prv = cur;
- cur = cur->next;
- }
- ans->next = dc->anss[hid];
- dc->anss[hid] = ans;
-}
-
-static dns_ans_t* dns_get_answer_from_cache (dns_ctx_t* dc, const qse_mchar_t* name)
-{
- dns_ans_t* prv, * cur;
- qse_size_t hid;
- qse_ntime_t now;
-
- hid = hash_string(name) % QSE_COUNTOF(dc->anss);
-
- qse_gettime (&now);
-
- prv = QSE_NULL;
- cur = dc->anss[hid];
- while (cur)
- {
- if (qse_mbscasecmp(cur->name, name) == 0)
- {
- if (cur->age + cur->ttl < now.sec)
- {
- /* entry expired. evict the entry from the cache */
- if (prv) prv->next = cur->next;
- else dc->anss[hid] = cur->next;
- qse_httpd_freemem (dc->httpd, cur);
- break;
- }
-
- return cur;
- }
-
- prv = cur;
- cur = cur->next;
- }
-
- return QSE_NULL;
-}
-
-static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns)
-{
- dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
- httpd_xtn_t* httpd_xtn;
-
- qse_skad_t fromaddr;
- socklen_t fromlen;
-
- qse_uint8_t buf[DNS_MAX_MSG_LEN];
- 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);
-
- fromlen = QSE_SIZEOF(fromaddr);
- len = recvfrom (dns->handle.i, buf, QSE_SIZEOF(buf), 0, (struct sockaddr*)&fromaddr, &fromlen);
-
-/* TODO: check if fromaddr matches the dc->skad... */
-
- if (len < QSE_SIZEOF(*hdr)) goto done; /* packet too small */
-
- hdr = (dns_hdr_t*)buf;
- qdcount = qse_ntoh16(hdr->qdcount);
-
- if (!hdr->qr || hdr->opcode != DNS_OPCODE_QUERY || qdcount <= 0)
- {
- /* 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; /* weird packet */
-
- if (!req)
- {
- qdtrail = (dns_qdtrail_t*)(plptr + dnlen);
-
- if (qdtrail->qclass == dc->n_qcin &&
- (qdtrail->qtype == dc->n_qta || qdtrail->qtype == dc->n_qtaaaa))
- {
- for (req = dc->reqs[xid]; req; req = req->next)
- {
- 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) goto done; /* no good answers */
-
- /* inspect the answer section */
- for (i = 0; i < ancount; i++)
- {
- 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) return 0; /* invalid dn name */
- }
-
- reclen = dnlen + QSE_SIZEOF(dns_antrail_t);
- if (pllen < reclen) goto done;
-
- antrail = (dns_antrail_t*)(plptr + dnlen);
- reclen += qse_ntoh16(antrail->dlen);
- if (pllen < reclen) goto done;
-
- anlen = qse_ntoh16(antrail->dlen);
-
- if (antrail->qclass == dc->n_qcin)
- {
- nwad.type = QSE_NWAD_NX;
-
- 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);
- }
- 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);
- }
-
- if (nwad.type != QSE_NWAD_NX)
- {
- 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;
-
- 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;
- else if (id == req->seqaaaa) req->flags |= DNS_REQ_AAAA_NX;
-
- 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 */
- 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_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;
-
-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_ctx_t* dc = req->dc;
- qse_uint16_t xid;
-
- /* when this handler is called, the event must 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->dns.tmout, &tmout_event.when);
- tmout_event.ctx = req;
- tmout_event.handler = tmr_dns_tmout_handle;
- tmout_event.updater = tmr_dns_tmout_update;
-
- 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))
- {
- /* resend failed. fall thru and destroy the request*/
- }
- else
- {
- req->tmr_tmout = qse_tmr_insert (dc->httpd->tmr, &tmout_event);
- if (req->tmr_tmout != QSE_TMR_INVALID)
- {
- req->resends--;
- return; /* resend ok */
- }
- }
- }
-
- /* ---------------------------------------------------------------
- * dns timed out + no resend
- *---------------------------------------------------------------- */
-
- /* 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 (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 (dc->httpd, req->name, QSE_NULL, req->ctx);
-
- /* i don't cache the items that have timed out */
- 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)
-{
- dns_ctx_t* dc = (dns_ctx_t*)dns->ctx;
- 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;
- qse_tmr_event_t tmout_event;
-
- httpd_xtn = qse_httpd_getxtn (httpd);
-
-printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n");
-
- ans = dns_get_answer_from_cache (dc, name);
- if (ans)
- {
- resol (httpd, name, ((ans->nwad.type == QSE_NWAD_NX)? QSE_NULL: &ans->nwad), ctx);
- return 0;
- }
-
- 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.
- * a.bb.ccc => 1a2bb3ccc0 => +2
- * a.bb.ccc. => 1a2bb3ccc0 => +1 */
- 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 + 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);
-
- qse_mbscpy (req->name, name);
- req->dnlen = to_dn (name, req->dn, name_len + 2);
- if (req->dnlen <= 0)
- {
- qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
- qse_httpd_freemem (httpd,req);
- return -1;
- }
- req->resol = resol;
- req->ctx = ctx;
-
- if (!(httpd->opt.trait & QSE_HTTPD_DNSNOA))
- req->qalen = init_dns_query (req->qa, QSE_SIZEOF(req->qa), name, DNS_QTYPE_A, req->seqa);
- else
- req->flags |= DNS_REQ_A_NX;
-
- if (!(httpd->opt.trait & QSE_HTTPD_DNSNOAAAA))
- req->qaaaalen = init_dns_query (req->qaaaa, QSE_SIZEOF(req->qaaaa), name, DNS_QTYPE_AAAA, req->seqaaaa);
- else
- req->flags |= DNS_REQ_AAAA_NX;
-
- if (req->qalen <= -1 || req->qaaaalen <= -1)
- {
- qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
- qse_httpd_freemem (httpd,req);
- return -1;
- }
-
- 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_update;
-
- 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->dns.resends;
-
- 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;
- }
-
- /* 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;
-
- /* 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
-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
-
-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
@@ -3586,6 +2268,18 @@ static void logact_httpd (qse_httpd_t* httpd, const qse_httpd_act_t* act)
/* do nothing */
}
+/* ------------------------------------------------------------------- */
+
+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;
+}
+
+#include "httpd-std-dns.h"
+#include "httpd-std-urs.h"
+/* ------------------------------------------------------------------- */
static qse_httpd_scb_t httpd_system_callbacks =
{
@@ -3629,7 +2323,6 @@ static qse_httpd_scb_t httpd_system_callbacks =
dir_close,
dir_read
},
-
/* client connection */
{ client_close,
@@ -3640,7 +2333,6 @@ static qse_httpd_scb_t httpd_system_callbacks =
client_accepted,
client_closed },
-
/* dns */
{ dns_open,
dns_close,
@@ -3946,6 +2638,7 @@ static int make_resource (
target->type = QSE_HTTPD_RSRC_PROXY;
target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_RAW;
+ target->u.proxy.host = QSE_NULL;
if (qse_mbstonwad (qse_htre_getqpath(req), &target->u.proxy.dst.nwad) <= -1)
{
@@ -3959,7 +2652,7 @@ static int make_resource (
target->u.proxy.src.nwad.type = target->u.proxy.dst.nwad.type;
}
- /* pseudonym for raw proxying should not be useful. set it for consistency */
+ /* pseudonym for raw proxying should not be useful. but set it for consistency */
if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_PSEUDONYM, &target->u.proxy.pseudonym) <= -1)
target->u.proxy.pseudonym = QSE_NULL;
@@ -3976,7 +2669,6 @@ static int make_resource (
/* TODO: check if proxying is allowed.... */
qse_mchar_t* host, * slash;
- /*host = tmp.qpath + 6;*/
host = tmp.qpath + 6;
slash = qse_mbschr (host, QSE_MT('/'));
@@ -3985,15 +2677,16 @@ static int make_resource (
target->type = QSE_HTTPD_RSRC_PROXY;
target->u.proxy.flags = 0;
- if (qse_mbsntonwad (host, slash - host, &target->u.proxy.dst.nwad) <= -1)
- {
/* TODO: refrain from manipulating the request like this */
+ QSE_MEMMOVE (host - 1, host, slash - host);
+ slash[-1] = QSE_MT('\0');
+ host = host - 1;
+ target->u.proxy.host = host;
- QSE_MEMMOVE (host - 1, host, slash - host);
- slash[-1] = QSE_MT('\0');
-
+ if (qse_mbstonwad (host, &target->u.proxy.dst.nwad) <= -1)
+ {
target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_STR;
- target->u.proxy.dst.str = host - 1;
+ target->u.proxy.dst.str = host;
}
else
{
@@ -4009,6 +2702,12 @@ static int make_resource (
/* TODO: refrain from manipulating the request like this */
req->u.q.path = slash; /* TODO: use setqpath or something... */
+
+/******************************************************************/
+/*TODO: load this from configuration. reamove this after debugging */
+//target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS;
+/******************************************************************/
+
/* mark that this request is going to be proxied. */
req->attr.flags |= QSE_HTRE_ATTR_PROXIED;
return 0;
@@ -4022,7 +2721,8 @@ static int make_resource (
/* proxy the request */
target->type = QSE_HTTPD_RSRC_PROXY;
target->u.proxy.flags = 0;
-
+ target->u.proxy.host = QSE_NULL;
+
/* transparent proxy may do the following
target->u.proxy.dst = client->orgdst_addr;
target->u.proxy.src = client->remote_addr;
@@ -4585,7 +3285,7 @@ void* qse_httpd_getserverstdxtn (qse_httpd_t* httpd, qse_httpd_server_t* server)
/* ------------------------------------------------------------------- */
-int qse_httpd_loopstd (qse_httpd_t* httpd, const qse_httpd_dnsstd_t* dns)
+int qse_httpd_loopstd (qse_httpd_t* httpd, const qse_httpd_dnsstd_t* dns, const qse_httpd_ursstd_t* urs)
{
httpd_xtn_t* httpd_xtn = qse_httpd_getxtn (httpd);
@@ -4604,5 +3304,17 @@ int qse_httpd_loopstd (qse_httpd_t* httpd, const qse_httpd_dnsstd_t* dns)
httpd_xtn->dns.cache_negttl = QSE_HTTPD_DNSSTD_DEFAULT_CACHE_NEGTTL;
}
+ if (urs)
+ {
+ httpd_xtn->urs = *urs;
+ }
+ else
+ {
+ httpd_xtn->urs.nwad.type = QSE_NWAD_NX;
+ httpd_xtn->urs.tmout.sec = QSE_HTTPD_URSSTD_DEFAULT_TMOUT;
+ httpd_xtn->urs.tmout.nsec = 0;
+ httpd_xtn->urs.resends = QSE_HTTPD_URSSTD_DEFAULT_RESENDS;
+ }
+
return qse_httpd_loop (httpd);
}
diff --git a/qse/lib/http/httpd-text.c b/qse/lib/http/httpd-text.c
index e0a9db27..215ae877 100644
--- a/qse/lib/http/httpd-text.c
+++ b/qse/lib/http/httpd-text.c
@@ -65,6 +65,7 @@ static int task_main_text (
if (ctx->left <= 0) return 0;
ctx->ptr += n;
}
+
return 1; /* more work to do */
}
diff --git a/qse/lib/http/httpd.c b/qse/lib/http/httpd.c
index 2c176c6e..27da972a 100644
--- a/qse/lib/http/httpd.c
+++ b/qse/lib/http/httpd.c
@@ -382,7 +382,7 @@ static qse_htrd_recbs_t htrd_recbs =
};
/* ----------------------------------------------------------------------- */
-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_update (qse_tmr_t* tmr, qse_tmr_index_t old_index, qse_tmr_index_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)
@@ -398,22 +398,22 @@ static void mark_bad_client (qse_httpd_client_t* client)
static qse_httpd_client_t* new_client (qse_httpd_t* httpd, qse_httpd_client_t* tmpl)
{
- qse_httpd_client_t* client;
+ qse_httpd_client_t* client = QSE_NULL;
qse_tmr_event_t idle_event;
htrd_xtn_t* xtn;
client = qse_httpd_allocmem (httpd, QSE_SIZEOF(*client));
- if (client == QSE_NULL) return QSE_NULL;
+ if (client == QSE_NULL) goto oops;
QSE_MEMSET (client, 0, QSE_SIZEOF(*client));
+ client->tmr_idle = QSE_TMR_INVALID_INDEX;
client->type = QSE_HTTPD_CLIENT;
client->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(*xtn));
if (client->htrd == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ENOMEM;
- qse_httpd_freemem (httpd, client);
- return QSE_NULL;
+ goto oops;
}
qse_gettime (&idle_event.when);
@@ -422,15 +422,7 @@ static qse_httpd_client_t* new_client (qse_httpd_t* httpd, qse_httpd_client_t* t
idle_event.handler = tmr_idle_handle;
idle_event.updater = tmr_idle_update;
- client->tmr_idle = qse_tmr_insert (httpd->tmr, &idle_event);
- if (client->tmr_idle == QSE_TMR_INVALID)
- {
- httpd->errnum = QSE_HTTPD_ENOMEM;
- qse_htrd_close (client->htrd);
- qse_httpd_freemem (httpd, client);
- return QSE_NULL;
- }
-printf ("tmr_insert %d\n", (int)client->tmr_idle);
+ if (qse_httpd_inserttimerevent (httpd, &idle_event, &client->tmr_idle) <= -1) goto oops;
qse_htrd_setoption (client->htrd, QSE_HTRD_REQUEST | QSE_HTRD_TRAILERS | QSE_HTRD_CANONQPATH);
@@ -446,13 +438,27 @@ printf ("tmr_insert %d\n", (int)client->tmr_idle);
client->server = tmpl->server;
client->initial_ifindex = tmpl->initial_ifindex;
- xtn = (htrd_xtn_t*)qse_htrd_getxtn (client->htrd);
+ xtn = (htrd_xtn_t*)qse_htrd_getxtn (client->htrd);
xtn->httpd = httpd;
xtn->client = client;
qse_htrd_setrecbs (client->htrd, &htrd_recbs);
return client;
+
+oops:
+ if (client)
+ {
+ if (client->tmr_idle != QSE_TMR_INVALID_INDEX)
+ {
+ qse_httpd_removetimerevent (httpd, client->tmr_idle);
+ /* cleint->tmr_idle = QSE_TMR_INVALID_INDEX; */
+ }
+ if (client->htrd) qse_htrd_close (client->htrd);
+ qse_httpd_freemem (httpd, client);
+ }
+
+ return QSE_NULL;
}
static void free_client (
@@ -474,6 +480,12 @@ qse_printf (QSE_T("Debug: CLOSING SOCKET %d\n"), client->handle.i);
client->status &= ~CLIENT_HANDLE_RW_IN_MUX;
}
+ if (client->tmr_idle != QSE_TMR_INVALID_INDEX)
+ {
+ qse_httpd_removetimerevent (httpd, client->tmr_idle);
+ client->tmr_idle = QSE_TMR_INVALID_INDEX;
+ }
+
/* note that client.closed is not a counterpart to client.accepted.
* so it is called even if client.close() failed. */
if (httpd->opt.scb.client.closed)
@@ -481,12 +493,6 @@ qse_printf (QSE_T("Debug: CLOSING SOCKET %d\n"), client->handle.i);
httpd->opt.scb.client.close (httpd, client);
- if (client->tmr_idle != QSE_TMR_INVALID)
- {
- qse_tmr_remove (httpd->tmr, client->tmr_idle);
- client->tmr_idle = QSE_TMR_INVALID;
- }
-
qse_httpd_freemem (httpd, client);
}
@@ -618,7 +624,7 @@ printf ("MUX ADDHND CLIENT READ %d\n", client->handle.i);
}
-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_update (qse_tmr_t* tmr, qse_tmr_index_t old_index, qse_tmr_index_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);
@@ -645,6 +651,9 @@ printf ("client is idle purging....\n");
{
qse_tmr_event_t idle_event;
+printf ("client is NOT idle....\n");
+ QSE_ASSERT (client->server->httpd->tmr == tmr);
+
/*qse_gettime (&idle_event.when);*/
idle_event.when = *now;
qse_addtime (&idle_event.when, &client->server->httpd->opt.idle_limit, &idle_event.when);
@@ -653,11 +662,9 @@ printf ("client is idle purging....\n");
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);
- client->tmr_idle = qse_tmr_insert (tmr, &idle_event);
- if (client->tmr_idle == QSE_TMR_INVALID) mark_bad_client (client);
-
-printf ("client is not idle rescheduling.....%d\n", (int)client->tmr_idle);
+ QSE_ASSERT (client->tmr_idle == QSE_TMR_INVALID_INDEX);
+ if (qse_httpd_inserttimerevent (client->server->httpd, &idle_event, &client->tmr_idle) <= -1)
+ mark_bad_client (client);
}
}
}
@@ -1730,12 +1737,16 @@ printf ("DNS_SEND.........................\n");
return httpd->opt.scb.dns.send (httpd, &httpd->dns, name, resol, ctx);
}
-#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.urs.send (httpd, &httpd->dns, name, resol, ctx);
+ if (!httpd->ursactive)
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOURS);
+ return -1;
+ }
+
+ return httpd->opt.scb.urs.send (httpd, &httpd->urs, url, rewrite, ctx);
}
-#endif
int qse_httpd_activatetasktrigger (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
@@ -1770,3 +1781,20 @@ int qse_httpd_inactivatetasktrigger (qse_httpd_t* httpd, qse_httpd_client_t* cli
return update_mux_for_current_task (httpd, client, task);
}
+int qse_httpd_inserttimerevent (qse_httpd_t* httpd, const qse_tmr_event_t* event, qse_tmr_index_t* index)
+{
+ qse_tmr_index_t tmp = qse_tmr_insert (httpd->tmr, event);
+ if (tmp == QSE_TMR_INVALID_INDEX)
+ {
+ qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
+ return -1;
+ }
+
+ *index = tmp;
+ return 0;
+}
+
+void qse_httpd_removetimerevent (qse_httpd_t* httpd, qse_tmr_index_t index)
+{
+ qse_tmr_remove (httpd->tmr, index);
+}
diff --git a/qse/lib/http/httpd.h b/qse/lib/http/httpd.h
index c3d35dd4..38dda1de 100644
--- a/qse/lib/http/httpd.h
+++ b/qse/lib/http/httpd.h
@@ -161,6 +161,17 @@ int qse_httpd_inactivatetasktrigger (
qse_httpd_task_t* task
);
+int qse_httpd_inserttimerevent (
+ qse_httpd_t* httpd,
+ const qse_tmr_event_t* event,
+ qse_tmr_index_t* index
+);
+
+void qse_httpd_removetimerevent (
+ qse_httpd_t* httpd,
+ qse_tmr_index_t index
+);
+
#ifdef __cplusplus
}
#endif