sldns_buffer_free(scratch_buffer);
return 0;
}
+ if(auth_load_thread_poll_for_quit(thr)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
xfr_http_preview(task->file, task->chunks_first);
if(!xfr_http_syntax_check(task->name, task->namelen, task->dclass,
auth_zone_delete_proxy(z);
return 0;
}
+ if(auth_load_thread_poll_for_quit(thr)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
if(!xfr_apply_http(task->name, task->namelen, task->host, task->file,
task->chunks_first, z, scratch_buffer)) {
sldns_buffer_free(scratch_buffer);
sldns_buffer_free(scratch_buffer);
if(z->rpz)
rpz_finish_config(z->rpz);
+ if(auth_load_thread_poll_for_quit(thr)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
auth_load_swap_zone(thr, z);
auth_zone_delete_proxy(z);
+ sldns_buffer_free(scratch_buffer);
+ return 1;
+}
+
+/** Copy RRset and append it to the domain, update last pointer. */
+static int
+rrset_append_copy(struct auth_data* domain, struct auth_rrset* rrset,
+ struct auth_rrset** last)
+{
+ struct auth_rrset* s = calloc(1, sizeof(*s));
+ if(!s)
+ return 0;
+ s->type = rrset->type;
+ s->data = (struct packed_rrset_data*)memdup(rrset->data,
+ packed_rrset_sizeof(rrset->data));
+ if(!s->data)
+ return 0;
+ packed_rrset_ptr_fixup(s->data);
+ if(!*last)
+ domain->rrsets = s;
+ else (*last)->next = s;
+ *last = s;
+ return 1;
+}
+
+/** Copy the existing zone for modification */
+static int
+auth_load_copy_into_zone(struct auth_load_thread* thr, struct auth_zone* proxyz)
+{
+ int count = 0;
+ struct auth_zone* z;
+ struct auth_data* d;
+ lock_rw_rdlock(&thr->task->worker->env.auth_zones->lock);
+ z = auth_zone_find(thr->task->worker->env.auth_zones,
+ thr->task->name, thr->task->namelen, thr->task->dclass);
+ if(!z) {
+ lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
+ verbose(VERB_ALGO, "auth zone missing for copy for IXFR.");
+ return 0;
+ }
+ lock_rw_rdlock(&z->lock);
+ lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
+
+ /* Copy from z into proxyz. */
+ RBTREE_FOR(d, struct auth_data*, &z->data) {
+ struct auth_rrset* rrset, *last = NULL;
+ struct auth_data* proxy_d = az_domain_create(proxyz,
+ d->name, d->namelen);
+ if(!proxy_d) {
+ log_err("out of memory");
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ for(rrset = d->rrsets; rrset; rrset=rrset->next) {
+ if(!rrset_append_copy(proxy_d, rrset, &last)) {
+ log_err("out of memory");
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ if((count++)%10000 == 0) {
+ if(auth_load_thread_poll_for_quit(thr)) {
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ }
+ }
+ if((count++)%10000 == 0) {
+ if(auth_load_thread_poll_for_quit(thr)) {
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ }
+ }
+
+ lock_rw_unlock(&z->lock);
+ return 1;
+}
+
+/** Process ixfr transfer */
+static int
+auth_load_process_ixfr(struct auth_load_thread* thr)
+{
+ struct auth_load_task* task = thr->task;
+ struct sldns_buffer* scratch_buffer;
+ struct auth_zone* z;
+
+ scratch_buffer = sldns_buffer_new(sldns_buffer_capacity(
+ thr->task->worker->env.scratch_buffer));
+ if(!scratch_buffer) {
+ log_err("out of memory");
+ return 0;
+ }
+ z = auth_zone_create_proxy(task->name, task->namelen, task->dclass);
+ if(!z) {
+ log_err("out of memory");
+ sldns_buffer_free(scratch_buffer);
+ return 0;
+ }
+ if(auth_load_thread_poll_for_quit(thr)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
+
+ /* Copy the existing zone for modification, that uses a read lock.
+ * That then does not interrupt the service of threads. */
+ if(!auth_load_copy_into_zone(thr, z)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
+ if(!xfr_apply_ixfr(task->chunks_first, task->serial, z,
+ scratch_buffer)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
+ if(auth_load_thread_poll_for_quit(thr)) {
+ sldns_buffer_free(scratch_buffer);
+ auth_zone_delete_proxy(z);
+ return 0;
+ }
+
+ auth_load_swap_zone(thr, z);
+ auth_zone_delete_proxy(z);
+ sldns_buffer_free(scratch_buffer);
return 1;
}
if(!auth_load_process_http(thr))
return 0;
} else if(task->on_ixfr && !task->on_ixfr_is_axfr) {
+ if(!auth_load_process_ixfr(thr))
+ return 0;
} else {
}
return 1;
}
/** create domain with the given name */
-static struct auth_data*
+struct auth_data*
az_domain_create(struct auth_zone* z, uint8_t* nm, size_t nmlen)
{
struct auth_data* n = (struct auth_data*)malloc(sizeof(*n));
/** RR list iterator, returns RRs from answer section one by one from the
* dns packets in the chunklist */
static void
-chunk_rrlist_start(struct auth_xfer* xfr, struct auth_chunk** rr_chunk,
+chunk_rrlist_start(struct auth_chunk* chunk_list, struct auth_chunk** rr_chunk,
int* rr_num, size_t* rr_pos)
{
- *rr_chunk = xfr->task_transfer->chunks_first;
+ *rr_chunk = chunk_list;
*rr_num = 0;
*rr_pos = 0;
}
}
/** apply IXFR to zone in memory. z is locked. false on failure(mallocfail) */
-static int
-apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
- struct sldns_buffer* scratch_buffer)
+int
+xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
+ struct auth_zone* z, struct sldns_buffer* scratch_buffer)
{
struct auth_chunk* rr_chunk;
int rr_num;
int softfail = 0;
/* start RR iterator over chunklist of packets */
- chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
+ chunk_rrlist_start(chunk_list, &rr_chunk, &rr_num, &rr_pos);
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
if(!ixfr_start_serial(rr_chunk, rr_num, rr_pos,
rr_dname, rr_type, rr_class, rr_ttl,
rr_rdlen, rr_rdata, rr_nextpos,
- transfer_serial, xfr->serial)) {
+ transfer_serial, xfr_serial)) {
return 0;
}
} else if(transfer_serial == serial) {
* SOA 3 followed by add
* SOA 3 end */
/* ended by SOA record */
- xfr->serial = transfer_serial;
+ /* xfr->serial is set by xfr_find_soa
+ * after this function. */
break;
}
}
/** apply IXFR to zone in memory. z is locked. false on failure(mallocfail) */
static int
-xfr_apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
+apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
struct sldns_buffer* scratch_buffer)
{
xfr->num_ixfrs++;
- return apply_ixfr(xfr, z, scratch_buffer);
+ return xfr_apply_ixfr(xfr->task_transfer->chunks_first, xfr->serial, z,
+ scratch_buffer);
}
/** apply AXFR to zone in memory. z is locked. false on failure(mallocfail) */
/* insert all RRs in to the zone */
/* insert the SOA only once, skip the last one */
/* start RR iterator over chunklist of packets */
- chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
+ chunk_rrlist_start(xfr->task_transfer->chunks_first, &rr_chunk,
+ &rr_num, &rr_pos);
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
}
} else if(xfr->task_transfer->on_ixfr &&
!xfr->task_transfer->on_ixfr_is_axfr) {
- if(!xfr_apply_ixfr(xfr, z, env->scratch_buffer)) {
+ if(!apply_ixfr(xfr, z, env->scratch_buffer)) {
auth_zone_clear_data(z);
lock_rw_unlock(&z->lock);
verbose(VERB_ALGO, "xfr from %s: could not store IXFR"