isc_result_t
dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
			     dns_keynode_t **nextnodep)
{
	isc_result_t result;
	dns_keynode_t *knode;

	/*
	 * Search for the next key with the same properties as 'keynode' in
	 * 'keytable'.
	 */

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(VALID_KEYNODE(keynode));
	REQUIRE(nextnodep != NULL && *nextnodep == NULL);

	for (knode = keynode->next; knode != NULL; knode = knode->next) {
		if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
		    dst_key_id(keynode->key) == dst_key_id(knode->key))
			break;
	}
	if (knode != NULL) {
		LOCK(&keytable->lock);
		keytable->active_nodes++;
		UNLOCK(&keytable->lock);
		result = ISC_R_SUCCESS;
		*nextnodep = knode;
	} else
		result = ISC_R_NOTFOUND;

	return (result);
}
isc_boolean_t
dns_keynode_managed(dns_keynode_t *keynode) {
	/*
	 * Is this a managed key?
	 */
	REQUIRE(VALID_KEYNODE(keynode));

	return (keynode->managed);
}
void
dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) {
	dns_keynode_t *next = NULL, *node = *keynode;
	REQUIRE(VALID_KEYNODE(node));
	while (node != NULL) {
		next = node->next;
		dns_keynode_detach(mctx, &node);
		node = next;
	}
	*keynode = NULL;
}
dst_key_t *
dns_keynode_key(dns_keynode_t *keynode) {

	/*
	 * Get the DST key associated with keynode.
	 */

	REQUIRE(VALID_KEYNODE(keynode));

	return (keynode->key);
}
static void
free_keynode(void *node, void *arg) {
	dns_keynode_t *keynode = node;
	isc_mem_t *mctx = arg;

	REQUIRE(VALID_KEYNODE(keynode));
	dst_key_free(&keynode->key);
	if (keynode->next != NULL)
		free_keynode(keynode->next, mctx);
	isc_mem_put(mctx, keynode, sizeof(dns_keynode_t));
}
void
dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) {
	unsigned int refs;
	dns_keynode_t *node = *keynode;
	REQUIRE(VALID_KEYNODE(node));
	isc_refcount_decrement(&node->refcount, &refs);
	if (refs == 0) {
		if (node->key != NULL)
			dst_key_free(&node->key);
		isc_refcount_destroy(&node->refcount);
		isc_mem_put(mctx, node, sizeof(dns_keynode_t));
	}
	*keynode = NULL;
}
void
dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
{
	/*
	 * Give back a keynode found via dns_keytable_findkeynode().
	 */

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));

	LOCK(&keytable->lock);
	INSIST(keytable->active_nodes > 0);
	keytable->active_nodes--;
	UNLOCK(&keytable->lock);

	dns_keynode_detach(keytable->mctx, keynodep);
}
void
dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source,
			   dns_keynode_t **target)
{
	/*
	 * Give back a keynode found via dns_keytable_findkeynode().
	 */

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(VALID_KEYNODE(source));
	REQUIRE(target != NULL && *target == NULL);

	LOCK(&keytable->lock);
	keytable->active_nodes++;
	UNLOCK(&keytable->lock);

	dns_keynode_attach(source, target);
}
isc_result_t
dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
			 dns_keynode_t **nextnodep)
{
	/*
	 * Return the next key after 'keynode', regardless of
	 * properties.
	 */

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(VALID_KEYNODE(keynode));
	REQUIRE(nextnodep != NULL && *nextnodep == NULL);

	if (keynode->next == NULL)
		return (ISC_R_NOTFOUND);

	dns_keynode_attach(keynode->next, nextnodep);
	LOCK(&keytable->lock);
	keytable->active_nodes++;
	UNLOCK(&keytable->lock);

	return (ISC_R_SUCCESS);
}
void
dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
	REQUIRE(VALID_KEYNODE(source));
	isc_refcount_increment(&source->refcount, NULL);
	*target = source;
}