parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
{
	struct msg_parse* prs;
	struct edns_data edns;
	uint64_t timestamp, expiry;
	time_t adjust;
	size_t lim = sldns_buffer_limit(buf);
	if(lim < LDNS_HEADER_SIZE+sizeof(timestamp)+sizeof(expiry))
		return 0; /* too short */

	/* remove timestamp and expiry from end */
	sldns_buffer_read_at(buf, lim-sizeof(expiry), &expiry, sizeof(expiry));
	sldns_buffer_read_at(buf, lim-sizeof(expiry)-sizeof(timestamp),
		&timestamp, sizeof(timestamp));
	expiry = be64toh(expiry);
	timestamp = be64toh(timestamp);

	/* parse DNS packet */
	regional_free_all(qstate->env->scratch);
	prs = (struct msg_parse*)regional_alloc(qstate->env->scratch,
		sizeof(struct msg_parse));
	if(!prs)
		return 0; /* out of memory */
	memset(prs, 0, sizeof(*prs));
	memset(&edns, 0, sizeof(edns));
	sldns_buffer_set_limit(buf, lim - sizeof(expiry)-sizeof(timestamp));
	if(parse_packet(buf, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
		sldns_buffer_set_limit(buf, lim);
		return 0;
	}
	if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
		LDNS_RCODE_NOERROR) {
		sldns_buffer_set_limit(buf, lim);
		return 0;
	}

	qstate->return_msg = dns_alloc_msg(buf, prs, qstate->region);
	sldns_buffer_set_limit(buf, lim);
	if(!qstate->return_msg)
		return 0;
	
	qstate->return_rcode = LDNS_RCODE_NOERROR;

	/* see how much of the TTL expired, and remove it */
	if(*qstate->env->now <= (time_t)timestamp) {
		verbose(VERB_ALGO, "cachedb msg adjust by zero");
		return 1; /* message from the future (clock skew?) */
	}
	adjust = *qstate->env->now - (time_t)timestamp;
	if(qstate->return_msg->rep->ttl < adjust) {
		verbose(VERB_ALGO, "cachedb msg expired");
		/* If serve-expired is enabled, we still use an expired message
		 * setting the TTL to 0. */
		if(qstate->env->cfg->serve_expired)
			adjust = -1;
		else
			return 0; /* message expired */
	}
	verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
	adjust_msg_ttl(qstate->return_msg, adjust);

	/* Similar to the unbound worker, if serve-expired is enabled and
	 * the msg would be considered to be expired, mark the state so a
	 * refetch will be scheduled.  The comparison between 'expiry' and
	 * 'now' should be redundant given how these values were calculated,
	 * but we check it just in case as does good_expiry_and_qinfo(). */
	if(qstate->env->cfg->serve_expired &&
		(adjust == -1 || (time_t)expiry < *qstate->env->now)) {
		qstate->need_refetch = 1;
	}

	return 1;
}
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
{
	struct msg_parse* prs;
	struct edns_data edns;
	uint64_t timestamp, expiry;
	time_t adjust;
	size_t lim = sldns_buffer_limit(buf);
	if(lim < LDNS_HEADER_SIZE+sizeof(timestamp)+sizeof(expiry))
		return 0;  

	 
	sldns_buffer_read_at(buf, lim-sizeof(expiry), &expiry, sizeof(expiry));
	sldns_buffer_read_at(buf, lim-sizeof(expiry)-sizeof(timestamp),
		&timestamp, sizeof(timestamp));
	expiry = be64toh(expiry);
	timestamp = be64toh(timestamp);

	 
	regional_free_all(qstate->env->scratch);
	prs = (struct msg_parse*)regional_alloc(qstate->env->scratch,
		sizeof(struct msg_parse));
	if(!prs)
		return 0;  
	memset(prs, 0, sizeof(*prs));
	memset(&edns, 0, sizeof(edns));
	sldns_buffer_set_limit(buf, lim - sizeof(expiry)-sizeof(timestamp));
	if(parse_packet(buf, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
		sldns_buffer_set_limit(buf, lim);
		return 0;
	}
	if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
		LDNS_RCODE_NOERROR) {
		sldns_buffer_set_limit(buf, lim);
		return 0;
	}

	qstate->return_msg = dns_alloc_msg(buf, prs, qstate->region);
	sldns_buffer_set_limit(buf, lim);
	if(!qstate->return_msg)
		return 0;
	
	qstate->return_rcode = LDNS_RCODE_NOERROR;

	 
	if(*qstate->env->now <= (time_t)timestamp) {
		verbose(VERB_ALGO, "cachedb msg adjust by zero");
		return 1;  
	}
	adjust = *qstate->env->now - (time_t)timestamp;
	if(qstate->return_msg->rep->ttl < adjust) {
		verbose(VERB_ALGO, "cachedb msg expired");
		 
		if(qstate->env->cfg->serve_expired)
			adjust = -1;
		else
			return 0;  
	}
	verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
	adjust_msg_ttl(qstate->return_msg, adjust);

	 
	if(qstate->env->cfg->serve_expired &&
		(adjust == -1 || (time_t)expiry < *qstate->env->now)) {
		qstate->need_refetch = 1;
	}

	return 1;
}