|  |  |  | @ -543,6 +543,7 @@ struct httpd_xtn_t | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_ecb_t ecb; | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_dnsstd_t dns; | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_ursstd_t urs; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if defined(HAVE_SSL) | 
		
	
	
		
			
				
					
					|  |  |  | @ -2009,6 +2010,14 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* ------------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static qse_size_t hash_string (const qse_mchar_t *str) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_size_t h = 0; | 
		
	
		
			
				|  |  |  |  | 	while (*str) h = ((h << 5) + h) ^ *str++; | 
		
	
		
			
				|  |  |  |  | 	return h; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* ------------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  | #define DNS_MAX_DN_LEN 255 /* full domain name length in binary form (i.e. 3xyz2eu0) */ | 
		
	
	
		
			
				
					
					|  |  |  | @ -2017,6 +2026,8 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) | 
		
	
		
			
				|  |  |  |  | #define DNS_MIN_TTL 10 | 
		
	
		
			
				|  |  |  |  | #define DNS_MAX_TTL 120 /* TODO: make these configurable... */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #define DNS_SEQ_RANGE_SIZE ((QSE_TYPE_MAX(qse_uint16_t) / 2) - 2) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | typedef struct dns_ctx_t dns_ctx_t; | 
		
	
		
			
				|  |  |  |  | typedef struct dns_req_t dns_req_t; | 
		
	
		
			
				|  |  |  |  | typedef struct dns_ans_t dns_ans_t; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2109,7 +2120,6 @@ struct dns_antrail_t | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | #include <qse/unpack.h> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct dns_ctx_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_t* httpd; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2119,8 +2129,13 @@ struct dns_ctx_t | 
		
	
		
			
				|  |  |  |  | 	int skadlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t seq; | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* reqs[1024]; /* TOOD: choose the right size */ | 
		
	
		
			
				|  |  |  |  | 	dns_ans_t* anss[1024]; | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* reqs[2048]; /* TOOD: choose the right size or make it configurable. must be < DNS_SEQ_RANGE_SIZE */ | 
		
	
		
			
				|  |  |  |  | 	dns_ans_t* anss[2048]; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t req_count; /* the number of pending requests */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t n_qcin; /* DNS_QCLASS_IN in network byte order */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t n_qta; /* DNS_QTYPE_A in network byte order */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t n_qtaaaa; /* DNS_QTYPE_AAAA in network byte order */ | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct dns_req_t | 
		
	
	
		
			
				
					
					|  |  |  | @ -2148,11 +2163,18 @@ struct dns_req_t | 
		
	
		
			
				|  |  |  |  | 	int resends; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* next; | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* prev; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct dns_ans_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	/* the name part must be the same as dns_req_t */ | 
		
	
		
			
				|  |  |  |  | 	qse_mchar_t* name;  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* the total size of data fields below must not be greater than | 
		
	
		
			
				|  |  |  |  | 	 * the total size of data fields of dns_req_t excluding name.  | 
		
	
		
			
				|  |  |  |  | 	 * this condition is required for reusing the dns_req_t chunk | 
		
	
		
			
				|  |  |  |  | 	 * when caching an answer without allocating another chunk. */ | 
		
	
		
			
				|  |  |  |  | 	qse_nwad_t nwad; | 
		
	
		
			
				|  |  |  |  | 	qse_int64_t age; | 
		
	
		
			
				|  |  |  |  | 	qse_uint32_t ttl; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2270,6 +2292,9 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dc->httpd = httpd; | 
		
	
		
			
				|  |  |  |  | 	dc->dns = dns; | 
		
	
		
			
				|  |  |  |  | 	dc->n_qcin = qse_hton16(DNS_QCLASS_IN); | 
		
	
		
			
				|  |  |  |  | 	dc->n_qta = qse_hton16(DNS_QTYPE_A); | 
		
	
		
			
				|  |  |  |  | 	dc->n_qtaaaa = qse_hton16(DNS_QTYPE_AAAA); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: add static cache entries from /etc/hosts */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -2314,7 +2339,7 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (qse_getnwadport(&nwad) == 0)  | 
		
	
		
			
				|  |  |  |  | 		qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DEFAULT_DNS_PORT)); | 
		
	
		
			
				|  |  |  |  | 		qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DNSSTD_DEFAULT_PORT)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dc->skadlen = qse_nwadtoskad (&nwad, &dc->skad); | 
		
	
		
			
				|  |  |  |  | 	if (dc->skadlen <= -1) | 
		
	
	
		
			
				
					
					|  |  |  | @ -2359,6 +2384,7 @@ static int dns_open (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dns->handle.i = fd; | 
		
	
		
			
				|  |  |  |  | 	dns->ctx = dc; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | oops: | 
		
	
	
		
			
				
					
					|  |  |  | @ -2392,9 +2418,12 @@ static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  | 			dns_remove_tmr_tmout (dc->reqs[i]); | 
		
	
		
			
				|  |  |  |  | 			qse_httpd_freemem (httpd, dc->reqs[i]); | 
		
	
		
			
				|  |  |  |  | 			dc->reqs[i] = next_req; | 
		
	
		
			
				|  |  |  |  | 			dc->req_count--; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (dc->req_count == 0); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	for (i = 0; i < QSE_COUNTOF(dc->anss); i++) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		dns_ans_t* next_ans; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2406,25 +2435,11 @@ static void dns_close (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if defined(_WIN32) | 
		
	
		
			
				|  |  |  |  | 	closesocket (dns->handle.i); | 
		
	
		
			
				|  |  |  |  | #elif defined(__OS2__) | 
		
	
		
			
				|  |  |  |  | 	soclose (dns->handle.i); | 
		
	
		
			
				|  |  |  |  | #elif defined(__DOS__) | 
		
	
		
			
				|  |  |  |  | 	/* TODO: */ | 
		
	
		
			
				|  |  |  |  | #else | 
		
	
		
			
				|  |  |  |  | 	QSE_CLOSE (dns->handle.i); | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	close_socket (dns->handle.i); | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_freemem (httpd, dns->ctx); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static unsigned long dns_hash_name (const qse_mchar_t *str) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_size_t h = 0; | 
		
	
		
			
				|  |  |  |  | 	while (*str) h = ((h << 5) + h) ^ *str++; | 
		
	
		
			
				|  |  |  |  | 	return h; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* nwad, qse_uint32_t ttl) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
	
		
			
				
					
					|  |  |  | @ -2441,6 +2456,10 @@ static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* n | 
		
	
		
			
				|  |  |  |  | 	qse_gettime (&now); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ans = (dns_ans_t*)req; /* shadow the request with an answer */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* reuse the data fields of the request except the name field. | 
		
	
		
			
				|  |  |  |  | 	 * from here downwards, the data fields of the request are invalid. */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (nwad) ans->nwad = *nwad; /* positive */ | 
		
	
		
			
				|  |  |  |  | 	else ans->nwad.type = QSE_NWAD_NX; /* negative */ | 
		
	
		
			
				|  |  |  |  | 	ans->age = now.sec; /* the granularity of a second should be good enough */ | 
		
	
	
		
			
				
					
					|  |  |  | @ -2449,7 +2468,7 @@ static void dns_cache_answer (dns_ctx_t* dc, dns_req_t* req, const qse_nwad_t* n | 
		
	
		
			
				|  |  |  |  | 	else if (ttl > DNS_MAX_TTL) ttl = DNS_MAX_TTL; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ans->ttl = ttl; | 
		
	
		
			
				|  |  |  |  | 	hid = dns_hash_name (req->name) % QSE_COUNTOF(dc->anss); | 
		
	
		
			
				|  |  |  |  | 	hid = hash_string (req->name) % QSE_COUNTOF(dc->anss); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	prv = QSE_NULL; | 
		
	
		
			
				|  |  |  |  | 	cur = dc->anss[hid]; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2477,7 +2496,7 @@ static dns_ans_t* dns_get_answer_from_cache (dns_ctx_t* dc, const qse_mchar_t* n | 
		
	
		
			
				|  |  |  |  | 	qse_size_t hid; | 
		
	
		
			
				|  |  |  |  | 	qse_ntime_t now; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	hid = dns_hash_name (name) % QSE_COUNTOF(dc->anss); | 
		
	
		
			
				|  |  |  |  | 	hid = hash_string(name) % QSE_COUNTOF(dc->anss); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_gettime (&now); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -2518,6 +2537,19 @@ static int dns_recv (qse_httpd_t* httpd, qse_httpd_dns_t* dns) | 
		
	
		
			
				|  |  |  |  | 	qse_ssize_t len; | 
		
	
		
			
				|  |  |  |  | 	dns_hdr_t* hdr; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t id, qdcount, ancount, i; | 
		
	
		
			
				|  |  |  |  | 	qse_uint8_t* plptr; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t pllen; | 
		
	
		
			
				|  |  |  |  | 	dns_qdtrail_t* qdtrail; | 
		
	
		
			
				|  |  |  |  | 	dns_antrail_t* antrail; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t anlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* req = QSE_NULL; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid = QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  | 	qse_nwad_t nwad; | 
		
	
		
			
				|  |  |  |  | 	qse_nwad_t* resolved_nwad = QSE_NULL; | 
		
	
		
			
				|  |  |  |  | 	int cache_ttl = 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("DNS_RECV....\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn = qse_httpd_getxtn (httpd); | 
		
	
	
		
			
				
					
					|  |  |  | @ -2527,69 +2559,80 @@ printf ("DNS_RECV....\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: check if fromaddr matches the dc->skad... */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (len >= QSE_SIZEOF(*hdr)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_uint16_t id, qdcount, ancount, xid; | 
		
	
		
			
				|  |  |  |  | 	if (len < QSE_SIZEOF(*hdr)) goto done; /* packet too small */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	hdr = (dns_hdr_t*)buf; | 
		
	
		
			
				|  |  |  |  | 		id = qse_ntoh16(hdr->id); | 
		
	
		
			
				|  |  |  |  | 	qdcount = qse_ntoh16(hdr->qdcount); | 
		
	
		
			
				|  |  |  |  | 		ancount = qse_ntoh16(hdr->ancount); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		xid = (id >= QSE_COUNTOF(dc->reqs))? (id - QSE_COUNTOF(dc->reqs)): id; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (xid >= 0 && xid < QSE_COUNTOF(dc->reqs) && hdr->qr && hdr->opcode == DNS_OPCODE_QUERY && qdcount >= 1) | 
		
	
		
			
				|  |  |  |  | 	if (!hdr->qr || hdr->opcode != DNS_OPCODE_QUERY || qdcount <= 0)  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 			qse_uint8_t* plptr = (qse_uint8_t*)(hdr + 1); | 
		
	
		
			
				|  |  |  |  | 			qse_size_t pllen = len - QSE_SIZEOF(*hdr); | 
		
	
		
			
				|  |  |  |  | 			qse_uint8_t i, dnlen; | 
		
	
		
			
				|  |  |  |  | 			dns_req_t* req = QSE_NULL, * preq = QSE_NULL; | 
		
	
		
			
				|  |  |  |  | 			qse_size_t reclen; | 
		
	
		
			
				|  |  |  |  | 		/* not a response to a query */ | 
		
	
		
			
				|  |  |  |  | 		goto done; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ancount = qse_ntoh16(hdr->ancount); | 
		
	
		
			
				|  |  |  |  | 	id = qse_ntoh16(hdr->id); | 
		
	
		
			
				|  |  |  |  | 	xid = (id >= DNS_SEQ_RANGE_SIZE)? (id - DNS_SEQ_RANGE_SIZE): id; | 
		
	
		
			
				|  |  |  |  | 	xid = xid % QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	plptr = (qse_uint8_t*)(hdr + 1); | 
		
	
		
			
				|  |  |  |  | 	pllen = len - QSE_SIZEOF(*hdr); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* inspect the question section */ | 
		
	
		
			
				|  |  |  |  | 	for (i = 0; i < qdcount; i++) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_size_t reclen; | 
		
	
		
			
				|  |  |  |  | 		qse_uint8_t dnlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		dnlen = dn_length (plptr, pllen); | 
		
	
		
			
				|  |  |  |  | 		if (dnlen <= 0) goto done; /* invalid dn name */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		reclen = dnlen + QSE_SIZEOF(dns_qdtrail_t); | 
		
	
		
			
				|  |  |  |  | 				if (pllen < reclen) goto done; | 
		
	
		
			
				|  |  |  |  | 		if (pllen < reclen) goto done; /* weird packet */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (!req) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 					dns_qdtrail_t* qdtrail = (dns_qdtrail_t*)(plptr + dnlen); | 
		
	
		
			
				|  |  |  |  | 					for (preq = QSE_NULL, req = dc->reqs[xid]; req; preq = req, req = req->next) | 
		
	
		
			
				|  |  |  |  | 			qdtrail = (dns_qdtrail_t*)(plptr + dnlen); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			if (qdtrail->qclass == dc->n_qcin && | 
		
	
		
			
				|  |  |  |  | 			    (qdtrail->qtype == dc->n_qta || qdtrail->qtype == dc->n_qtaaaa)) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 						if (req->dnlen == dnlen &&  | 
		
	
		
			
				|  |  |  |  | 						    QSE_MEMCMP (req->dn, plptr, req->dnlen) == 0 && | 
		
	
		
			
				|  |  |  |  | 						    qdtrail->qclass == qse_hton16(DNS_QCLASS_IN) && | 
		
	
		
			
				|  |  |  |  | 						    (qdtrail->qtype == qse_hton16(DNS_QTYPE_A) || qdtrail->qtype == qse_hton16(DNS_QTYPE_AAAA))) | 
		
	
		
			
				|  |  |  |  | 				for (req = dc->reqs[xid]; req; req = req->next) | 
		
	
		
			
				|  |  |  |  | 				{ | 
		
	
		
			
				|  |  |  |  | 							/* found a matching request */ | 
		
	
		
			
				|  |  |  |  | 					if ((id == req->seqa || id == req->seqaaaa) && | 
		
	
		
			
				|  |  |  |  | 					    req->dnlen == dnlen && QSE_MEMCMP (req->dn, plptr, req->dnlen) == 0)  | 
		
	
		
			
				|  |  |  |  | 					{ | 
		
	
		
			
				|  |  |  |  | 						/* found a match. note that the test here is a bit loose | 
		
	
		
			
				|  |  |  |  | 						 * in that it doesn't really check if the original question  | 
		
	
		
			
				|  |  |  |  | 						 * was A or AAAA. it is possible that it can process an AAAA answer | 
		
	
		
			
				|  |  |  |  | 						 * for an A question and vice versa. i don't care if someone | 
		
	
		
			
				|  |  |  |  | 						 * exploits this and sends a fake response*/ | 
		
	
		
			
				|  |  |  |  | 						break; | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  | 				} | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		plptr += reclen;  | 
		
	
		
			
				|  |  |  |  | 		pllen -= reclen; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (!req) goto done; /* no matching request for the question */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			if (hdr->rcode == DNS_RCODE_NOERROR && ancount > 0) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				dns_antrail_t* antrail; | 
		
	
		
			
				|  |  |  |  | 				qse_uint16_t qtype, anlen; | 
		
	
		
			
				|  |  |  |  | 	if (hdr->rcode != DNS_RCODE_NOERROR || ancount <= 0) goto done; /* no good answers */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* inspect the answer section */ | 
		
	
		
			
				|  |  |  |  | 	for (i = 0; i < ancount; i++) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 					if (pllen < 1) goto done; | 
		
	
		
			
				|  |  |  |  | 		qse_size_t reclen; | 
		
	
		
			
				|  |  |  |  | 		qse_uint8_t dnlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (pllen < 1) goto done; /* weird length */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (*plptr > 63) dnlen = 2; | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			dnlen = dn_length (plptr, pllen); | 
		
	
		
			
				|  |  |  |  | 						if (dnlen <= 0) goto done; /* invalid dn name */ | 
		
	
		
			
				|  |  |  |  | 			if (dnlen <= 0) return 0; /* invalid dn name */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		reclen = dnlen + QSE_SIZEOF(dns_antrail_t); | 
		
	
	
		
			
				
					
					|  |  |  | @ -2599,55 +2642,39 @@ printf ("DNS_RECV....\n"); | 
		
	
		
			
				|  |  |  |  | 		reclen += qse_ntoh16(antrail->dlen); | 
		
	
		
			
				|  |  |  |  | 		if (pllen < reclen) goto done; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					qtype = qse_ntoh16(antrail->qtype); | 
		
	
		
			
				|  |  |  |  | 		anlen = qse_ntoh16(antrail->dlen); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 					if (qse_ntoh16(antrail->qclass) == DNS_QCLASS_IN) | 
		
	
		
			
				|  |  |  |  | 		if (antrail->qclass == dc->n_qcin) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 						qse_nwad_t nwad; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			nwad.type = QSE_NWAD_NX; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 						if (qtype == DNS_QTYPE_A && anlen == 4) | 
		
	
		
			
				|  |  |  |  | 			if (antrail->qtype == dc->n_qta && anlen == 4) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				QSE_MEMSET (&nwad, 0, QSE_SIZEOF(nwad)); | 
		
	
		
			
				|  |  |  |  | 				nwad.type = QSE_NWAD_IN4; | 
		
	
		
			
				|  |  |  |  | 				QSE_MEMCPY (&nwad.u.in4.addr, antrail + 1, 4); | 
		
	
		
			
				|  |  |  |  | printf ("invoking resoll with ipv4 \n"); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 						else if (qtype == DNS_QTYPE_AAAA && anlen == 16) | 
		
	
		
			
				|  |  |  |  | 			else if (antrail->qtype == dc->n_qtaaaa && anlen == 16) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				QSE_MEMSET (&nwad, 0, QSE_SIZEOF(nwad)); | 
		
	
		
			
				|  |  |  |  | 				nwad.type = QSE_NWAD_IN6; | 
		
	
		
			
				|  |  |  |  | 				QSE_MEMCPY (&nwad.u.in6.addr, antrail + 1, 16); | 
		
	
		
			
				|  |  |  |  | printf ("invoking resoll with ipv6 \n"); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			if (nwad.type != QSE_NWAD_NX) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 							int ttl; | 
		
	
		
			
				|  |  |  |  | 				cache_ttl = httpd_xtn->dns.cache_ttl; | 
		
	
		
			
				|  |  |  |  | 				if (cache_ttl > qse_ntoh32(antrail->ttl)) cache_ttl = qse_ntoh32(antrail->ttl); | 
		
	
		
			
				|  |  |  |  | 				if (cache_ttl < httpd_xtn->dns.cache_minttl) cache_ttl = httpd_xtn->dns.cache_minttl; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 							dns_remove_tmr_tmout (req); | 
		
	
		
			
				|  |  |  |  | 							req->resol (httpd, req->name, &nwad, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 							/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 							if (preq) preq->next = req->next; | 
		
	
		
			
				|  |  |  |  | 							else dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 							/*qse_httpd_freemem (httpd, req);*/ | 
		
	
		
			
				|  |  |  |  | 							ttl = httpd_xtn->dns.cache_ttl; | 
		
	
		
			
				|  |  |  |  | 							if (ttl > qse_ntoh32(antrail->ttl)) ttl = qse_ntoh32(antrail->ttl); | 
		
	
		
			
				|  |  |  |  | 							if (ttl < httpd_xtn->dns.cache_minttl) ttl = httpd_xtn->dns.cache_minttl; | 
		
	
		
			
				|  |  |  |  | 							dns_cache_answer (dc, req, &nwad, ttl); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 							goto done; | 
		
	
		
			
				|  |  |  |  | 				resolved_nwad = &nwad; | 
		
	
		
			
				|  |  |  |  | 				goto resolved; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		plptr += reclen; | 
		
	
		
			
				|  |  |  |  | 		pllen -= reclen; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* no good answer have been found */ | 
		
	
		
			
				|  |  |  |  | 	if (id == req->seqa) req->flags |= DNS_REQ_A_NX; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2656,24 +2683,35 @@ printf ("invoking resoll with ipv6 \n"); | 
		
	
		
			
				|  |  |  |  | 	if ((req->flags & (DNS_REQ_A_NX | DNS_REQ_AAAA_NX)) == (DNS_REQ_A_NX | DNS_REQ_AAAA_NX)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* both ipv4 and ipv6 address are unresolvable */ | 
		
	
		
			
				|  |  |  |  | 				dns_remove_tmr_tmout (req); | 
		
	
		
			
				|  |  |  |  | 				req->resol (httpd, req->name, QSE_NULL, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 				if (preq) preq->next = req->next; | 
		
	
		
			
				|  |  |  |  | 				else dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				/*qse_httpd_freemem (httpd, req);*/ | 
		
	
		
			
				|  |  |  |  | 				dns_cache_answer (dc, req, QSE_NULL, httpd_xtn->dns.cache_negttl); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		cache_ttl = httpd_xtn->dns.cache_negttl; | 
		
	
		
			
				|  |  |  |  | 		resolved_nwad = QSE_NULL; | 
		
	
		
			
				|  |  |  |  | 		goto resolved; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | done: | 
		
	
		
			
				|  |  |  |  | 	/* is there anything to do here? */ | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | resolved: | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (req != QSE_NULL); | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (xid >= 0 && xid < QSE_COUNTOF(dc->reqs)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dns_remove_tmr_tmout (req); | 
		
	
		
			
				|  |  |  |  | 	req->resol (httpd, req->name, resolved_nwad, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 	if (req == dc->reqs[xid]) dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  | 	else req->prev->next = req->next; | 
		
	
		
			
				|  |  |  |  | 	if (req->next) req->next->prev = req->prev; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* cache the negative answer instead of destroying it */ | 
		
	
		
			
				|  |  |  |  | 	dns_cache_answer (dc, req, resolved_nwad, cache_ttl); | 
		
	
		
			
				|  |  |  |  | 	dc->req_count--; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void tmr_dns_tmout_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx) | 
		
	
		
			
				|  |  |  |  | static void tmr_dns_tmout_update (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* req = (dns_req_t*)ctx; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -2687,34 +2725,36 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* | 
		
	
		
			
				|  |  |  |  | 	/* destory the unanswered request if timed out */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* req = (dns_req_t*)ctx; | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* preq, * xreq; | 
		
	
		
			
				|  |  |  |  | 	dns_ctx_t* dc = req->dc; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* when this handler is called, the event should be removed from the timer */ | 
		
	
		
			
				|  |  |  |  | 	/* when this handler is called, the event must be removed from the timer */ | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: resend?? + reschedule?? */ | 
		
	
		
			
				|  |  |  |  | 	/* --------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  | 	 * resend  | 
		
	
		
			
				|  |  |  |  | 	 *---------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  | 	if (req->resends > 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  | 		qse_tmr_event_t tmout_event; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		httpd_xtn = qse_httpd_getxtn (req->dc->httpd); | 
		
	
		
			
				|  |  |  |  | 		httpd_xtn = qse_httpd_getxtn (dc->httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		qse_gettime (&tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 		qse_addtime (&tmout_event.when, &httpd_xtn->dns.tmout, &tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 		tmout_event.ctx = req; | 
		
	
		
			
				|  |  |  |  | 		tmout_event.handler = tmr_dns_tmout_handle; | 
		
	
		
			
				|  |  |  |  | 		tmout_event.updater = tmr_dns_tmout_updated; | 
		
	
		
			
				|  |  |  |  | 		tmout_event.updater = tmr_dns_tmout_update; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if ((!(req->flags & DNS_REQ_A_NX) && req->qalen > 0 && sendto (req->dc->dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&req->dc->skad, req->dc->skadlen) != req->qalen) || | 
		
	
		
			
				|  |  |  |  | 			(!(req->flags & DNS_REQ_AAAA_NX) && req->qaaaalen > 0 && sendto (req->dc->dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&req->dc->skad, req->dc->skadlen) != req->qaaaalen)) | 
		
	
		
			
				|  |  |  |  | 		if ((!(req->flags & DNS_REQ_A_NX) && req->qalen > 0 && sendto (dc->dns->handle.i, req->qa, req->qalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qalen) || | 
		
	
		
			
				|  |  |  |  | 			(!(req->flags & DNS_REQ_AAAA_NX) && req->qaaaalen > 0 && sendto (dc->dns->handle.i, req->qaaaa, req->qaaaalen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->qaaaalen)) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* error. fall thru */ | 
		
	
		
			
				|  |  |  |  | 			/* resend failed. fall thru and destroy the request*/ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			req->tmr_tmout = qse_tmr_insert (req->dc->httpd->tmr, &tmout_event); | 
		
	
		
			
				|  |  |  |  | 			req->tmr_tmout = qse_tmr_insert (dc->httpd->tmr, &tmout_event); | 
		
	
		
			
				|  |  |  |  | 			if (req->tmr_tmout != QSE_TMR_INVALID) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				req->resends--; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2723,27 +2763,27 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("dns timed out....\n"); | 
		
	
		
			
				|  |  |  |  | 	xid = req->seqa;  | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (xid >= 0 && QSE_COUNTOF(req->dc->reqs)); | 
		
	
		
			
				|  |  |  |  | /* TODO: doubly linked list??? speed up ??? */ | 
		
	
		
			
				|  |  |  |  | 	for (preq = QSE_NULL, xreq = req->dc->reqs[xid]; xreq; preq = xreq, xreq = xreq->next) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if (req == xreq) break; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	/* --------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  | 	 * dns timed out + no resend  | 
		
	
		
			
				|  |  |  |  | 	 *---------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* this request that timed out must be inside the request list */ | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (req == xreq); | 
		
	
		
			
				|  |  |  |  | 	/* it's safe to use req->seqa to find the hash index | 
		
	
		
			
				|  |  |  |  | 	 * because seqa is always set regardless of A or AAAA */ | 
		
	
		
			
				|  |  |  |  | 	xid = req->seqa % QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 	if (preq) preq->next = req->next; | 
		
	
		
			
				|  |  |  |  | 	else req->dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  | 	if (req == dc->reqs[xid]) dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  | 	else req->prev->next = req->next; | 
		
	
		
			
				|  |  |  |  | 	if (req->next) req->next->prev = req->prev; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* dns timed out. report that name resolution failed */ | 
		
	
		
			
				|  |  |  |  | 	req->resol (req->dc->httpd, req->name, QSE_NULL, req->ctx); | 
		
	
		
			
				|  |  |  |  | 	req->resol (dc->httpd, req->name, QSE_NULL, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* i don't cache the items that have timed out */ | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_freemem (req->dc->httpd, req); | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_freemem (dc->httpd, req); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* decrement the number of pending requests */ | 
		
	
		
			
				|  |  |  |  | 	dc->req_count--; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t* name, qse_httpd_resol_t resol, void* ctx) | 
		
	
	
		
			
				
					
					|  |  |  | @ -2752,6 +2792,7 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint32_t seq; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid; | 
		
	
		
			
				|  |  |  |  | 	dns_req_t* req; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t name_len; | 
		
	
		
			
				|  |  |  |  | 	dns_ans_t* ans; | 
		
	
	
		
			
				
					
					|  |  |  | @ -2760,6 +2801,7 @@ static int dns_send (qse_httpd_t* httpd, qse_httpd_dns_t* dns, const qse_mchar_t | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn = qse_httpd_getxtn (httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ans = dns_get_answer_from_cache (dc, name); | 
		
	
		
			
				|  |  |  |  | 	if (ans) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
	
		
			
				
					
					|  |  |  | @ -2767,10 +2809,18 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 		return 0; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	seq = dc->seq; | 
		
	
		
			
				|  |  |  |  | 	seq = (seq + 1) % QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  | 	if (dc->req_count >= QSE_COUNTOF(dc->reqs)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* too many pending requests */ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	seq = ((qse_uint32_t)dc->seq + 1) % DNS_SEQ_RANGE_SIZE; | 
		
	
		
			
				|  |  |  |  | 	dc->seq = seq; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	xid = seq % QSE_COUNTOF(dc->reqs);  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	name_len = qse_mbslen(name); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* dn is at most as long as the source length + 2. | 
		
	
	
		
			
				
					
					|  |  |  | @ -2779,8 +2829,10 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 	req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + (name_len + 1) + (name_len + 2)); | 
		
	
		
			
				|  |  |  |  | 	if (req == QSE_NULL) return -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* seqa is between 0 and DNS_SEQ_RANGE_SIZE - 1 inclusive. | 
		
	
		
			
				|  |  |  |  | 	 * seqaaaa is between DNS_SEQ_RANGE_SIZE and DNS_SEQ_RANGE_SIZE * 2 - 1 inclusive. */ | 
		
	
		
			
				|  |  |  |  | 	req->seqa = seq; | 
		
	
		
			
				|  |  |  |  | 	req->seqaaaa = seq + QSE_COUNTOF(dc->reqs); /* this must not go beyond the qse_uint16_t max */ | 
		
	
		
			
				|  |  |  |  | 	req->seqaaaa = seq + DNS_SEQ_RANGE_SIZE; /* this must not go beyond QSE_TYPE_MAX(qse_uint16_t) */ | 
		
	
		
			
				|  |  |  |  | 	req->name = (qse_mchar_t*)(req + 1); | 
		
	
		
			
				|  |  |  |  | 	req->dn = (qse_uint8_t*)(req->name + name_len + 1); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @ -2816,12 +2868,12 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 	qse_addtime (&tmout_event.when, &httpd_xtn->dns.tmout, &tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 	tmout_event.ctx = req; | 
		
	
		
			
				|  |  |  |  | 	tmout_event.handler = tmr_dns_tmout_handle; | 
		
	
		
			
				|  |  |  |  | 	tmout_event.updater = tmr_dns_tmout_updated; | 
		
	
		
			
				|  |  |  |  | 	tmout_event.updater = tmr_dns_tmout_update; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req->tmr_tmout = qse_tmr_insert (httpd->tmr, &tmout_event); | 
		
	
		
			
				|  |  |  |  | 	if (req->tmr_tmout == QSE_TMR_INVALID) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_freemem (httpd, req); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
	
		
			
				
					
					|  |  |  | @ -2837,14 +2889,443 @@ printf ("DNS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* NOTE:  | 
		
	
		
			
				|  |  |  |  | 	 *  if the sequence number is repeated before it timed out or resolved, | 
		
	
		
			
				|  |  |  |  | 	 *  the newer request gets chained together with the older one. | 
		
	
		
			
				|  |  |  |  | 	 *  it may not be so easy to determine which request to match an incoming  | 
		
	
		
			
				|  |  |  |  | 	 *  response.  | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	req->dc = dc; | 
		
	
		
			
				|  |  |  |  | 	req->next = dc->reqs[seq]; | 
		
	
		
			
				|  |  |  |  | 	dc->reqs[seq] = req; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* link the request to the front of the chain */ | 
		
	
		
			
				|  |  |  |  | 	if (dc->reqs[xid]) dc->reqs[xid]->prev = req; | 
		
	
		
			
				|  |  |  |  | 	req->next = dc->reqs[xid]; | 
		
	
		
			
				|  |  |  |  | 	dc->reqs[xid] = req; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* increment the number of pending requests */ | 
		
	
		
			
				|  |  |  |  | 	dc->req_count++; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("DNS REALLY SENT>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* ------------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #define URS_SEQ_RANGE_SIZE (QSE_TYPE_MAX(qse_uint16_t) - 2) | 
		
	
		
			
				|  |  |  |  | #define URS_MAX_URL_LEN 50000 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | typedef struct urs_hdr_t urs_hdr_t; | 
		
	
		
			
				|  |  |  |  | typedef struct urs_pkt_t urs_pkt_t; | 
		
	
		
			
				|  |  |  |  | typedef struct urs_ctx_t urs_ctx_t; | 
		
	
		
			
				|  |  |  |  | typedef struct urs_req_t urs_req_t; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #include <qse/pack1.h> | 
		
	
		
			
				|  |  |  |  | struct urs_hdr_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t seq; /* in network-byte order */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t rcode; /* response code */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint32_t qusum;/* checksum of url in the request */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t len; /* url length in network-byte order */ | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct urs_pkt_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	struct urs_hdr_t hdr; | 
		
	
		
			
				|  |  |  |  | 	qse_mchar_t url[1]; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | #include <qse/unpack.h> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct urs_ctx_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_t* httpd; | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_urs_t* urs; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_skad_t skad; | 
		
	
		
			
				|  |  |  |  | 	int skadlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t seq; /* TODO: change to uint32_t??? */ | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* reqs[1024]; /* TOOD: choose the right size */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t req_count; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint8_t rcvbuf[URS_MAX_URL_LEN + QSE_SIZEOF(urs_pkt_t)]; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | struct urs_req_t | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t seq; /* in host-byte order */ | 
		
	
		
			
				|  |  |  |  | 	qse_uint32_t pktlen; | 
		
	
		
			
				|  |  |  |  | 	urs_pkt_t* pkt; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_rewrite_t rewrite; | 
		
	
		
			
				|  |  |  |  | 	void* ctx; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t tmr_tmout; | 
		
	
		
			
				|  |  |  |  | 	int resends; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* prev; | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* next; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | int init_urs_query (qse_uint8_t* buf, qse_size_t len, const qse_mchar_t* name, qse_uint16_t seq) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	urs_hdr_t* hdr; | 
		
	
		
			
				|  |  |  |  | 	urs_qdtrail_t* qdtrail; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t x; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (len < QSE_SIZEOF(*hdr)) return -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	QSE_MEMSET (buf, 0, len); | 
		
	
		
			
				|  |  |  |  | 	hdr = (urs_hdr_t*)buf; | 
		
	
		
			
				|  |  |  |  | 	hdr->id = qse_hton16(seq); | 
		
	
		
			
				|  |  |  |  | 	hdr->opcode = URS_OPCODE_QUERY;  | 
		
	
		
			
				|  |  |  |  | 	hdr->rd = 1;  /* recursion desired*/ | 
		
	
		
			
				|  |  |  |  | 	hdr->qdcount = qse_hton16(1); /* 1 question */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	len -= QSE_SIZEOF(*hdr); | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	x = to_dn (name, (qse_uint8_t*)(hdr + 1), len); | 
		
	
		
			
				|  |  |  |  | 	if (x <= 0) return -1; | 
		
	
		
			
				|  |  |  |  | 	len -= x; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (len < QSE_SIZEOF(*qdtrail)) return -1; | 
		
	
		
			
				|  |  |  |  | 	qdtrail = (urs_qdtrail_t*)((qse_uint8_t*)(hdr + 1) + x); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qdtrail->qtype = qse_hton16(qtype); | 
		
	
		
			
				|  |  |  |  | 	qdtrail->qclass = qse_hton16(URS_QCLASS_IN); | 
		
	
		
			
				|  |  |  |  | 	return QSE_SIZEOF(*hdr) + x + QSE_SIZEOF(*qdtrail); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int urs_open (qse_httpd_t* httpd, qse_httpd_urs_t* urs) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | #if defined(__DOS__) | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
		
			
				|  |  |  |  | #else | 
		
	
		
			
				|  |  |  |  | 	sock_t fd = SOCK_INIT;  | 
		
	
		
			
				|  |  |  |  | 	int flag; | 
		
	
		
			
				|  |  |  |  | 	qse_nwad_t nwad; | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc; | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn = qse_httpd_getxtn (httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dc = (urs_ctx_t*) qse_httpd_callocmem (httpd, QSE_SIZEOF(urs_ctx_t)); | 
		
	
		
			
				|  |  |  |  | 	if (dc == NULL) goto oops; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dc->httpd = httpd; | 
		
	
		
			
				|  |  |  |  | 	dc->urs = urs; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	nwad = httpd_xtn->urs.nwad; | 
		
	
		
			
				|  |  |  |  | 	if (nwad.type == QSE_NWAD_NX) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (qse_getnwadport(&nwad) == 0)  | 
		
	
		
			
				|  |  |  |  | 		qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_URSSTD_DEFAULT_PORT)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	dc->skadlen = qse_nwadtoskad (&nwad, &dc->skad); | 
		
	
		
			
				|  |  |  |  | 	if (dc->skadlen <= -1) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (httpd->opt.trait & QSE_HTTPD_LOGACT) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_act_t msg; | 
		
	
		
			
				|  |  |  |  | 		qse_size_t pos; | 
		
	
		
			
				|  |  |  |  | 		msg.code = QSE_HTTPD_CATCH_MDBGMSG; | 
		
	
		
			
				|  |  |  |  | 		pos = qse_mbsxcpy (msg.u.mdbgmsg, QSE_COUNTOF(msg.u.mdbgmsg), "ursserver set to "); | 
		
	
		
			
				|  |  |  |  | 		qse_nwadtombs (&nwad, &msg.u.mdbgmsg[pos], QSE_COUNTOF(msg.u.mdbgmsg) - pos, QSE_NWADTOMBS_ALL); | 
		
	
		
			
				|  |  |  |  | 		httpd->opt.rcb.logact (httpd, &msg); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	fd = socket (qse_skadfamily(&dc->skad), SOCK_DGRAM, IPPROTO_UDP); | 
		
	
		
			
				|  |  |  |  | 	if (!is_valid_socket(fd))  | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 
		
	
		
			
				|  |  |  |  | 		goto oops; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: set socket send/recv buffer size. it's needed as urs may be long */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	#if defined(FD_CLOEXEC) | 
		
	
		
			
				|  |  |  |  | 	flag = fcntl (fd, F_GETFD); | 
		
	
		
			
				|  |  |  |  | 	if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); | 
		
	
		
			
				|  |  |  |  | 	#endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	#if defined(SO_REUSEADDR) | 
		
	
		
			
				|  |  |  |  | 	flag = 1; | 
		
	
		
			
				|  |  |  |  | 	setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void*)&flag, QSE_SIZEOF(flag)); | 
		
	
		
			
				|  |  |  |  | 	#endif | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	#if defined(SO_REUSEPORT) | 
		
	
		
			
				|  |  |  |  | 	flag = 1; | 
		
	
		
			
				|  |  |  |  | 	setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void*)&flag, QSE_SIZEOF(flag)); | 
		
	
		
			
				|  |  |  |  | 	#endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	urs->handle.i = fd; | 
		
	
		
			
				|  |  |  |  | 	urs->ctx = dc; | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | oops: | 
		
	
		
			
				|  |  |  |  | 	if (is_valid_socket(fd)) close_socket (fd); | 
		
	
		
			
				|  |  |  |  | 	if (dc) qse_httpd_freemem (httpd, dc); | 
		
	
		
			
				|  |  |  |  | 	return -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void urs_remove_tmr_tmout (urs_req_t* req) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (req->tmr_tmout != QSE_TMR_INVALID) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_tmr_remove (req->dc->httpd->tmr, req->tmr_tmout); | 
		
	
		
			
				|  |  |  |  | 		req->tmr_tmout = QSE_TMR_INVALID; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void urs_close (qse_httpd_t* httpd, qse_httpd_urs_t* urs) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t i; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	for (i = 0; i < QSE_COUNTOF(dc->reqs); i++) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		urs_req_t* next_req; | 
		
	
		
			
				|  |  |  |  | 		while (dc->reqs[i]) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			next_req = dc->reqs[i]->next; | 
		
	
		
			
				|  |  |  |  | 			urs_remove_tmr_tmout (dc->reqs[i]); | 
		
	
		
			
				|  |  |  |  | 			qse_httpd_freemem (httpd, dc->reqs[i]); | 
		
	
		
			
				|  |  |  |  | 			dc->reqs[i] = next_req; | 
		
	
		
			
				|  |  |  |  | 			dc->req_count--; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (dc->req_count == 0); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	close_socket (urs->handle.i); | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_freemem (httpd, urs->ctx); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_skad_t fromaddr; | 
		
	
		
			
				|  |  |  |  | 	socklen_t fromlen; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid; | 
		
	
		
			
				|  |  |  |  | 	qse_ssize_t len; | 
		
	
		
			
				|  |  |  |  | 	urs_pkt_t* pkt; | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* req; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("URS_RECV....\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn = qse_httpd_getxtn (httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	fromlen = QSE_SIZEOF(fromaddr); | 
		
	
		
			
				|  |  |  |  | 	len = recvfrom (urs->handle.i, dc->rcvbuf, QSE_SIZEOF(dc->rcvbuf) - 1, 0, (struct sockaddr*)&fromaddr, &fromlen); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* TODO: check if fromaddr matches the dc->skad... */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	pkt = (urs_pkt_t*)dc->rcvbuf; | 
		
	
		
			
				|  |  |  |  | 	if (len >= QSE_SIZEOF(pkt->hdr) &&  len >= QSE_SIZEOF(pkt->hdr) + qse_ntoh16(pkt->hdr.len)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		xid = qse_ntoh16(pkt->hdr.seq) % QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		for (req = dc->reqs[xid]; req; req = req->next) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			if (req->pkt->hdr.seq == pkt->hdr.seq && req->pkt->hdr.qusum == pkt->hdr.qusum) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				pkt->url[qse_ntoh16(pkt->hdr.len)] = QSE_MT('\0'); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				urs_remove_tmr_tmout (req); | 
		
	
		
			
				|  |  |  |  | 				req->rewrite (httpd, req->pkt->url, pkt->url, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 				if (req == dc->reqs[xid]) dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  | 				else req->prev->next = req->next; | 
		
	
		
			
				|  |  |  |  | 				if (req->next) req->next->prev = req->prev; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				qse_httpd_freemem (httpd, req); | 
		
	
		
			
				|  |  |  |  | 				dc->req_count--; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 				break; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void tmr_urs_tmout_updated (qse_tmr_t* tmr, qse_size_t old_index, qse_size_t new_index, void* ctx) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* req = (urs_req_t*)ctx; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf (">>tmr_urs_tmout_updated %d %d\n", (int)req->tmr_tmout, (int)old_index); | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (req->tmr_tmout == old_index); | 
		
	
		
			
				|  |  |  |  | 	req->tmr_tmout = new_index; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void tmr_urs_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, void* ctx) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	/* destory the unanswered request if timed out */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* req = (urs_req_t*)ctx; | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc = req->dc; | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* when this handler is called, the event should be removed from the timer */ | 
		
	
		
			
				|  |  |  |  | 	QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* --------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  | 	 * resend  | 
		
	
		
			
				|  |  |  |  | 	 *---------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  | 	if (req->resends > 0) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  | 		qse_tmr_event_t tmout_event; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		httpd_xtn = qse_httpd_getxtn (dc->httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		qse_gettime (&tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 		qse_addtime (&tmout_event.when, &httpd_xtn->urs.tmout, &tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 		tmout_event.ctx = req; | 
		
	
		
			
				|  |  |  |  | 		tmout_event.handler = tmr_urs_tmout_handle; | 
		
	
		
			
				|  |  |  |  | 		tmout_event.updater = tmr_urs_tmout_updated; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (sendto (dc->urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			/* error. fall thru */ | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			req->tmr_tmout = qse_tmr_insert (dc->httpd->tmr, &tmout_event); | 
		
	
		
			
				|  |  |  |  | 			if (req->tmr_tmout != QSE_TMR_INVALID) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				req->resends--; | 
		
	
		
			
				|  |  |  |  | 				return; /* resend ok */ | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("urs timed out....\n"); | 
		
	
		
			
				|  |  |  |  | 	/* --------------------------------------------------------------- | 
		
	
		
			
				|  |  |  |  | 	 * timed out + no resend  | 
		
	
		
			
				|  |  |  |  | 	 *---------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  | 	xid = req->seq % QSE_COUNTOF(dc->reqs); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* detach the request off dc->reqs */ | 
		
	
		
			
				|  |  |  |  | 	if (req == dc->reqs[xid]) dc->reqs[xid] = req->next; | 
		
	
		
			
				|  |  |  |  | 	else req->prev->next = req->next; | 
		
	
		
			
				|  |  |  |  | 	if (req->next) req->next->prev = req->prev; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* urs timed out. report that name resolution failed */ | 
		
	
		
			
				|  |  |  |  | 	req->rewrite (dc->httpd, req->pkt->url, QSE_NULL, req->ctx); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* i don't cache the items that have timed out */ | 
		
	
		
			
				|  |  |  |  | 	qse_httpd_freemem (dc->httpd, req); | 
		
	
		
			
				|  |  |  |  | 	dc->req_count--; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static int urs_send (qse_httpd_t* httpd, qse_httpd_urs_t* urs, const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, void* ctx) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn_t* httpd_xtn; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_uint16_t xid; | 
		
	
		
			
				|  |  |  |  | 	qse_uint32_t seq; | 
		
	
		
			
				|  |  |  |  | 	urs_req_t* req; | 
		
	
		
			
				|  |  |  |  | 	qse_size_t url_len; | 
		
	
		
			
				|  |  |  |  | 	qse_tmr_event_t tmout_event; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	httpd_xtn = qse_httpd_getxtn (httpd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("URS REALLY SENING>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (dc->req_count >= QSE_COUNTOF(dc->reqs)) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		/* too many pending requests */ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	url_len = qse_mbslen(url); | 
		
	
		
			
				|  |  |  |  | 	if (url_len > URS_MAX_URL_LEN) /* TODO: change the limit */ | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	seq = ((qse_uint32_t)dc->seq + 1) % URS_SEQ_RANGE_SIZE; | 
		
	
		
			
				|  |  |  |  | 	dc->seq = seq; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	xid = seq % QSE_COUNTOF(dc->reqs);  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + url_len + QSE_SIZEOF(urs_pkt_t)); | 
		
	
		
			
				|  |  |  |  | 	if (req == QSE_NULL) return  -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req->seq = seq; | 
		
	
		
			
				|  |  |  |  | 	req->pkt = (urs_pkt_t*)(req + 1); | 
		
	
		
			
				|  |  |  |  | 	req->pkt->hdr.seq = qse_hton16(seq); | 
		
	
		
			
				|  |  |  |  | 	req->pkt->hdr.len = qse_hton16(url_len); | 
		
	
		
			
				|  |  |  |  | 	req->pkt->hdr.qusum = hash_string (url); | 
		
	
		
			
				|  |  |  |  | 	qse_mbscpy (req->pkt->url, url); | 
		
	
		
			
				|  |  |  |  | 	req->pktlen = QSE_SIZEOF(urs_pkt_t) + url_len - 1; /* to exclude the terminating '\0' */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req->rewrite = rewrite; | 
		
	
		
			
				|  |  |  |  | 	req->ctx = ctx; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	qse_gettime (&tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 	qse_addtime (&tmout_event.when, &httpd_xtn->urs.tmout, &tmout_event.when); | 
		
	
		
			
				|  |  |  |  | 	tmout_event.ctx = req; | 
		
	
		
			
				|  |  |  |  | 	tmout_event.handler = tmr_urs_tmout_handle; | 
		
	
		
			
				|  |  |  |  | 	tmout_event.updater = tmr_urs_tmout_updated; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req->tmr_tmout = qse_tmr_insert (httpd->tmr, &tmout_event); | 
		
	
		
			
				|  |  |  |  | 	if (req->tmr_tmout == QSE_TMR_INVALID) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_freemem (httpd, req); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	req->resends = httpd_xtn->urs.resends; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if (sendto (urs->handle.i, req->pkt, req->pktlen, 0, (struct sockaddr*)&dc->skad, dc->skadlen) != req->pktlen) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		qse_tmr_remove (httpd->tmr, req->tmr_tmout); | 
		
	
		
			
				|  |  |  |  | 		req->tmr_tmout = QSE_TMR_INVALID; | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 
		
	
		
			
				|  |  |  |  | 		qse_httpd_freemem (httpd, req); | 
		
	
		
			
				|  |  |  |  | 		return -1; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	req->dc = dc; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* link the request to the front of the chain */ | 
		
	
		
			
				|  |  |  |  | 	if (dc->reqs[xid]) dc->reqs[xid]->prev = req; | 
		
	
		
			
				|  |  |  |  | 	req->next = dc->reqs[xid]; | 
		
	
		
			
				|  |  |  |  | 	dc->reqs[xid] = req; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* increment the number of pending requests */ | 
		
	
		
			
				|  |  |  |  | 	dc->req_count++; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | printf ("URS REALLY SENT>>>>>>>>>>>>>>>>>>>>>>>\n"); | 
		
	
		
			
				|  |  |  |  | 	return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* ------------------------------------------------------------------- */ | 
		
	
		
			
				|  |  |  |  | #if 0 | 
		
	
		
			
				|  |  |  |  | static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) | 
		
	
	
		
			
				
					
					|  |  |  | @ -3164,7 +3645,13 @@ static qse_httpd_scb_t httpd_system_callbacks = | 
		
	
		
			
				|  |  |  |  | 	{ dns_open, | 
		
	
		
			
				|  |  |  |  | 	  dns_close, | 
		
	
		
			
				|  |  |  |  | 	  dns_recv, | 
		
	
		
			
				|  |  |  |  | 	  dns_send } | 
		
	
		
			
				|  |  |  |  | 	  dns_send }, | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* urs */ | 
		
	
		
			
				|  |  |  |  | 	{ urs_open, | 
		
	
		
			
				|  |  |  |  | 	  urs_close, | 
		
	
		
			
				|  |  |  |  | 	  urs_recv, | 
		
	
		
			
				|  |  |  |  | 	  urs_send } | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static qse_httpd_rcb_t httpd_request_callbacks = | 
		
	
	
		
			
				
					
					|  |  |  | 
 |