#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include "ldap-int.h"
#include "lutil.h"
static int
do_abandon(
LDAP *ld,
ber_int_t origid,
ber_int_t msgid,
LDAPControl **sctrls,
int sendabandon );
int
ldap_abandon_ext(
LDAP *ld,
int msgid,
LDAPControl **sctrls,
LDAPControl **cctrls )
{
int rc;
Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
rc = ldap_int_client_controls( ld, cctrls );
if ( rc == LDAP_SUCCESS ) {
rc = do_abandon( ld, msgid, msgid, sctrls, 1 );
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
return rc;
}
int
ldap_abandon( LDAP *ld, int msgid )
{
Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
? 0 : -1;
}
int
ldap_pvt_discard(
LDAP *ld,
ber_int_t msgid )
{
int rc;
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
rc = do_abandon( ld, msgid, msgid, NULL, 0 );
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
return rc;
}
static int
do_abandon(
LDAP *ld,
ber_int_t origid,
ber_int_t msgid,
LDAPControl **sctrls,
int sendabandon )
{
BerElement *ber;
int i, err;
Sockbuf *sb;
LDAPRequest *lr;
Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
origid, msgid, 0 );
start_again:;
lr = ld->ld_requests;
while ( lr != NULL ) {
if ( lr->lr_msgid == msgid ) {
break;
}
if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
(void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
sctrls, sendabandon );
goto start_again;
}
lr = lr->lr_next;
}
if ( lr != NULL ) {
if ( origid == msgid && lr->lr_parent != NULL ) {
ld->ld_errno = LDAP_PARAM_ERROR;
return( LDAP_PARAM_ERROR );
}
if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
sendabandon = 0;
}
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
err = ldap_msgdelete( ld, msgid );
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
if ( err == 0 ) {
ld->ld_errno = LDAP_SUCCESS;
return LDAP_SUCCESS;
}
if ( lr != NULL ) {
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
if ( lr->lr_msgid == msgid ) {
break;
}
}
}
err = 0;
if ( sendabandon ) {
if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
err = -1;
ld->ld_errno = LDAP_SERVER_DOWN;
} else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
err = -1;
ld->ld_errno = LDAP_NO_MEMORY;
} else {
i = ++(ld)->ld_msgid;
#ifdef LDAP_CONNECTIONLESS
if ( LDAP_IS_UDP(ld) ) {
struct sockaddr sa = {0};
err = ber_write( ber, &sa, sizeof(sa), 0 );
}
if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
LDAP_VERSION2 )
{
char *dn = ld->ld_options.ldo_cldapdn;
if (!dn) dn = "";
err = ber_printf( ber, "{isti",
i, dn,
LDAP_REQ_ABANDON, msgid );
} else
#endif
{
err = ber_printf( ber, "{iti",
i,
LDAP_REQ_ABANDON, msgid );
}
if ( err == -1 ) {
ld->ld_errno = LDAP_ENCODING_ERROR;
} else {
if ( ldap_int_put_controls( ld, sctrls, ber )
!= LDAP_SUCCESS )
{
err = -1;
} else {
err = ber_printf( ber, "N}" );
if ( err == -1 ) {
ld->ld_errno = LDAP_ENCODING_ERROR;
}
}
}
if ( err == -1 ) {
ber_free( ber, 1 );
} else {
if ( lr != NULL ) {
assert( lr->lr_conn != NULL );
sb = lr->lr_conn->lconn_sb;
} else {
sb = ld->ld_sb;
}
if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
ld->ld_errno = LDAP_SERVER_DOWN;
err = -1;
} else {
err = 0;
}
}
}
}
if ( lr != NULL ) {
if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
ldap_free_connection( ld, lr->lr_conn, 0, 1 );
}
if ( origid == msgid ) {
ldap_free_request( ld, lr );
} else {
lr->lr_abandoned = 1;
}
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
#endif
i = 0;
if ( ld->ld_nabandoned == 0 ||
ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
{
ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
}
if ( err != -1 ) {
ld->ld_errno = LDAP_SUCCESS;
}
#ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
return( ld->ld_errno );
}
int
ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
{
int begin,
end,
rc = 0;
assert( n >= 0 );
assert( id >= 0 );
begin = 0;
end = n - 1;
if ( n <= 0 || id < v[ begin ] ) {
*idxp = 0;
} else if ( id > v[ end ] ) {
*idxp = n;
} else {
int pos;
ber_int_t curid;
do {
pos = (begin + end)/2;
curid = v[ pos ];
if ( id < curid ) {
end = pos - 1;
} else if ( id > curid ) {
begin = ++pos;
} else {
rc = 1;
break;
}
} while ( end >= begin );
*idxp = pos;
}
return rc;
}
int
ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
{
ber_int_t *v;
ber_len_t n;
int i;
assert( vp != NULL );
assert( np != NULL );
assert( *np >= 0 );
assert( idx >= 0 );
assert( idx <= *np );
n = *np;
v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
if ( v == NULL ) {
return -1;
}
*vp = v;
for ( i = n; i > idx; i-- ) {
v[ i ] = v[ i - 1 ];
}
v[ idx ] = id;
++(*np);
return 0;
}
int
ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
{
ber_int_t *v;
ber_len_t n;
int i;
assert( vp != NULL );
assert( np != NULL );
assert( *np >= 0 );
assert( idx >= 0 );
assert( idx < *np );
v = *vp;
assert( v[ idx ] == id );
--(*np);
n = *np;
for ( i = idx; i < n; i++ ) {
v[ i ] = v[ i + 1 ];
}
return 0;
}