int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
        struct comm_reply* rep, uint16_t qid, uint16_t qflags,
        const struct query_info* qinfo)
{
	struct mesh_reply* r = regional_alloc(s->s.region,
		sizeof(struct mesh_reply));
	if(!r)
		return 0;
	r->query_reply = *rep;
	r->edns = *edns;
	if(edns->opt_list_in && !(r->edns.opt_list_in =
			edns_opt_copy_region(edns->opt_list_in, s->s.region)))
		return 0;
	if(edns->opt_list_out && !(r->edns.opt_list_out =
			edns_opt_copy_region(edns->opt_list_out, s->s.region)))
		return 0;
	if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
			edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
		return 0;
	r->qid = qid;
	r->qflags = qflags;
	r->start_time = *s->s.env->now_tv;
	r->next = s->reply_list;
	r->qname = regional_alloc_init(s->s.region, qinfo->qname,
		s->s.qinfo.qname_len);
	if(!r->qname)
		return 0;
	if(rep->c->use_h2)
		r->h2_stream = rep->c->h2_stream;

	/* Data related to local alias stored in 'qinfo' (if any) is ephemeral
	 * and can be different for different original queries (even if the
	 * replaced query name is the same).  So we need to make a deep copy
	 * and store the copy for each reply info. */
	if(qinfo->local_alias) {
		struct packed_rrset_data* d;
		struct packed_rrset_data* dsrc;
		r->local_alias = regional_alloc_zero(s->s.region,
			sizeof(*qinfo->local_alias));
		if(!r->local_alias)
			return 0;
		r->local_alias->rrset = regional_alloc_init(s->s.region,
			qinfo->local_alias->rrset,
			sizeof(*qinfo->local_alias->rrset));
		if(!r->local_alias->rrset)
			return 0;
		dsrc = qinfo->local_alias->rrset->entry.data;

		/* In the current implementation, a local alias must be
		 * a single CNAME RR (see worker_handle_request()). */
		log_assert(!qinfo->local_alias->next && dsrc->count == 1 &&
			qinfo->local_alias->rrset->rk.type ==
			htons(LDNS_RR_TYPE_CNAME));
		/* we should make a local copy for the owner name of
		 * the RRset */
		r->local_alias->rrset->rk.dname_len =
			qinfo->local_alias->rrset->rk.dname_len;
		r->local_alias->rrset->rk.dname = regional_alloc_init(
			s->s.region, qinfo->local_alias->rrset->rk.dname,
			qinfo->local_alias->rrset->rk.dname_len);
		if(!r->local_alias->rrset->rk.dname)
			return 0;

		/* the rrset is not packed, like in the cache, but it is
		 * individually allocated with an allocator from localzone. */
		d = regional_alloc_zero(s->s.region, sizeof(*d));
		if(!d)
			return 0;
		r->local_alias->rrset->entry.data = d;
		if(!rrset_insert_rr(s->s.region, d, dsrc->rr_data[0],
			dsrc->rr_len[0], dsrc->rr_ttl[0], "CNAME local alias"))
			return 0;
	} else
		r->local_alias = NULL;

	s->reply_list = r;
	return 1;
}
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
        struct comm_reply* rep, uint16_t qid, uint16_t qflags,
        const struct query_info* qinfo)
{
	struct mesh_reply* r = regional_alloc(s->s.region,
		sizeof(struct mesh_reply));
	if(!r)
		return 0;
	r->query_reply = *rep;
	r->edns = *edns;
	if(edns->opt_list_in && !(r->edns.opt_list_in =
			edns_opt_copy_region(edns->opt_list_in, s->s.region)))
		return 0;
	if(edns->opt_list_out && !(r->edns.opt_list_out =
			edns_opt_copy_region(edns->opt_list_out, s->s.region)))
		return 0;
	if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out =
			edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region)))
		return 0;
	r->qid = qid;
	r->qflags = qflags;
	r->start_time = *s->s.env->now_tv;
	r->next = s->reply_list;
	r->qname = regional_alloc_init(s->s.region, qinfo->qname,
		s->s.qinfo.qname_len);
	if(!r->qname)
		return 0;
	if(rep->c->use_h2)
		r->h2_stream = rep->c->h2_stream;

	 
	if(qinfo->local_alias) {
		struct packed_rrset_data* d;
		struct packed_rrset_data* dsrc;
		r->local_alias = regional_alloc_zero(s->s.region,
			sizeof(*qinfo->local_alias));
		if(!r->local_alias)
			return 0;
		r->local_alias->rrset = regional_alloc_init(s->s.region,
			qinfo->local_alias->rrset,
			sizeof(*qinfo->local_alias->rrset));
		if(!r->local_alias->rrset)
			return 0;
		dsrc = qinfo->local_alias->rrset->entry.data;

		 
		log_assert(!qinfo->local_alias->next && dsrc->count == 1 &&
			qinfo->local_alias->rrset->rk.type ==
			htons(LDNS_RR_TYPE_CNAME));
		 
		r->local_alias->rrset->rk.dname_len =
			qinfo->local_alias->rrset->rk.dname_len;
		r->local_alias->rrset->rk.dname = regional_alloc_init(
			s->s.region, qinfo->local_alias->rrset->rk.dname,
			qinfo->local_alias->rrset->rk.dname_len);
		if(!r->local_alias->rrset->rk.dname)
			return 0;

		 
		d = regional_alloc_zero(s->s.region, sizeof(*d));
		if(!d)
			return 0;
		r->local_alias->rrset->entry.data = d;
		if(!rrset_insert_rr(s->s.region, d, dsrc->rr_data[0],
			dsrc->rr_len[0], dsrc->rr_ttl[0], "CNAME local alias"))
			return 0;
	} else
		r->local_alias = NULL;

	s->reply_list = r;
	return 1;
}