static isc_boolean_t
zonekey_on_list(dst_key_t *key) {
	keynode_t *keynode;
	for (keynode = ISC_LIST_HEAD(keylist);
	     keynode != NULL;
	     keynode = ISC_LIST_NEXT(keynode, link))
	{
		if (dst_key_compare(keynode->key, key))
			return (ISC_TRUE);
	}
	return (ISC_FALSE);
}
isc_result_t
dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
	isc_result_t result;
	dns_name_t *keyname;
	dns_rbtnode_t *node = NULL;
	dns_keynode_t *knode = NULL, **kprev = NULL;

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(dstkey != NULL);

	keyname = dst_key_name(dstkey);

	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);

	if (result == DNS_R_PARTIALMATCH)
		result = ISC_R_NOTFOUND;
	if (result != ISC_R_SUCCESS)
		goto finish;

	if (node->data == NULL) {
		result = ISC_R_NOTFOUND;
		goto finish;
	}

	knode = node->data;
	if (knode->next == NULL && knode->key != NULL &&
	    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
	{
		result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
		goto finish;
	}

	kprev = (dns_keynode_t **)(void *)&node->data;
	while (knode != NULL) {
		if (knode->key != NULL &&
		    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
			break;
		kprev = &knode->next;
		knode = knode->next;
	}

	if (knode != NULL) {
		if (knode->key != NULL)
			dst_key_free(&knode->key);
		/*
		 * This is equivalent to:
		 * dns_keynode_attach(knode->next, &tmp);
		 * dns_keynode_detach(kprev);
		 * dns_keynode_attach(tmp, &kprev);
		 * dns_keynode_detach(&tmp);
		 */
		*kprev = knode->next;
		knode->next = NULL;
		dns_keynode_detach(keytable->mctx, &knode);
	} else
		result = DNS_R_PARTIALMATCH;
  finish:
	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
	return (result);
}
static isc_result_t
insert(dns_keytable_t *keytable, isc_boolean_t managed,
       dns_name_t *keyname, dst_key_t **keyp)
{
	isc_result_t result;
	dns_keynode_t *knode = NULL;
	dns_rbtnode_t *node;

	REQUIRE(keyp == NULL || *keyp != NULL);
	REQUIRE(VALID_KEYTABLE(keytable));

	result = dns_keynode_create(keytable->mctx, &knode);
	if (result != ISC_R_SUCCESS)
		return (result);

	knode->managed = managed;

	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);

	node = NULL;
	result = dns_rbt_addnode(keytable->table, keyname, &node);

	if (keyp != NULL) {
		if (result == ISC_R_EXISTS) {
			/* Key already in table? */
			dns_keynode_t *k;
			for (k = node->data; k != NULL; k = k->next) {
				if (k->key == NULL) {
					k->key = *keyp;
					*keyp = NULL; /* transfer ownership */
					break;
				}
				if (dst_key_compare(k->key, *keyp) == ISC_TRUE)
					break;
			}

			if (k == NULL)
				result = ISC_R_SUCCESS;
			else if (*keyp != NULL)
				dst_key_free(keyp);
		}

		if (result == ISC_R_SUCCESS) {
			knode->key = *keyp;
			knode->next = node->data;
			*keyp = NULL;
		}
	}

	if (result == ISC_R_SUCCESS) {
		node->data = knode;
		knode = NULL;
	}

	/* Key was already there?  That's the same as a success */
	if (result == ISC_R_EXISTS)
		result = ISC_R_SUCCESS;

	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);

	if (knode != NULL)
		dns_keynode_detach(keytable->mctx, &knode);

	return (result);
}