예제 #1
0
static void
journal_ix_link_zone(journal *jh, zdb_zone *zone)
{
    yassert(jh->zone == NULL);
#if ZDB_ZONE_HAS_JNL_REFERENCE
    yassert(zone->journal == NULL);
#endif
    journal_ix *jix = (journal_ix*)jh;
    journal_ix_writelock(jix);
    jix->zone = zone;
#if ZDB_ZONE_HAS_JNL_REFERENCE
    zone->journal = jh;
#endif
    journal_ix_writeunlock(jix);
}
예제 #2
0
void
buffer_input_stream_init(input_stream* stream, input_stream* filtered, int buffer_size)
{
    buffer_input_stream_data* data;
    
    if(buffer_size == 0)
    {
        buffer_size = BUFFER_INPUT_STREAM_DEFAULT_BUFFER_SIZE;
    }

    yassert(filtered->vtbl != NULL);

    MALLOC_OR_DIE(buffer_input_stream_data*, data, sizeof(buffer_input_stream_data) + buffer_size - 1, BUFFER_INPUT_STREAM_TAG);

    data->filtered.data = filtered->data;
    data->filtered.vtbl = filtered->vtbl;

    filtered->data = NULL;
    filtered->vtbl = NULL;

    data->buffer_maxsize = buffer_size;
    data->buffer_size = 0;
    data->buffer_offset = 0;

    stream->data = data;
    stream->vtbl = &buffer_input_stream_vtbl;
}
예제 #3
0
ya_result
tsig_register(const u8 *name, const u8 *mac, u16 mac_size, u8 mac_algorithm)
{
    ya_result return_code = SUCCESS;

    tsig_node *node = tsig_avl_insert(&tsig_tree, name);

    if(node != NULL)
    {
        if(node->item.mac != NULL)
        {
            bool same = (node->item.mac_size == mac_size)                 &&
                        (node->item.mac_algorithm == mac_algorithm)       &&
                        (memcmp((u8*)node->item.mac, mac, mac_size) == 0);
            
            if(node->item.load_serial != tsig_serial)
            {
                node->item.load_serial = tsig_serial; // else every 256 updates will see a duplicate
                        
                if(same)
                {
                    // same key, different instances ... nothing to do
                    
                    return SUCCESS;
                }
                else
                {
                    // this is an old version of the key
                    
                    free((void*)node->item.mac);
                    node->item.mac = NULL;
                }
            }
            else
            {
                // it's a dup in the config file
                
                return TSIG_DUPLICATE_REGISTRATION; /* dup */
            }
        }
        
        yassert(node->item.mac == NULL);
        
        MALLOC_OR_DIE(u8*, node->item.mac, mac_size, TSIGMAC_TAG);
        MEMCOPY((u8*)node->item.mac, mac, mac_size);

        node->item.evp_md = tsig_get_EVP_MD(mac_algorithm);
        node->item.mac_algorithm_name = tsig_get_algorithm_name(mac_algorithm);
        node->item.name_len = dnsname_len(name);
        node->item.mac_algorithm_name_len = dnsname_len(node->item.mac_algorithm_name);
        node->item.mac_size = mac_size;
        node->item.mac_algorithm = mac_algorithm;
        node->item.load_serial = tsig_serial;

        tsig_tree_count++;
    }
    else
    {
예제 #4
0
파일: statmath.c 프로젝트: yhcting/ylib
static void
test_ivar(void) {
	int i;
	double vs0[] = {1};
	double vs1[] = {1, 2, 3, 4, 5, 6, 7};
	double vs2[] = {1, 2, 3, 4, 5, 6, 7, 8};
	struct ysm_ivar *iv, *iv0, *iv1, *iv2;
	iv = ysm_ivar_create();
	for (i = 0; i < yut_arrsz(vs0); i++)
		ysm_ivar_add(iv, vs0[i]);
	yassert(0 == ysm_ivar(iv));
	ysm_ivar_destroy(iv);

	iv = ysm_ivar_create();
	for (i = 0; i < yut_arrsz(vs1); i++)
		ysm_ivar_add(iv, vs1[i]);
	yassert(4 == ysm_ivar(iv));
	ysm_ivar_destroy(iv);

	iv = ysm_ivar_create();
	iv0 = ysm_ivar_create();
	iv1 = ysm_ivar_create();
	iv2 = ysm_ivar_create();
	for (i = 0; i < yut_arrsz(vs2); i++)
		ysm_ivar_add(iv, vs2[i]);
	yassert(5.25f == ysm_ivar(iv));
	for (i = 0; i < yut_arrsz(vs2) / 2; i++)
		ysm_ivar_add(iv0, vs2[i]);
	for (; i < yut_arrsz(vs2); i++)
		ysm_ivar_add(iv1, vs2[i]);
	ysm_ivar_combine(iv2, iv0, iv1);
	yassert(ysm_ivar(iv) == ysm_ivar(iv2));

	ysm_ivar_destroy(iv);
	ysm_ivar_destroy(iv0);
	ysm_ivar_destroy(iv1);
	ysm_ivar_destroy(iv2);

	iv = ysm_ivar_create();
	yassert(isnan(ysm_ivar(iv)));
	ysm_ivar_destroy(iv);
}
예제 #5
0
void
nsec_zone_label_detach(zdb_rr_label *rr_label)
{
    yassert((rr_label != NULL) && (rr_label->flags & ZDB_RR_LABEL_NSEC) != 0);
    
    if((rr_label->nsec.dnssec != NULL) && (rr_label->nsec.nsec.node != NULL))
    {
       rr_label->nsec.nsec.node->label = NULL;
       rr_label->nsec.nsec.node = NULL;
    }
}
예제 #6
0
void
tsig_hmac_free(tsig_hmac_t t)
{
    HMAC_CTX *hmac = (HMAC_CTX*)t;
    yassert(hmac != NULL);
#if SSL_API_LT_110
    HMAC_CTX_cleanup(hmac);
    ZFREE(t, HMAC_CTX);
#else
    HMAC_CTX_free(hmac);
#endif
}
예제 #7
0
static void
tc3(struct ymsghandler *mh) {
	struct ythreadex *yt;
	struct targ *ta;
	struct tres *tr;
	void *retval;
	/* Normal successful thread */
	ta = ymalloc(sizeof(*ta));
	memset(ta, 0, sizeof(*ta));
	ta->s = ymalloc(16);
	ta->sleep_cnt = 10 + rand() % 20;
	ta->sleep_interval = 10;
	strcpy(ta->s, "ok:arg");
	yt = ythreadex_create("ok",
			      mh,
			      YTHREADEX_NORMAL,
			      &_lis,
			      ta,
			      &free_arg,
			      &free_result,
			      &thread_run);
	yassert(ythreadex_destroy(yt));
	yassert(!ythreadex_start(yt));
	yassert(!ythreadex_cancel(yt, FALSE));
	ythreadex_join(yt, &retval);
	yassert(YTHREADEX_TERMINATED_CANCELLED == ythreadex_get_state(yt));
	tr = ythreadex_get_result(yt);
	yassert(!tr);
	yassert(!ythreadex_destroy(yt));

}
예제 #8
0
파일: pool.c 프로젝트: yhcting/ylib
struct ylistl_link *
ypool_get(struct ypool *p) {
	struct ylistl_link *lk = NULL;
	lock(p);
	if (unlikely(ylistl_is_empty(&p->hd)))
		goto done_unlock;
	lk = ylistl_remove_first(&p->hd);
	yassert(p->sz > 0);
	p->sz--;
 done_unlock:
	unlock(p);
        return lk;
}
예제 #9
0
static void
nsec3_free_node(nsec3_zone_item* node)
{
    /*
     * This assert is wrong because this is actually the payload that has just overwritten our node
     * assert(node->rc == 0 && node->sc == 0 && node->label.owners == NULL && node->star_label.owners == NULL & node->type_bit_maps == NULL);
     */
#ifdef DEBUG
    yassert((node->rc == 0) && (node->sc == 0));
#endif
    u32 node_size = NSEC3_NODE_SIZE(node);
    ZFREE_ARRAY(node, node_size);
}
예제 #10
0
int
ymsglooper_loop(void) {
	int r __unused;
	struct ymsglooper *ml = ymsglooper_get();
	if (unlikely(!ml))
		return -EPERM;
	dfpr("start LOOP!");
	lock_state(ml);
	if (YMSGLOOPER_READY != get_state_locked(ml)) {
		unlock_state(ml);
		goto skip_loop;
	}
	set_state_locked(ml, YMSGLOOPER_LOOP);
	unlock_state(ml);
	while (TRUE) {
		struct ymsg *m = ymsgq_de(ml->mq);
		struct ymsg_ *m_ = msg_mutate(m);
		/* Operation is NOT locked intentionally.
		 * See comment for 'struct ymsglooper'.
		 */
		if (YMSGLOOPER_STOPPING == get_state(ml)) {
			if (likely(m))
				ymsg_destroy(m);
			dfpr("break!!!! from loop!");
			break;
		}
		if (unlikely(!m))
			continue;
		/* Handler code here! */
		yassert(m_->handler && m_->handler->handle);
		(*m_->handler->handle)(m);
		ymsg_destroy(m);
	}
 skip_loop:
	r = pthread_setspecific(_tkey, NULL);
	yassert(!r);
	set_state(ml, YMSGLOOPER_TERMINATED);
	return 0;
}
예제 #11
0
static void
tc2(struct ymsghandler *mh) {
	struct ythreadex *yt;
	struct targ *ta;
	struct tres *tr;
	void *retval;
	/* Normal successful thread */
	ta = ymalloc(sizeof(*ta));
	memset(ta, 0, sizeof(*ta));
	ta->s = ymalloc(16);
	strcpy(ta->s, "ok:arg");
	yt = ythreadex_create("ok",
			      mh,
			      YTHREADEX_NORMAL,
			      &_lis,
			      ta,
			      &free_arg,
			      &free_result,
			      &thread_run);
	yassert(ythreadex_destroy(yt));
	yassert(!ythreadex_start(yt));
	ythreadex_join(yt, &retval);
	tr = ythreadex_get_result(yt);
	/* STARTED, DONE. And PROGRESS_INIT */
	ylogv("%d, %d, %d, %d, %d, %c\n",
	      ta->sti,
	      ta->st[0],
	      ta->st[1],
	      ta->progcnt,
	      tr->r,
	      tr->s[0]);
	yassert(2 == ta->sti
		&& YTHREADEX_STARTED == ta->st[0]
		&& YTHREADEX_DONE == ta->st[1]
		&& 1000 == ta->progcnt
		&& 0 == tr->r
		&& 'r' == tr->s[0]);
	yassert(!ythreadex_destroy(yt));
}
예제 #12
0
파일: statmath.c 프로젝트: yhcting/ylib
static void
test_imean(void) {
	int i;
	double vs0[] = {1};
	double vs1[] = {1, 2, 3, 4, 5, 6, 7};
	double vs2[] = {1, 2, 3, 4, 5, 6, 7, 8};
	struct ysm_imean *im, *im0, *im1, *im2;
	im = ysm_imean_create();
	for (i = 0; i < yut_arrsz(vs0); i++)
		ysm_imean_add(im, vs0[i]);
	yassert(1 == ysm_imean(im));
	ysm_imean_destroy(im);

	im = ysm_imean_create();
	for (i = 0; i < yut_arrsz(vs1); i++)
		ysm_imean_add(im, vs1[i]);
	yassert(4 == ysm_imean(im));
	ysm_imean_destroy(im);

	im0 = ysm_imean_create();
	im1 = ysm_imean_create();
	im2 = ysm_imean_create();
	im = ysm_imean_create();
	for (i = 0; i < yut_arrsz(vs2); i++)
		ysm_imean_add(im, vs2[i]);
	yassert(4.5f == ysm_imean(im));
	for (i = 0; i < yut_arrsz(vs2) / 2; i++)
		ysm_imean_add(im0, vs2[i]);
	for (; i < yut_arrsz(vs2); i++)
		ysm_imean_add(im1, vs2[i]);
	ysm_imean_combine(im2, im0, im1);
	yassert(ysm_imean(im) == ysm_imean(im2));
	ysm_imean_destroy(im);
	ysm_imean_destroy(im0);
	ysm_imean_destroy(im1);
	ysm_imean_destroy(im2);
}
예제 #13
0
static struct ymsglooper *
create_msglooper(pthread_t thread, int msgq_capacity) {
	struct ymsglooper *ml = ymalloc(sizeof(*ml));
	if (unlikely(!ml))
		return NULL;
	ml->mq = ymsgq_create(msgq_capacity);
	if (unlikely(!ml->mq))
		goto free_ml;
	yassert(thread); /* NOT NULL */
	ml->thread = thread;
	if (unlikely(pthread_mutex_init(&ml->state_lock, NULL)))
		goto free_mq;
	return ml;

 free_mq:
	ymsgq_destroy(ml->mq);
 free_ml:
	yfree(ml);
	return NULL;
}
예제 #14
0
파일: mempool.c 프로젝트: yhcting/ylib
/*
 * get one block from pool.
 */
void *
ymempool_get(struct ymempool *mp) {
	struct blk *b;

	lock(mp);
	if (mp->fbi >= sz(mp)) {
		if (expand(mp)) {
			unlock(mp);
			return NULL;
		}
	}

	b = fbpblk(mp, mp->fbi);
	yassert(b->i == mp->fbi);

	mp->fbi++;
	unlock(mp);

	return (void*)(&b->d);
}
예제 #15
0
파일: mempool.c 프로젝트: yhcting/ylib
struct ymempool *
ymempool_create(int grpsz, int elemsz, int opt) {
	struct ymempool *mp;

	yassert(grpsz > 0 && elemsz > 0);
	if (unlikely(!(mp = ycalloc(1, sizeof(*mp)))))
		return NULL;

	if (unlikely(!(mp->fbp = ymalloc(sizeof(*mp->fbp)))))
		goto nomem;

#ifndef CONFIG_MEMPOOL_DYNAMIC
	if (unlikely(!(mp->grp = ymalloc(sizeof(*mp->grp)))))
		goto nomem;
#endif

	mp->grpsz = grpsz;
	mp->nrgrp = 0;
	mp->esz = elemsz;
	mp->fbi = 0;
	mp->opt = opt;
	init_lock(mp);

	/* allocate 1-block-group for initial state */
	if (expand(mp))
		goto nomem;

	return mp;


 nomem:
#ifndef CONFIG_MEMPOOL_DYNAMIC
	if (mp->grp)
		yfree(mp->grp);
#endif
	if (mp->fbp)
		yfree(mp->fbp);
	yfree(mp);

	return NULL;
}
예제 #16
0
파일: mempool.c 프로젝트: yhcting/ylib
/*
 * return block to pool.
 */
void
ymempool_put(struct ymempool *mp, void *block) {
	struct blk *b;
	struct blk *ub; /* used block */
	int ti;

	b = containerof(block, struct blk, d);
	lock(mp);
	yassert(mp->fbi > 0
		&& b->i < mp->fbi);

	mp->fbi--;
	ub = fbpblk(mp, mp->fbi);

	/* swap free block pointer */
	ti = b->i;
	setfbp(mp, ub->i, b);
	setfbp(mp, ti, ub);

	if (need_shrink(mp))
		shrink(mp, 1);

	unlock(mp);
}
예제 #17
0
파일: etc.c 프로젝트: yhcting/ylib
static void
test_etc(void) {
	int n;
	n = 0;
	unroll16(-2, n++);
	yassert(!n);
	n = 0;
	unroll16(0, n++);
	yassert(!n);
	n = 0;
	unroll16(2, n++);
	yassert(2 == n);
	n = 0;
	unroll16(18, n++);
	yassert(18 == n);
	n = 0;
	unroll16(16, n++);
	yassert(16 == n);
	n = 0;
	unroll16(32, n++);
	yassert(32 == n);
}
예제 #18
0
static void
tc4(struct ymsghandler *mh) {
#define NR_THREADS 10
	int i;
	struct ythreadex *yt[NR_THREADS];
	struct targ *ta;
	struct tres *tr;
	void *retval[NR_THREADS];
	for (i = 0; i < NR_THREADS; i++) {
		/* Normal successful thread */
		ta = ymalloc(sizeof(*ta));
		memset(ta, 0, sizeof(*ta));
		/* sleep enough to get 'cancel' message after start */
		ta->sleep_cnt = 10 + rand() % 20;
		ta->sleep_interval = 10;
		ta->s = ymalloc(16);
		strcpy(ta->s, "ok:arg");
		yt[i] = ythreadex_create("ok",
		                         mh,
		                         YTHREADEX_NORMAL,
		                         &_lis,
		                         ta,
		                         &free_arg,
		                         &free_result,
		                         &thread_run);
	}

	for (i = 0; i < NR_THREADS; i++)
		yassert(!ythreadex_start(yt[i]));

	for (i = 0; i < NR_THREADS; i++) {
		if (i % 3)
			ythreadex_cancel(yt[i], i % 2);
	}
	for (i = 0; i < NR_THREADS; i++)
		ythreadex_join(yt[i], &retval[i]);

	for (i = 0; i < NR_THREADS; i++) {
		if (i % 3) {
			/* This is cancelled thread */
			ylogv("state: %d\n", ythreadex_get_state(yt[i]));
			yassert(YTHREADEX_TERMINATED_CANCELLED == ythreadex_get_state(yt[i]));
		} else {
			yassert(YTHREADEX_TERMINATED == ythreadex_get_state(yt[i]));
			tr = ythreadex_get_result(yt[i]);
			ta = ythreadex_get_arg(yt[i]);
			/* STARTED, DONE. And PROGRESS_INIT */
			ylogv("%d, %d, %d, %d, %d, %c\n",
			      ta->sti,
			      ta->st[0],
			      ta->st[1],
			      ta->progcnt,
			      tr->r,
			      tr->s[0]);
			yassert(2 == ta->sti
				&& YTHREADEX_STARTED == ta->st[0]
				&& YTHREADEX_DONE == ta->st[1]
				&& 1000 == ta->progcnt
				&& 0 == tr->r
				&& 'r' == tr->s[0]);
		}
		yassert(!ythreadex_destroy(yt[i]));
	}
#undef NR_THREADS
}
예제 #19
0
파일: mempool.c 프로젝트: yhcting/ylib
/*
 * i : index of fbp (ex. fbi)
 */
static INLINE struct blk *
fbpblk(struct ymempool *mp, int i) {
	struct blk *b = *(mp->fbp[i / mp->grpsz] + i % mp->grpsz);
	yassert(b->i == i);
	return b;
}
예제 #20
0
void
database_load_zone_desc(zone_desc_s *zone_desc)
{
    yassert(zone_desc != NULL);
    
    log_debug1("database_load_zone_desc(%{dnsname}@%p=%i)", zone_desc->origin, zone_desc, zone_desc->rc);
    
    s32 err = zone_register(&database_zone_desc, zone_desc);

    if(ISOK(err))
    {
        log_info("zone: %{dnsname}: %p: config: registered", zone_desc->origin, zone_desc);
        
        zone_lock(zone_desc, ZONE_LOCK_LOAD_DESC);
        zone_set_status(zone_desc, ZONE_STATUS_REGISTERED);
        zone_clear_status(zone_desc, ZONE_STATUS_DROP_AFTER_RELOAD);
        zone_unlock(zone_desc, ZONE_LOCK_LOAD_DESC);
        
        // newly registered zone
        // used to be message->origin
        
        if(database_service_started())
        {
            database_zone_load(zone_desc->origin); // before this I should set the file name

#if HAS_MASTER_SUPPORT
            if(zone_desc->type == ZT_MASTER)
            {
                if(!host_address_empty(zone_desc->slaves))
                {
                    log_info("zone: %{dnsname}: %p: config: notifying slaves", zone_desc->origin, zone_desc);
                    host_address *slaves = host_address_copy_list(zone_desc->slaves);
                    notify_host_list(zone_desc, slaves, CLASS_CTRL);
                }
            }
            else
#endif
            {

            }
        }
    }
    else
    {
        switch(err)
        {
            case DATABASE_ZONE_MISSING_DOMAIN:
            {
                log_err("zone: ?: %p: config: no domain set (not loaded)", zone_desc);
                
                if(zone_get_status(zone_desc) & ZONE_STATUS_PROCESSING)
                {
                    log_err("zone: ?: %p: is processed by %s (releasing)", zone_desc, database_service_operation_get_name(zone_desc->last_processor));
                }
                
                zone_release(zone_desc);
                
                break;
            }
            case DATABASE_ZONE_MISSING_MASTER:
            {
                log_err("zone: %{dnsname}: %p: config: slave but no master setting (not loaded)", zone_desc->origin, zone_desc);
                
                if(zone_get_status(zone_desc) & ZONE_STATUS_PROCESSING)
                {
                    log_err("zone: ?: %p: is processed by %s (releasing)", zone_desc, database_service_operation_get_name(zone_desc->last_processor));
                }
                
                zone_release(zone_desc);
                
                break;
            }
            case DATABASE_ZONE_CONFIG_CLONE: // Exact copy
            {
                log_debug("zone: %{dnsname}: %p: config: has already been set (same settings)", zone_desc->origin, zone_desc);
                
                zone_desc_s* current = zone_acquirebydnsname(zone_desc->origin);
                
                zone_lock(current, ZONE_LOCK_REPLACE_DESC);
                zone_clear_status(current, ZONE_STATUS_DROP_AFTER_RELOAD);
                zone_unlock(current, ZONE_LOCK_REPLACE_DESC);
                zone_release(current);
                
                // whatever has been decided above, loading the zone file (if it changed) should be queued
                database_zone_load(zone_desc->origin);
                
                zone_release(zone_desc);
                
                break;
            }
            case DATABASE_ZONE_CONFIG_DUP: // Not an exact copy
            {
                log_debug("zone: %{dnsname}: %p: config: has already been set (different settings)", zone_desc->origin, zone_desc);
                
                // basically, most of the changes require a stop, restart of
                // any task linked to the zone
                // so let's make this a rule, whatever changed
                
                notify_clear(zone_desc->origin);
                
                zone_desc_s *current = zone_acquirebydnsname(zone_desc->origin);

#if HAS_DYNAMIC_PROVISIONING
                host_address *notify_slaves_then_delete = NULL;
                host_address *notify_slaves = NULL;
#endif
                if(current != zone_desc)
                {
                    zone_lock(current, ZONE_LOCK_REPLACE_DESC);
                    
                    if(zone_get_status(current) & ZONE_STATUS_PROCESSING)
                    {
                        log_err("zone: ?: %p: is processed by %s (overwriting)", zone_desc, database_service_operation_get_name(zone_desc->last_processor));
                    }
                    
                    // what happens if the change is on :
                    
                    // domain: impossible
                    
                    /// @todo 20131203 edf -- compare before replace
                    
                    // file_name : try to load the new file (will happen anyway)
                    
                    if((current->file_name != NULL) && (zone_desc->file_name != NULL))
                    {
                        if(strcmp(current->file_name, zone_desc->file_name) != 0)
                        {
                            zone_set_status(current, ZONE_STATUS_MODIFIED);
                        }
                    }
                    else if(current->file_name != zone_desc->file_name) // at least one of them is NULL
                    {
                        zone_set_status(current, ZONE_STATUS_MODIFIED);
                    }
                    
                    free(current->file_name);
                    current->file_name = zone_desc->file_name;
                    zone_desc->file_name = NULL;
                    
                    // masters :
                    
                    log_debug7("updating %p (%u) with %p (%u): masters", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    
                    if(host_address_list_equals(current->masters, zone_desc->masters))
                    {
                        host_address_delete_list(zone_desc->masters);
                    }
                    else
                    {
                        host_address_delete_list(current->masters);
                        current->masters = zone_desc->masters;
                    }
                    zone_desc->masters = NULL;
                    
                    // notifies :
                    
                    log_debug7("updating %p (%u) with %p (%u): notifies", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    
                    if(host_address_list_equals(current->notifies, zone_desc->notifies))
                    {
                        host_address_delete_list(zone_desc->notifies);
                    }
                    else
                    {
                        host_address_delete_list(current->notifies);
                        current->notifies = zone_desc->notifies;
                    }
                    zone_desc->notifies = NULL;
                    
#if HAS_DYNAMIC_PROVISIONING
                    
                    log_debug7("updating %p (%u) with %p (%u): slaves", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    
                    if(host_address_list_equals(current->slaves, zone_desc->slaves))
                    {
#if HAS_MASTER_SUPPORT
                        if((current->type == ZT_MASTER) || (zone_desc->type == ZT_MASTER))
                        {
                            notify_slaves_then_delete = zone_desc->slaves;
                        }
                        else
#endif
                        {
                            host_address_delete_list(zone_desc->slaves);
                        }
                    }
                    else
                    {
#if HAS_MASTER_SUPPORT
                        if(current->type == ZT_MASTER)
                        {
                            notify_slaves_then_delete = current->slaves;
                        }
                        else
                        {
                            host_address_delete_list(current->slaves);
                        }
                        
                        if(zone_desc->type == ZT_MASTER)
                        {
                            notify_slaves = zone_desc->slaves;
                        }
#else
                        host_address_delete_list(current->slaves);
#endif
                        
                        current->slaves = zone_desc->slaves;
                    }
                    zone_desc->slaves = NULL;
                    
#endif              
                    // type : ?
                    
                    log_debug7("updating %p (%u) with %p (%u): type", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    current->type = zone_desc->type;
                    
#if HAS_ACL_SUPPORT
                    // ac : apply the new one, update the zone access
                                        
                    log_debug7("updating %p (%u) with %p (%u): ac@%p with ac@%p",
                            current, current->lock_owner, zone_desc, zone_desc->lock_owner,
                            &current->ac, &zone_desc->ac);
                    
#ifdef DEBUG
                    log_debug7("old@%p:", current);
                    log_debug7("    notify@%p",current->ac.allow_notify.ipv4.items);
                    log_debug7("     query@%p",current->ac.allow_query.ipv4.items);
                    log_debug7("  transfer@%p",current->ac.allow_transfer.ipv4.items);
                    log_debug7("    update@%p",current->ac.allow_update.ipv4.items);
                    log_debug7("forwarding@%p",current->ac.allow_update_forwarding.ipv4.items);
                    log_debug7("   control@%p",current->ac.allow_control.ipv4.items);
                    
                    log_debug7("new@%p:", zone_desc);
                    log_debug7("    notify@%p",zone_desc->ac.allow_notify.ipv4.items);
                    log_debug7("     query@%p",zone_desc->ac.allow_query.ipv4.items);
                    log_debug7("  transfer@%p",zone_desc->ac.allow_transfer.ipv4.items);
                    log_debug7("    update@%p",zone_desc->ac.allow_update.ipv4.items);
                    log_debug7("forwarding@%p",zone_desc->ac.allow_update_forwarding.ipv4.items);
                    log_debug7("   control@%p",zone_desc->ac.allow_control.ipv4.items);
#endif
                    
                    acl_unmerge_access_control(&current->ac, &g_config->ac);
                    acl_empties_access_control(&current->ac);
                    memcpy(&current->ac, &zone_desc->ac, sizeof(access_control));
                    ZEROMEMORY(&zone_desc->ac, sizeof(access_control));
#endif
                    // notify : reset, restart
                    
                    log_debug7("updating %p (%u) with %p (%u): notify", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    memcpy(&current->notify, &zone_desc->notify, sizeof(zone_notify_s));
#if HAS_DNSSEC_SUPPORT                    
#if HAS_RRSIG_MANAGEMENT_SUPPORT
                    // signature : reset, restart
                    
                    log_debug7("updating %p (%u) with %p (%u): signature", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    memcpy(&current->signature, &zone_desc->signature, sizeof(zone_signature_s));
#endif                    
                    // dnssec_mode : drop everything related to the zone, load the new config
                    
                    log_debug7("updating %p (%u) with %p (%u): dnssec_mode", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    
                    current->dnssec_mode = zone_desc->dnssec_mode;
#endif

                                        
                    // refresh : update the "alarms"
                    
                    log_debug7("updating %p (%u) with %p (%u): refresh", current, current->lock_owner, zone_desc, zone_desc->lock_owner);

                    memcpy(&current->refresh, &zone_desc->refresh, sizeof(zone_refresh_s));
                                        
                    // dynamic_provisioning : ?
                    
                    log_debug7("updating %p (%u) with %p (%u): dynamic_provisioning", current, current->lock_owner, zone_desc, zone_desc->lock_owner);
                    
                    memcpy(&current->dynamic_provisioning, &zone_desc->dynamic_provisioning, sizeof(dynamic_provisioning_s));
                    
                    // slaves : update the list
                    
                    zone_unlock(current, ZONE_LOCK_REPLACE_DESC);
                }

                // whatever has been decided above, loading the zone file should be queued
                database_zone_load(zone_desc->origin);

#if HAS_DYNAMIC_PROVISIONING
                // if asking for a load of the zone_data on a master should trigger a notify of its slaves
                
                log_debug7("handling dynamic provisioning");

                if(!host_address_empty(notify_slaves_then_delete))
                {
                    log_info("zone load desc: %{dnsname}: notifying slaves: %{hostaddrlist}", zone_desc->origin, notify_slaves_then_delete);
                    
                    notify_host_list(current, notify_slaves_then_delete, CLASS_CTRL);
                    notify_slaves_then_delete = NULL;
                }
                
                if(!host_address_empty(notify_slaves))
                {
                    log_info("zone load desc: %{dnsname}: notifying slaves: %{hostaddrlist}", zone_desc->origin, notify_slaves);
                    
                    host_address *notify_slaves_copy = host_address_copy_list(notify_slaves);
                    notify_host_list(current, notify_slaves_copy, CLASS_CTRL);
                    notify_slaves = NULL;
                }
#endif
                
#if HAS_MASTER_SUPPORT && HAS_DNSSEC_SUPPORT && HAS_RRSIG_MANAGEMENT_SUPPORT
                
                if(current->dnssec_policy != zone_desc->dnssec_policy)
                {
                    log_info("zone: %{dnsname}: %p: config: dnssec-policy modified", zone_desc->origin, zone_desc);
                    
                    if(zone_desc->dnssec_policy != NULL)
                    {
                        if(current->dnssec_policy != NULL)
                        {
                            log_warn("zone: %{dnsname}: %p: config: changing dnssec-policy at runtime (%s to %s)", zone_desc->origin, zone_desc, current->dnssec_policy->name, zone_desc->dnssec_policy->name);
                            
                            if(current->dnssec_policy->denial != zone_desc->dnssec_policy->denial)
                            {
                                log_warn("zone: %{dnsname}: %p: config: modifications of the dnssec-policy denial setting may be ignored", zone_desc->origin, zone_desc);
                            }
                        
                            dnssec_policy_release(current->dnssec_policy);
                            current->dnssec_policy = dnssec_policy_acquire_from_name(zone_desc->dnssec_policy->name);
                        }
                        else
                        {
                            log_info("zone: %{dnsname}: %p: config: dnssec-policy %s enabled", zone_desc->origin, zone_desc, zone_desc->dnssec_policy->name);
                            current->dnssec_policy = dnssec_policy_acquire_from_name(zone_desc->dnssec_policy->name);
                        }
                    }
                    else
                    {
                        log_warn("zone: %{dnsname}: %p: config: removing policy at runtime", zone_desc->origin, zone_desc);
                        dnssec_policy_release(current->dnssec_policy);
                        current->dnssec_policy = NULL;
                    }
                }
#endif
                if(current != zone_desc)
                {
                    log_debug7("destroying temporary zone descriptor @%p", zone_desc);

                    zone_release(zone_desc);
                }
                
                zone_clear_status(zone_desc, ZONE_STATUS_DROP_AFTER_RELOAD);
                
                zone_release(current);
                
                break;
            } // DUP
            default:
            {
                log_err("zone: %{dnsname}: %p: failed to register", zone_desc->origin, zone_desc);
                break;
            }
        } // switch
    }
    
    log_debug1("database_load_zone_desc(%p) done", zone_desc);
}
예제 #21
0
파일: taskmanager.c 프로젝트: yhcting/ylib
static void
tc0(struct ymsghandler *mh0,
    struct ymsghandler *mh1) {
	struct ytaskmanager *tm;
	struct targ *ta;
	struct ytask *tsk;
	int nrtasks;
	struct ytask *ptsks[2 * NR_TEST_TASKS];
	int ptski = 0;

	tm = ytaskmanager_create(mh0, 3);
	yassert(tm);
	nrtasks = NR_TEST_TASKS;

	while (nrtasks--) {
		usleep((rand() % 50) * 100);
		/* Normal successful thread */
		ta = ycalloc(1, sizeof(*ta));
		ta->s = ymalloc(16);
		strcpy(ta->s, "TC0");
		ta->sleep_cnt = rand() % 10;
		ta->sleep_interval = rand() % 10;
		tsk = ytask_create3("TC0-0",
				    mh0,
				    rand() % YTHREADEX_NUM_PRIORITY,
				    NULL,
				    ta,
				    &free_arg,
				    NULL,
				    &task_runnable,
				    TRUE);
		ytaskmanager_add_task(tm, tsk);
		ptsks[ptski++] = tsk;
	}
	nrtasks = NR_TEST_TASKS;
	while (nrtasks--) {
		usleep((rand() % 50) * 100);
		/* Normal successful thread */
		ta = ycalloc(1, sizeof(*ta));
		ta->s = ymalloc(16);
		strcpy(ta->s, "TC0");
		ta->sleep_cnt = rand() % 10;
		ta->sleep_interval = rand() % 10;
		tsk = ytask_create3("TC0-1",
				    mh1,
				    rand() % YTHREADEX_NUM_PRIORITY,
				    NULL,
				    ta,
				    &free_arg,
				    NULL,
				    &task_runnable,
				    TRUE);
		ytaskmanager_add_task(tm, tsk);
		ptsks[ptski++] = tsk;
	}

	while (ytaskmanager_destroy(tm))
		usleep(10 * 1000);

	while (ptski--)
		yassert(!ytask_destroy(ptsks[ptski]));

}
예제 #22
0
static void
mexit(void) {
	int r __unused;
	r = pthread_key_delete(_tkey);
	yassert(!r);
}
예제 #23
0
struct ymsglooper *
ymsglooper_start_looper_thread(bool destroy_on_exit) {
	int r __unused;
	int r0 __unused;
	pthread_t thread;
	struct looper_thread_share ts;

	dfpr("Enter");
	memset(&ts, 0, sizeof(ts));

	r = pthread_cond_init(&ts.cond, NULL);
	if (unlikely(r))
		goto done;

	r = pthread_mutex_init(&ts.lock, NULL);
	if (unlikely(r))
		goto free_cond;
	ts.destroy_on_exit = destroy_on_exit;
	r = pthread_create(&thread,
			   NULL,
			   &looper_thread,
			   &ts);
	if (unlikely(r)) {
		yassert(0);
		ylogf("Fail to create thread: %s\n", yerrno_str(r));
		goto free_cond;
	}

	r = pthread_mutex_lock(&ts.lock);
	if (unlikely(r))
		goto free_lock;
	if (!ts.result) {
		r = pthread_cond_wait(&ts.cond, &ts.lock);
		if (unlikely(r)) {
			r0 = pthread_mutex_unlock(&ts.lock);
			yassert(!r0);
			goto free_lock;
		}
	}
	yassert(ts.result);
	r = pthread_mutex_unlock(&ts.lock);
	yassert(!r);

	if (ts.result < 0)
		r = -ts.result; /* error ! */
	else
		yassert(ts.ml);

 free_lock:
	r0 = pthread_mutex_destroy(&ts.lock);
	yassert(!r0);
 free_cond:
	r0 = pthread_cond_destroy(&ts.cond);
	yassert(!r0);
 done:
	if (unlikely(r)) {
		dfpr("%s", yerrno_str(r));
		return NULL;
	}
	return ts.ml;
}
예제 #24
0
AVL_NODE_TYPE*
AVL_PREFIXED(avl_find_prev_mod)(AVL_CONST_TREE_TYPE* root, const AVL_REFERENCE_TYPE obj_hash)
{
    AVL_NODE_TYPE* node = *root;
    AVL_NODE_TYPE* lower_bound = NULL;
    AVL_REFERENCE_TYPE h;
    
    yassert(node != NULL);

    /* This is one of the parts I could try to optimize
     * I've checked the assembly, and it sucks ...
     */

    /* Both the double-test while/ternary and the current one
     * are producing the same assembly code.
     */
    
    /**
     * Get a key that 
     */

    while(node != NULL)
    {
        h = AVL_REFERENCE(node);

        /*
         * [0] is the length of the obj_hash
         *
         * The obj_hashs starts at [1]
         *
         */

#ifdef DEBUG
        if(h[0] != obj_hash[0])
        {
            DIE_MSG("NSEC3 corrupted NSEC3 node");
        }
#endif

        int cmp = memcmp(&obj_hash[1], &h[1], h[0]);

        /* equals */
        if(cmp == 0)
        {
            // want the prev mod
            
            return nsec3_avl_node_mod_prev(node);
        }

        /* bigger */
        if(cmp > 0)
        {
            lower_bound = node;
            node = AVL_CHILD(node, DIR_RIGHT);            
        }
        else
        {
            node = AVL_CHILD(node, DIR_LEFT);
        }
    }
    
    if(lower_bound == NULL)
    {
        lower_bound = *root;
        
        yassert(lower_bound != NULL);
        
        while((node = AVL_CHILD(lower_bound, DIR_RIGHT)) != NULL)
        {
            lower_bound = node;
        }
    }
    
    return lower_bound;
}
예제 #25
0
파일: list.c 프로젝트: yhcting/ylib
/**
 * Linked list test.
 */
static void
test_list(void) {
	int i;
	int *p;
	struct ylist *lst;
	struct ylisti *itr;

	lst = ylist_create(0, &yfree);
	ylist_destroy(lst);

	lst = ylist_create(0, &yfree);
	p = (int *)ymalloc(sizeof(*p));
	*p = 3;
	ylist_add_last(lst, p);

	itr = ylisti_create(lst, YLISTI_FORWARD);
	yassert(ylisti_has_next(itr));
	p = (int *)ylisti_next(itr);
	yassert(3 == *p);
	yassert(!ylisti_has_next(itr));
	ylisti_destroy(itr);

	itr = ylisti_create(lst, YLISTI_FORWARD);
	yassert(ylisti_has_next(itr));
	ylisti_next(itr);
	ylist_remove_current(lst, itr, 1);
	yassert(0 == ylist_size(lst));
	ylisti_destroy(itr);

	for (i = 0; i < 10; i++) {
		p = (int *)ymalloc(sizeof(*p));
		*p = i;
		ylist_add_last(lst, p);
	}
	yassert(10 == ylist_size(lst));
	yassert(ylist_has(lst, p));
	yassert(!ylist_has(lst, lst));

	/* simple iteration */
	i = 0;
	itr = ylisti_create(lst, YLISTI_FORWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		yassert(ylist_has(lst, p));
		yassert(i == *p);
		i++;
	}
	ylisti_destroy(itr);

	i = 9;
	itr = ylisti_create(lst, YLISTI_BACKWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		yassert(i == *p);
		i--;
	}
	ylisti_destroy(itr);

	/* remove odd numbers - tail is removed. */
	itr = ylisti_create(lst, YLISTI_FORWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		if (*p % 2)
			ylist_remove_current(lst, itr, 1);
	}
	ylisti_destroy(itr);

	i = 0;
	itr = ylisti_create(lst, YLISTI_FORWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		yassert(i == *p);
		i += 2;
	}
	ylisti_destroy(itr);
	ylist_destroy(lst);


	lst = ylist_create(0, &yfree);
	/* remove even numbers - head is removed. */
	for (i = 0; i < 10; i++) {
		p = (int *)ymalloc(sizeof(*p));
		*p = i;
		ylist_add_last(lst, p);
	}

	itr = ylisti_create(lst, YLISTI_FORWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		if (!(*p % 2))
			ylist_remove_current(lst, itr, 1);
	}
	ylisti_destroy(itr);

	i = 1;
	itr = ylisti_create(lst, YLISTI_FORWARD);
	while (ylisti_has_next(itr)) {
		p = ylisti_next(itr);
		yassert(i == *p);
		i += 2;
	}
	ylisti_destroy(itr);
	ylist_destroy(lst);

	{ /* Just Scope */
		struct dummy *dum;
		lst = ylist_create(0, free_dummycb);
		for (i = 0; i < 10; i++) {
			dum = (struct dummy *)ymalloc(sizeof(*dum));
			dum->id = i;
			dum->mem = (int *)ymalloc(sizeof(*dum->mem));
			*(dum->mem) = i;
			ylist_add_last(lst, dum);
		}
		yassert(10 == ylist_size(lst));

		itr = ylisti_create(lst, YLISTI_FORWARD);
		while (ylisti_has_next(itr)) {
			dum = ylisti_next(itr);
			if (5 == dum->id)
				ylist_remove_current(lst, itr, 1);
		}
		ylisti_destroy(itr);
		yassert(9 == ylist_size(lst));

		itr = ylisti_create(lst, YLISTI_FORWARD);
		while (ylisti_has_next(itr)) {
			dum = ylisti_next(itr);
			yassert(5 != dum->id);
		}
		ylisti_destroy(itr);
		ylist_destroy(lst);
	}

	lst = ylist_create(1, &yfree);
	p = (int *)ymalloc(sizeof(*p));
	*p = 0;
	ylist_add_last(lst, p);
	yassert(1 == ylist_size(lst));

	p = (int *)ymalloc(sizeof(*p));
	*p = 1;
	yassert(ylist_add_last(lst, p));
	yassert(1 == ylist_size(lst));
	yfree(p); /* p is fail to insert to the list */

	p = (int *)ylist_peek_last(lst);
	yassert(0 == *p && 1 == ylist_size(lst));
	p = ylist_remove_last(lst, FALSE);
	yassert(ylist_is_empty(lst));
	yfree(p);

	ylist_destroy(lst);
}
예제 #26
0
ya_result
nsec_update_zone(zdb_zone *zone, bool read_only) // read_only a.k.a slave
{
    nsec_node *nsec_tree = NULL;
    nsec_node *first_node;
    nsec_node *node;
    u8 *prev_name;
    u8 *name;
    soa_rdata soa;
    u32 missing_nsec_records = 0;
    u32 sibling_count = 0;
    u32 nsec_under_delegation = 0;
    ya_result return_code;
    u8 name_buffer[2][MAX_DOMAIN_LENGTH];
    u8 inverse_name[MAX_DOMAIN_LENGTH];
    u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */

    yassert(zdb_zone_islocked_weak(zone));
    
    if(FAIL(return_code = zdb_zone_getsoa(zone, &soa))) // zone is locked (weak)
    {
        return return_code;
    }
    
#ifdef DEBUG
    memset(name_buffer, 0xde, sizeof(name_buffer));
#endif
    
    name = name_buffer[0];
    prev_name = name_buffer[1];
    
    zdb_zone_label_iterator label_iterator;
    zdb_zone_label_iterator_init(&label_iterator, zone);

    while(zdb_zone_label_iterator_hasnext(&label_iterator))
    {
        zdb_zone_label_iterator_nextname(&label_iterator, name);
        zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);

        if(zdb_rr_label_is_glue(label) || (label->resource_record_set == NULL))
        {
            // we are under a delegation or on an empty (non-terminal) 
            // there should not be an NSEC record here
            
            zdb_packed_ttlrdata *nsec_record;

            if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked
            {
                nsec_under_delegation++;
                
                log_err("nsec: %{dnsname}: unexpected NSEC record under a delegation", name);
            }
            
            continue;
        }

        nsec_inverse_name(inverse_name, name);

        nsec_node *node = nsec_avl_insert(&nsec_tree, inverse_name);
        node->label = label;
        label->nsec.nsec.node = node;
    }

    /*
     * Now that we have the NSEC chain
     */

    type_bit_maps_context tbmctx;
    
    nsec_avl_iterator nsec_iter;
    nsec_avl_iterator_init(&nsec_tree, &nsec_iter);

    if(nsec_avl_iterator_hasnext(&nsec_iter))
    {
        first_node = nsec_avl_iterator_next_node(&nsec_iter);

        node = first_node;

        do
        {
            nsec_node *next_node;

            nsec_update_zone_count++;

            if(nsec_avl_iterator_hasnext(&nsec_iter))
            {
                next_node = nsec_avl_iterator_next_node(&nsec_iter);
            }
            else
            {
                next_node = first_node;
            }

            /*
             * Compute the type bitmap
             */

            zdb_rr_label *label = node->label;
            
            if(label == NULL)
            {
                node = next_node;
                continue;
            }

            u32 tbm_size = type_bit_maps_initialise_from_label(&tbmctx, label, TRUE, TRUE);
            type_bit_maps_write(&tbmctx, tmp_bitmap);
            
            u8 *tmp_name = prev_name;
            prev_name = name;
            name = tmp_name;

            nsec_inverse_name(name, next_node->inverse_relative_name);

            /*
             * Get the NSEC record
             */

            zdb_packed_ttlrdata *nsec_record;

            if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked
            {
                /*
                 * has record -> compare the type and the nsec next
                 * if something does not match remove the record and its signature (no record)
                 *
                 */

                if(nsec_record->next == NULL) // should only be one record => delete all if not the case (the rrsig is lost anyway)
                {
                    const u8 *rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
                    const u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record);
                    const u16 dname_len = dnsname_len(rdata);

                    if(dname_len < size)
                    {
                        const u8 *type_bitmap = &rdata[dname_len];

                        /*
                         * check the type bitmap
                         */

                        if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0)
                        {
                            /*
                             * check the nsec next
                             */

                            if(dnsname_equals(rdata, name))
                            {
                                /* All good */
                                
                                label->flags |= ZDB_RR_LABEL_NSEC;

                                node = next_node;
                                continue;
                            }
                            else // else the "next fqdn" do not match (this is irrecoverable for a slave)
                            {
                                rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                                log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name);
                            }
                        }
                        else // else the type bitmap do not match (this is wrong)
                        {
                            rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                            log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} types map do not match expected value", zone->origin, prev_name, &nsec_desc);
                        }
                    }
                    else // else the "next fqdn" do not match (early test, this is irrecoverable for a slave)
                    {
                        rdata_desc nsec_desc = {TYPE_NSEC, size, rdata};
                        log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name);
                    }
                }
                else
                {
                    sibling_count++;
                    
                    log_warn("nsec: %{dnsname}: %{dnsname}: multiple NSEC records where only one is expected", zone->origin, prev_name);
                }
                
                // wrong NSEC RRSET
                
                zdb_packed_ttlrdata *nsec_rec = nsec_record;

                do
                {
                    zdb_ttlrdata unpacked_ttlrdata;

                    unpacked_ttlrdata.ttl = nsec_rec->ttl;
                    unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec);
                    unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec);

                    rdata_desc nsec_desc = {TYPE_NSEC, unpacked_ttlrdata.rdata_size, unpacked_ttlrdata.rdata_pointer};

                    if(!read_only)
                    {
                        log_warn("nsec: %{dnsname}: del: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
#if ZDB_CHANGE_FEEDBACK_SUPPORT
                        zdb_listener_notify_remove_record(zone, name, TYPE_NSEC, &unpacked_ttlrdata);
#endif
                    }
                    else
                    {
                        log_err("nsec: %{dnsname}: got: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
                    }

                    nsec_rec = nsec_rec->next;
                }
                while(nsec_rec != NULL);
                
                if(!read_only)
                {
                    zdb_record_delete(&label->resource_record_set, TYPE_NSEC);
                    rrsig_delete(zone, name, label, TYPE_NSEC);
                    nsec_record = NULL;
                }
            }

            /*
             * no record -> create one and schedule a signature (MASTER ONLY)
             */

            if(nsec_record == NULL)
            {
                missing_nsec_records++;
                
                zdb_packed_ttlrdata *nsec_record;

                u16 dname_len = nsec_inverse_name(name, next_node->inverse_relative_name);
                u16 rdata_size = dname_len + tbm_size;

                ZDB_RECORD_ZALLOC_EMPTY(nsec_record, soa.minimum, rdata_size);
                u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
                memcpy(rdata, name, dname_len);
                rdata += dname_len;
                memcpy(rdata, tmp_bitmap, tbm_size);
                
                rdata_desc nsec_desc = {TYPE_NSEC, ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record), ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record)};
                
                if(!read_only)
                {                    
                    zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record);

#ifdef DEBUG
                    log_debug("nsec: %{dnsname}: add: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
#endif
#if ZDB_CHANGE_FEEDBACK_SUPPORT
                    if(zdb_listener_notify_enabled())
                    {        
                        dnsname_vector name_path;

                        zdb_ttlrdata unpacked_ttlrdata;

                        unpacked_ttlrdata.ttl = nsec_record->ttl;
                        unpacked_ttlrdata.rdata_size = rdata_size;
                        unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

                        dnsname_to_dnsname_vector(name, &name_path);
                        zdb_listener_notify_add_record(zone, name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata);
                    }
#endif
                    
                    /*
                     * Schedule a signature
                     */
                }
                else
                {
                    log_warn("nsec: %{dnsname}: need: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc);
                    ZDB_RECORD_ZFREE(nsec_record);
                }
            }

            label->flags |= ZDB_RR_LABEL_NSEC;

            node = next_node;
        }
        while(node != first_node);
    }

    zone->nsec.nsec = nsec_tree;
    
    if(read_only)
    {
        if(missing_nsec_records + sibling_count + nsec_under_delegation)
        {
            log_err("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation);
            
            //return DNSSEC_ERROR_NSEC_INVALIDZONESTATE;
        }
    }
    else
    {
        if(missing_nsec_records + sibling_count + nsec_under_delegation)
        {
            log_warn("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation);
        }
    }
    
    return SUCCESS;
}
예제 #27
0
파일: mempool.c 프로젝트: yhcting/ylib
static INLINE void
unlock(struct ymempool *mp) {
	if (opt_is_mt_safe(mp))
		if (pthread_mutex_unlock(&mp->m))
			yassert(0);
}
예제 #28
0
bool
nsec_update_label_record(zdb_zone *zone, zdb_rr_label *label, nsec_node *item, nsec_node *next_item, u8 *name)
{
    yassert(zdb_zone_islocked(zone));
    
    type_bit_maps_context tbmctx;
    u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */
    u32 tbm_size = type_bit_maps_initialise_from_label(&tbmctx, label, TRUE, TRUE);
    u32 ttl = zone->min_ttl;
    type_bit_maps_write(&tbmctx, tmp_bitmap);

    /*
     * Get the NSEC record
     */

    zdb_packed_ttlrdata *nsec_record;

    if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked
    {
        /*
         * has record -> compare the type and the nsec next
         * if something does not match remove the record and its signature (no record)
         *
         */

        log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) updating record.", name, item->inverse_relative_name, next_item->inverse_relative_name);

        /*
         * If there is more than one record, clean-up
         */


        if(nsec_record->next == NULL)
        {
            u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);
            u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record);

            u16 dname_len = dnsname_len(rdata);

            if(dname_len < size)
            {
                u8* type_bitmap = &rdata[dname_len];

                /*
                 * check the type bitmap
                 */

                if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0)
                {
                    /*
                     * check the nsec next
                     */
                    
                    u8 tmp_name[MAX_DOMAIN_LENGTH];
                    nsec_inverse_name(tmp_name, next_item->inverse_relative_name);

                    if(dnsname_equals(rdata, tmp_name))
                    {
                        /* All good */

                        return FALSE;
                    }
                }
            }    
        }

#if ZDB_CHANGE_FEEDBACK_SUPPORT
        if(zdb_listener_notify_enabled())
        {
            zdb_packed_ttlrdata *nsec_rec = nsec_record;

            do
            {
                zdb_ttlrdata unpacked_ttlrdata;

                unpacked_ttlrdata.ttl = nsec_rec->ttl;
                unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec);
                unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec);

                zdb_listener_notify_remove_record(zone, name, TYPE_NSEC, &unpacked_ttlrdata);

                nsec_rec = nsec_rec->next;
            }
            while(nsec_rec != NULL);
        }
#endif
        zdb_record_delete(&label->resource_record_set, TYPE_NSEC);

        rrsig_delete(zone, name, label, TYPE_NSEC);

        nsec_record = NULL;
    }

    /*
     * no record -> create one and schedule a signature
     */

    if(nsec_record == NULL)
    {
        zdb_packed_ttlrdata *nsec_record;
        u8 next_name[256];

        log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) building new record.", name, item->inverse_relative_name, next_item->inverse_relative_name);

        u16 dname_len = nsec_inverse_name(next_name, next_item->inverse_relative_name);
        u16 rdata_size = dname_len + tbm_size;

        ZDB_RECORD_ZALLOC_EMPTY(nsec_record, ttl, rdata_size);

        u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

        memcpy(rdata, next_name, dname_len);
        rdata += dname_len;

        memcpy(rdata, tmp_bitmap, tbm_size);

        zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record);
        
#if ZDB_CHANGE_FEEDBACK_SUPPORT
        if(zdb_listener_notify_enabled())
        {        
            dnsname_vector name_path;

            zdb_ttlrdata unpacked_ttlrdata;
            
            unpacked_ttlrdata.ttl = ttl;
            unpacked_ttlrdata.rdata_size = rdata_size;
            unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record);

            dnsname_to_dnsname_vector(name, &name_path);

            zdb_listener_notify_add_record(zone, name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata);
        }
#endif
        /*
         * Schedule a signature
         */
    }

    label->flags |= ZDB_RR_LABEL_NSEC;

    return TRUE;
}
예제 #29
0
ya_result
xfr_input_stream_init(input_stream* filtering_stream, const u8 *origin, input_stream *xfr_source_stream, message_data *message, u32 current_serial, xfr_copy_flags flags)
{
    yassert(filtering_stream != NULL && origin != NULL && xfr_source_stream != NULL && message != NULL);
    
    input_stream *is = xfr_source_stream;
    
    packet_unpack_reader_data reader;
    u8 *buffer;
    u8 *record;
    u8 *ptr;
#if DNSCORE_HAS_TSIG_SUPPORT
    const tsig_item *tsig;
#endif
    ya_result record_len;
    ya_result return_value;
    u32 origin_len;
    u32 last_serial = 0;

    u16 tcplen;
    u16 qtype;
    u16 qclass;

    u16 old_mac_size;
    
    bool last_message_had_tsig;
    bool need_cleanup_tsig = FALSE;

#if DNSCORE_HAS_TSIG_SUPPORT
    u8 old_mac[64];
#endif
    
    /*
     * ensure the stream will be unusable if the initialisation fails
     */
    
    input_stream_set_void(filtering_stream);
    
    /*
     * Start by reading the first packet, and determine if it's an AXFR or an IXFR (for the name)
     * note: it's read and converted to the host endianness
     */
    
    if(!is_fd_input_stream(is))
    {
        // expected file input stream
        return INVALID_ARGUMENT_ERROR;
    }
    
    //buffer_input_stream_init(is, is, 4096);
    
    /* TCP length */

    if(FAIL(return_value = input_stream_read_nu16(is, &tcplen)))
    {
        return return_value;
    }
    
    if(return_value != 2)
    {
        return UNEXPECTED_EOF;
    }
    
    /* if the length is not enough, return the most appropriate error code */

    origin_len = dnsname_len(origin);

    if(tcplen < DNS_HEADER_LENGTH + origin_len + 4)
    {
        return_value = UNEXPECTED_EOF;
        
        if(tcplen >= DNS_HEADER_LENGTH)
        {
            if(ISOK(return_value = input_stream_read_fully(is, message->pool_buffer, DNS_HEADER_LENGTH)))
            {
                return_value = MAKE_DNSMSG_ERROR(MESSAGE_RCODE(message->pool_buffer));
            }
        }

        return return_value;
    }
    
    /* read the whole message */

    buffer = &message->buffer[0];
    record = &message->pool_buffer[0];
    
    assert(sizeof(message->pool_buffer) >= 255 + 10 + 65535);

    if(FAIL(return_value = input_stream_read_fully(is, buffer, tcplen)))
    {
        return return_value;
    }
    
#if DEBUG_XFR_INPUT_STREAM
    log_memdump(g_system_logger, MSG_DEBUG1, &message->buffer[0], tcplen, 32);
#endif
    
    message->received = return_value;
    
    /* check the message makes sense */

    const u64 *h64 = (u64*)buffer;
    u64 m64 = AXFR_MESSAGE_HEADER_MASK;
    u64 r64 = AXFR_MESSAGE_HEADER_RESULT;

    if(((*h64&m64) != r64) || (MESSAGE_NS(message->buffer) != 0))
    {
        u8 code = MESSAGE_RCODE(message->buffer);

        if(code != 0)
        {
            return_value = MAKE_DNSMSG_ERROR(code);
        }
        else
        {
            return_value = UNPROCESSABLE_MESSAGE;
        }

         return return_value;
    }

    //m64 = AXFR_NEXT_MESSAGE_HEADER_MASK;
    //r64 = AXFR_NEXT_MESSAGE_HEADER_RESULT;

    packet_reader_init(&reader, buffer, tcplen);
    reader.offset = DNS_HEADER_LENGTH;

    packet_reader_read_fqdn(&reader, record, RDATA_MAX_LENGTH + 1);

    if(!dnsname_equals(record, origin))
    {
        return INVALID_PROTOCOL;
    }

    if(FAIL(return_value = packet_reader_read_u16(&reader, &qtype)))
    {
        return return_value;
    }
    
    if(return_value != 2)
    {
        return UNEXPECTED_EOF;
    }

    /* 
     * check that we are allowed to process this particular kind of transfer
     * note : this does not determine what is REALLY begin transferred
     */
    
    switch(qtype)
    {
        case TYPE_AXFR:
        {
            if((flags & XFR_ALLOW_AXFR) == 0)
            {
                return INVALID_PROTOCOL;
            }
            break;
        }
        case TYPE_IXFR:
        {
            if((flags & XFR_ALLOW_IXFR) == 0)
            {
                return INVALID_PROTOCOL;
            }
            break;
        }
        default:
        {
            return INVALID_PROTOCOL;
        }
    }

    if(FAIL(return_value = packet_reader_read_u16(&reader, &qclass)))
    {
        return return_value;
    }

    if(qclass != CLASS_IN)
    {
        /** wrong answer */
        return INVALID_PROTOCOL;
    }
    
    /* check for TSIG and verify */

    u16 ancount = ntohs(MESSAGE_AN(buffer));
    
#if DNSCORE_HAS_TSIG_SUPPORT
    if((last_message_had_tsig = ((tsig = message->tsig.tsig) != NULL)))
    {
        /* verify the TSIG
         *
         * AR > 0
         * skip ALL the records until the last AR
         * it MUST be a TSIG
         * It's the first TSIG answering to our query
         * verify it
         *
         */
        
        message->tsig.tsig = NULL;

        old_mac_size = message->tsig.mac_size;
        memcpy(old_mac, message->tsig.mac, old_mac_size);

        if(FAIL(return_value = tsig_message_extract(message)))
        {
            log_debug("xfr_input_stream: error extracting the signature");

            return return_value;
        }

        if(return_value == 0)
        {
            log_debug("xfr_input_stream: no signature when one was requested");

            return TSIG_BADSIG; /* no signature, when one was requested, is a bad signature */
        }

        if(message->tsig.tsig != tsig)
        {
            /* This is not the one we started with */

            log_debug("xfr_input_stream: signature key does not match");

            return TSIG_BADSIG;
        }

        /// check that the tsig in the message matches the one that was sent

        if(FAIL(return_value = tsig_verify_tcp_first_message(message, old_mac, old_mac_size)))
        {
            return return_value;
        }

        reader.packet_size = message->received;
        
        need_cleanup_tsig = TRUE;
    }
#endif
    
    log_debug("xfr_input_stream: expecting %5d answer records", ancount);    

    /*
     * read the SOA (it MUST be an SOA)
     */

    if(FAIL(record_len = packet_reader_read_record(&reader, record, RDATA_MAX_LENGTH + 1)))
    {
        return record_len;
    }

    if(!dnsname_equals(record, origin))
    {
        return INVALID_PROTOCOL;
    }

    ptr = &record[origin_len];

    if(GET_U16_AT(*ptr) != TYPE_SOA)
    {
        return INVALID_PROTOCOL;
    }

    ptr += 8; /* type class ttl */
    
    u16 rdata_size = ntohs(GET_U16_AT(*ptr));
    
    if(rdata_size < 22)
    {
        return INVALID_PROTOCOL;
    }

    rdata_size -= 16;

    ptr += 2; /* rdata size */

    s32 len = dnsname_len(ptr);

    if(len >= rdata_size)
    {
        return INVALID_PROTOCOL;
    }
    rdata_size -= len;
    ptr += len;

    len = dnsname_len(ptr);
    if(len >= rdata_size)
    {
        return INVALID_PROTOCOL;
    }
    rdata_size -= len;

    if(rdata_size != 4)
    {
        return INVALID_PROTOCOL;
    }

    ptr += len;

    // if the serial of the SOA is the same one as we know, then there is no
    // need to download the zone
    
    last_serial = ntohl(GET_U32_AT(*ptr));
    
    if(last_serial == current_serial)
    {
        //args->out_loaded_serial = args->current_serial;
                        
        return ZONE_ALREADY_UP_TO_DATE;
    }

    xfr_input_stream_data *data;    
    ZALLOC_OR_DIE(xfr_input_stream_data*, data, xfr_input_stream_data, XFRISDTA_TAG);
    ZEROMEMORY(data, sizeof(xfr_input_stream_data));
    
    /*
     * We have got the first SOA
     * Next time we find this SOA (second next time for IXFR) the stream, it will be the end of the stream
     */

    /*
     * The stream can be AXFR or IXFR.
     * The only way to know this is to look at the records, maybe on many packets.
     * If there are two SOA (different serial numbers) for the start, then it's an IXFR, else it's an AXFR.
     * 
     * OPEN A PIPE STREAM "XFRs"
     *
     * Save the first SOA
     */

    MALLOC_OR_DIE(u8*, data->first_soa_record, record_len, XFRISSOA_TAG);
    MEMCOPY(data->first_soa_record, record, record_len);
    data->first_soa_record_size = record_len;         

    filtering_stream->vtbl = &xfr_input_stream_vtbl;
    filtering_stream->data = data;
    
    pipe_stream_init(&data->pipe_stream_output, &data->pipe_stream_input, 65536);
    MEMCOPY(&data->reader, &reader, sizeof(packet_unpack_reader_data));
    
    data->origin = origin;
    data->message = message;
    
    data->ancount = ancount - 1;
    data->record_index++;
    data->last_serial = last_serial;
    data->xfr_mode = TYPE_ANY;
    data->ixfr_mark = FALSE;
    data->last_message_had_tsig = last_message_had_tsig;
    data->source_stream = *is;
    data->need_cleanup_tsig = need_cleanup_tsig;
    
    /*
     * Then we read all records for all packets
     * If we find an SOA ...
     *      AXFR: it has to be the last serial and it is the end of the stream.
     *      IXFR: if it's not the last serial it has to go from step to step
     *            AND once we have reached the "last serial" once, the next hit is the end of the stream.
     */

    data->eos = FALSE;
    
    /*
     * In order to know what the type is, read the first packet.
     */
    
    return_value = xfr_input_stream_read_packet(data);
    
    if(FAIL(return_value))
    {
        xfr_input_stream_close(filtering_stream);
    }
    
    return return_value;
}
예제 #30
0
ya_result
zdb_icmtl_replay_commit(zdb_zone *zone, input_stream *is, u32 *current_serialp)
{
    ya_result ret;
    /*
     * 0: DELETE, 1: ADD
     * The mode is switched every time an SOA is found.
     */

    yassert(zdb_zone_islocked(zone));
    
#if ZDB_HAS_NSEC3_SUPPORT
    bool has_nsec3 = zdb_zone_is_nsec3(zone);
#endif
#if ZDB_HAS_NSEC_SUPPORT
    bool has_nsec = zdb_zone_is_nsec(zone);
#endif
    
#if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT
    if(has_nsec3 && has_nsec)
    {
        log_err("journal: %{dnsname}: zone has both NSEC and NSEC3 status, which is not supported by YADIFA", zone->origin);
        return ERROR;
    }
#endif
    
    u8 mode = 1; // the first SOA will switch the mode to delete
    s32 changes = 0;
    
    zdb_ttlrdata ttlrdata;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    const u8 *fqdn = rr.name;
    dnslabel_vector labels;

    ttlrdata.next = NULL;
    


    /*
     * The plan for NSEC3 :
     * Store the fqdn + type class ttl rdata in collections
     * => the delete collection
     * => the add collection
     * Then there is the NSEC3 covered labels: keep a reference to them for later
     *
     * When a pass of SOA-/SOA+ has finished:
     * _ replace the NSEC3 in both collections (reading from delete)
     * _ delete NSEC3 to delete
     * _ add NSEC3 to add
     *
     * _ and finally update the NSEC3 for the labels kept above
     */

#if ZDB_HAS_NSEC3_SUPPORT
    chain_replay nsec3replay;
    nsec3_chain_replay_init(&nsec3replay, zone);
#endif
    
#if ZDB_HAS_NSEC_SUPPORT
    chain_replay nsecreplay;
    nsec_chain_replay_init(&nsecreplay, zone);
#endif
    
#if ZDB_HAS_NSEC3_SUPPORT
    ptr_set downed_fqdn = PTR_SET_DNSNAME_EMPTY;
#endif

    /* 
     * At this point : the next record, if it exists AND is not an SOA , has to be deleted
     * 
     */
    
    bool did_remove_soa = FALSE;

    // something has to be committed

    for(;;)
    {
        /*
         * read the full record
         * 
         * == 0 : no record (EOF)
         *  < 0 : failed
         */

        if((ret = dns_resource_record_read(&rr, is)) <= 0)
        {
            if(ISOK(ret))
            {
                log_info("journal: %{dnsname}: reached the end of the journal page", zone->origin);
            }
            else
            {
                log_err("journal: %{dnsname}: broken journal: %r", zone->origin, ret);
                logger_flush(); // broken journal (bad, keep me)
            }

            break;
        }
        
        ttlrdata.ttl = ntohl(rr.tctr.ttl);
        ttlrdata.rdata_pointer = rr.rdata;
        ttlrdata.rdata_size = rr.rdata_size;

        /*
         * Stop at the SOA
         */

        if(rr.tctr.qtype == TYPE_SOA)
        {
            mode ^= 1;

            if(mode == 0)
            {
                /* ADD */

#if ZDB_HAS_NSEC3_SUPPORT
                // NSEC3
                {
                    ret = nsec3replay.vtbl->execute(&nsec3replay);

                    if(FAIL(ret))
                    {
                        dns_resource_record_clear(&rr);
                        // DO NOT: input_stream_close(is);

                        nsec3replay.vtbl->finalise(&nsec3replay);
                        
#if ZDB_HAS_NSEC_SUPPORT
                        nsecreplay.vtbl->finalise(&nsecreplay);
#endif // ZDB_HAS_NSEC_SUPPORT
                        return ret;
                    }
                }
#endif
                
#if ZDB_HAS_NSEC_SUPPORT
                // NSEC
                ret = nsecreplay.vtbl->execute(&nsecreplay);
#endif //ZDB_HAS_NSEC_SUPPORT
            }
        }

        if(!did_remove_soa)
        {
            log_info("journal: %{dnsname}: removing obsolete SOA", zone->origin);

            if(FAIL(ret = zdb_record_delete(&zone->apex->resource_record_set, TYPE_SOA)))
            {
                /**
                * complain
                */

                log_err("journal: %{dnsname}: removing current SOA gave an error: %r", zone->origin, ret);

                /* That's VERY bad ... */

                changes = ret;

                break;
            }

            did_remove_soa = TRUE;
        }

        s32 top = dnsname_to_dnslabel_vector(fqdn, labels);

        if(mode == 0)
        {
            /*
             * "TO DEL" record
             */

#if ICMTL_DUMP_JOURNAL_RECORDS
            rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, rr.rdata };
            log_debug("journal: del %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata);
            logger_flush();
#endif
            bool added_in_chain = FALSE;

#if ZDB_HAS_NSEC3_SUPPORT
            
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if((added_in_chain = (nsec3replay.vtbl->record_del(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                // add everything up until a non-empty terminal is found (the apex will thus be automatically avoided)
                // if the record is a delegation, add everything down too
                /*
                if((top > zone->origin_vector.size) &&
                        (rr.tctr.qtype != TYPE_NSEC3) &&
                        (   (rr.tctr.qtype != TYPE_RRSIG) ||
                            ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3))
                        )
                    )
                {
                    
                }
                */
                ++changes;
            }
            else
            {
                if(top > zone->origin_vector.size)
                {
                    const u8 *above_fqdn = fqdn;
                    for(int i = 1; i < top - zone->origin_vector.size; ++i)
                    {
                        zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i);
                        if(above != NULL)
                        {
                            if(btree_notempty(above->resource_record_set))
                            {
                                break;
                            }
                        }

                        above_fqdn += above_fqdn[0] + 1;
                        nsec3replay.vtbl->record_del(&nsec3replay, above_fqdn, TYPE_NONE, NULL);
                    }

                    zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1);
                    if(rr_label != NULL)
                    {
                        zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_del_cb, &nsec3replay);
                    }
                }
            }
#endif
#if ZDB_HAS_NSEC_SUPPORT
            
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if(!added_in_chain && (added_in_chain = nsecreplay.vtbl->record_del(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0))
            {
                ++changes;
            }
            //else
#endif
            if(!added_in_chain)
            switch(rr.tctr.qtype)
            {
                case TYPE_SOA:
                {
                    rdata_desc rdata = {TYPE_SOA, ttlrdata.rdata_size, ttlrdata.rdata_pointer};
                    log_info("journal: %{dnsname}: SOA: del %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata);

                    s32 m1 = (top - zone->origin_vector.size) - 1;

                    if(m1 == -1)
                    {
                        if(FAIL(ret = zdb_record_delete_exact(&zone->apex->resource_record_set, TYPE_SOA, &ttlrdata))) /* FB done, APEX : no delegation, source is the journal */
                        {
                            if(!did_remove_soa)
                            {
                                log_err("journal: %{dnsname}: SOA: %r", zone->origin, ret);
                            }
                        }
                    }
                    else
                    {
                        if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal
                        {
                            if(!did_remove_soa)
                            {
                                log_err("journal: %{dnsname}: SOA: (2) %r", zone->origin, ret);
                            }
                        }
                    }
                    break;
                }

                default:
                {
#if ZDB_HAS_NSEC3_SUPPORT
                    // NSEC3
                    if(rr.tctr.qtype != TYPE_NSEC3)
                    {
                        if((rr.tctr.qtype != TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr.rdata, rr.rdata_size) != TYPE_NSEC3))
                        {
                            if(ptr_set_avl_find(&downed_fqdn, fqdn) == NULL)
                            {
                                ptr_set_avl_insert(&downed_fqdn, dnsname_dup(fqdn));
                            }
                        }
                    }
                    else
                    {
                        if(!NSEC3_RDATA_IS_OPTOUT(rr.rdata))
                        {
                            zone->_flags &= ~ZDB_ZONE_HAS_OPTOUT_COVERAGE;
                        }
                    }
#endif
                    if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal
                    {
                        // signatures can be removed automatically by maintenance
                        
                        if((rr.tctr.qtype != TYPE_RRSIG) && (ret != ZDB_ERROR_KEY_NOTFOUND))
                        {
                            log_err("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr);
                            log_err("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret);
                        }
                        else
                        {
                            log_debug("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr);
                            log_debug("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret);
                        }
                    }
                }
            }
        }
        else
        {
            /*
             * "TO ADD" record
             */
            
            bool added_in_chain = FALSE;
            
#if ZDB_HAS_NSEC3_SUPPORT

            // returns the number of changes taken into account (0 or 1)
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if((added_in_chain = (nsec3replay.vtbl->record_add(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                ++changes;
            }
            else
            {
                if( (top > zone->origin_vector.size) &&
                    (rr.tctr.qtype != TYPE_NSEC3) &&
                    (   (rr.tctr.qtype != TYPE_RRSIG) ||
                        ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3))
                        )
                    )
                {
                    const u8 *above_fqdn = fqdn;
                    for(int i = 1; i < top - zone->origin_vector.size; ++i)
                    {
                        zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i);
                        if(above != NULL)
                        {
                            if(btree_notempty(above->resource_record_set))
                            {
                                break;
                            }
                        }

                        above_fqdn += above_fqdn[0] + 1;
                        nsec3replay.vtbl->record_add(&nsec3replay, above_fqdn, TYPE_NONE, NULL);
                    }

                    zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1);
                    if(rr_label != NULL)
                    {
                        zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_add_cb, &nsec3replay);
                    }
                }
            }
#endif
#if ZDB_HAS_NSEC_SUPPORT
            
            // returns the number of changes taken into account (0 or 1)
            // 0 : proceed
            // 1 : ignore
            // ? : error
            
            if(!added_in_chain && (added_in_chain = (nsecreplay.vtbl->record_add(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)))
            {
                ++changes;
            }
            //else
#endif
            if(!added_in_chain)
            switch(rr.tctr.qtype)
            {
#if ZDB_HAS_NSEC3_SUPPORT
                case TYPE_NSEC3CHAINSTATE:
                {
                    // create chain if missing ...
                    
                    nsec3_zone_add_from_rdata(zone, rr.rdata_size, rr.rdata);
                    
                    // add the record
                    
                    zdb_packed_ttlrdata *packed_ttlrdata;

                    ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size);
                    packed_ttlrdata->next = NULL;
                    MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size);
                    zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified
                    
                    break;
                }
#endif // ZDB_HAS_NSEC3_SUPPORT
#
                default:
                {
                    zdb_packed_ttlrdata *packed_ttlrdata;

                    ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size);
                    packed_ttlrdata->next = NULL;
                    MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size);

#if ICMTL_DUMP_JOURNAL_RECORDS
                    rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata) };
                    log_debug("journal: add %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata);
                    logger_flush();
#endif
                    if(rr.tctr.qtype == TYPE_SOA)
                    {
                        rr_soa_get_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), current_serialp);
                        rdata_desc rdata = {TYPE_SOA, ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata)};
                        log_info("journal: %{dnsname}: SOA: add %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata);
                    }
                    
                    zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified
                }
            }            
        } // end if ADD

        changes++;
    }

    /*
     * Yes, I know.  If 2^32 changes (add batch + del batch) occurs then it will be seen as an error ...
     */

    if(ISOK(changes))
    {
#if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT
        
        if(has_nsec3 && has_nsec)
        {
            log_warn("journal: %{dnsname}: both NSEC3 and NSEC operations happened, which is not supported by YADIFA. Keeping the original one.", zone->origin);
            
            has_nsec3 = zdb_zone_is_nsec3(zone);
            has_nsec = zdb_zone_is_nsec(zone);
        }        
#endif
        
#if ZDB_HAS_NSEC3_SUPPORT
        nsec3replay.vtbl->execute(&nsec3replay);
#endif

#if ZDB_HAS_NSEC_SUPPORT
        nsecreplay.vtbl->execute(&nsecreplay);
#endif
    }
    
#if ZDB_HAS_NSEC3_SUPPORT
    // has_nsec3 = zdb_zone_is_nsec3(zone);
    nsec3replay.vtbl->finalise(&nsec3replay);
#endif
#if ZDB_HAS_NSEC_SUPPORT
    // has_nsec = zdb_zone_is_nsec(zone);
    nsecreplay.vtbl->finalise(&nsecreplay);
#endif
    
    dns_resource_record_clear(&rr);


    
    return changes;
}