#ifdef LDAP_RESPONSE_RB_TREE
#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/unistd.h>
#include "ldap-int.h"
#include "rb.h"
#include "rb_response.h"
#include "ldap_rb_stats.h"
#define RBNODE_TO_LM(n) \
((LDAPMessage *)((uintptr_t)n - offsetof(LDAPMessage, lm_link)))
static int ldap_resp_rbt_compare_nodes( const struct rb_node *n1,
const struct rb_node *n2 )
{
const ber_int_t msgid1 = RBNODE_TO_LM(n1)->lm_msgid;
const ber_int_t msgid2 = RBNODE_TO_LM(n2)->lm_msgid;
if ( msgid1 < msgid2 ) {
return -1;
}
if ( msgid1 > msgid2 ) {
return 1;
}
return 0;
}
static int ldap_resp_rbt_compare_key( const struct rb_node *n,
const void *v )
{
const ber_int_t msgid1 = RBNODE_TO_LM(n)->lm_msgid;
const ber_int_t msgid2 = *((ber_int_t*)v);
if ( msgid1 < msgid2 ) {
return -1;
}
if ( msgid1 > msgid2 ) {
return 1;
}
return 0;
}
static const struct rb_tree_ops ldap_resp_rbt_ops = {
.rbto_compare_nodes = ldap_resp_rbt_compare_nodes,
.rbto_compare_key = ldap_resp_rbt_compare_key,
};
void ldap_resp_rbt_create( LDAP *ld )
{
assert( ld != NULL );
ld->ld_rbt_responses = LDAP_CALLOC( 1, sizeof(*ld->ld_rbt_responses) );
assert( ld->ld_rbt_responses != NULL );
rb_tree_init( ld->ld_rbt_responses, &ldap_resp_rbt_ops );
}
void ldap_resp_rbt_free( LDAP *ld )
{
LDAPMessage *lm;
LDAPMessage *doomed;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
lm = ldap_resp_rbt_get_first_msg( ld );
while ( lm ) {
doomed = lm;
lm = ldap_resp_rbt_get_next_msg( ld, lm );
ldap_resp_rbt_delete_msg( ld, doomed );
}
free( ld->ld_rbt_responses );
ld->ld_rbt_responses = NULL;
}
void ldap_resp_rbt_insert_msg( LDAP *ld, LDAPMessage *lm )
{
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
rb_tree_insert_node( ld->ld_rbt_responses, &lm->lm_link );
if ( LDAP_RB_STATS_COUNT_ENABLED() ) {
LDAP_RB_STATS_COUNT( ld->ld_rbt_responses->rbt_count, lm->lm_msgid, lm );
}
}
void ldap_resp_rbt_delete_msg( LDAP *ld, LDAPMessage *lm )
{
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
assert( lm != NULL );
rb_tree_remove_node( ld->ld_rbt_responses, &lm->lm_link );
ldap_msgfree( lm );
if ( LDAP_RB_STATS_COUNT_ENABLED() ) {
LDAP_RB_STATS_COUNT( ld->ld_rbt_responses->rbt_count, lm->lm_msgid, lm );
}
}
void ldap_resp_rbt_unlink_msg( LDAP *ld, LDAPMessage *lm)
{
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
assert( lm != NULL );
rb_tree_remove_node( ld->ld_rbt_responses, &lm->lm_link );
if ( LDAP_RB_STATS_COUNT_ENABLED() ) {
LDAP_RB_STATS_COUNT( ld->ld_rbt_responses->rbt_count, lm->lm_msgid, lm );
}
}
void ldap_resp_rbt_unlink_partial_msg( LDAP *ld, LDAPMessage *lm )
{
LDAPMessage *nextInChain;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
assert( lm != NULL );
rb_tree_remove_node( ld->ld_rbt_responses, &lm->lm_link );
nextInChain = lm->lm_chain;
nextInChain->lm_chain_tail = ( lm->lm_chain_tail != lm ) ? lm->lm_chain_tail : lm->lm_chain;
rb_tree_insert_node( ld->ld_rbt_responses, &nextInChain->lm_link );
lm->lm_chain = NULL;
lm->lm_chain_tail = NULL;
}
LDAPMessage *ldap_resp_rbt_find_msg( LDAP *ld, ber_int_t msgid )
{
struct rb_node* rbn = NULL;
LDAPMessage* lm = NULL;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
rbn = rb_tree_find_node( ld->ld_rbt_responses, &msgid );
if ( rbn ) {
lm = RBNODE_TO_LM( rbn );
}
return lm;
}
LDAPMessage *ldap_resp_rbt_get_first_msg( LDAP *ld )
{
struct rb_node *rbn;
LDAPMessage *lm = NULL;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
rbn = rb_tree_iterate( ld->ld_rbt_responses, NULL, RB_DIR_RIGHT );
if ( rbn ) {
lm = RBNODE_TO_LM( rbn );
}
return lm;
}
LDAPMessage *ldap_resp_rbt_get_next_msg( LDAP *ld, LDAPMessage *lm )
{
struct rb_node *rbn;
LDAPMessage *next = NULL;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
rbn = rb_tree_iterate( ld->ld_rbt_responses, &lm->lm_link, RB_DIR_LEFT );
if ( rbn ) {
next = RBNODE_TO_LM( rbn );
}
return next;
}
void ldap_resp_rbt_dump( LDAP* ld )
{
LDAPMessage *lm;
LDAPMessage *l;
struct rb_node *rbn;
assert( ld != NULL );
assert( ld->ld_rbt_responses != NULL );
fprintf( stderr, "** ld %p Red-Black Tree Response Queue:\n", (void *)ld );
rbn = rb_tree_iterate( ld->ld_rbt_responses, NULL, RB_DIR_RIGHT );
if ( rbn == NULL ) {
fprintf( stderr, " Empty\n" );
}
for ( ; rbn != NULL; rbn = rb_tree_iterate( ld->ld_rbt_responses, rbn, RB_DIR_LEFT ) )
{
lm = RBNODE_TO_LM(rbn);
fprintf( stderr, " * msgid %d, type %lu\n",
lm->lm_msgid,
(unsigned long) lm->lm_msgtype );
l = lm->lm_chain;;
if ( l != NULL )
{
fprintf( stderr, " chained responses:\n" );
for ( ; l != NULL; l = l->lm_chain )
{
fprintf( stderr,
" * msgid %d, type %lu\n",
l->lm_msgid,
(unsigned long) l->lm_msgtype );
}
}
}
}
#endif