mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-30 13:30:57 +08:00
dc07e765f2
This commit includes many changes. All changes compile under NT but have not been tested under UNIX. A Summary of changes (likely incomplete): NT changes: Removed lint. Clean up configuration support for "Debug", "Release", "SDebug", and "SRelease" configurations. Share output directories for clients, libraries, and slapd. (maybe they should be combined further and moved to build/{,S}{Debug,Release}). Enable threading when _MT is defined. Enable debuging when _DEBUG is defined. Disable setting of NDEBUG under Release/SRelease. Asserts are disabled in <ac/assert.h> when LDAP_DEBUG is not defined. Added 'build/main.dsp' Master project. Removed non-slapd projects from slapd.dsp (see main.dsp). Removed replaced many uses of _WIN32 macro with feature based macros. ldap_cdefs.h changes #define LDAP_CONST const (see below) #define LDAP_F(type) LDAP_F_PRE type LDAP_F_POST To allow specifiers to be added before and after the type declaration. (For DLL handling) LBER/LDAP changes Namespace changes: s/lber_/ber_/ for here and there. s/NAME_ERROR/LDAP_NAME_ERROR/g Deleted NULLMSG and other NULL* macros for namespace reasons. "const" libraries. Installed headers (ie: lber.h, ldap.h) use LDAP_CONST macro. Normally set to 'const' when __STDC__. Can be set externally to enable/disable 'constification' of external interface. Internal interface always uses 'const'. Did not fix warnings in -lldif (in lieu of new LDIF parser). Added _ext API implementations (excepting search and bind). Need to implement ldap_int_get_controls() for reponses with controls. Added numberous assert() checks. LDAP_R _MT defines HAVE_NT_THREADS Added numberous assert() checks. Changed ldap_pthread_t back to unsigned long. Used cast to HANDLE in _join(). LDBM Replaced _WIN32 with HAVE_SYSLOG ud Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). slapd Made connection sockbuf field a pointer to a sockbuf. This removed slap.h dependency on lber-int.h. lber-int.h now only included by those files needing to mess with the sockbuf. Used ber_* functions/macros to access sockbuf internals whenever possible. Added version string if MKVERSION is not defined. (MKVERSION needs to be set under UNIX). Removed FD_SET unsigned lint slapd/tools Used EXEEXT to added ".exe" to routines. Need to define EXEEXT under UNIX. ldappasswd Added ldappasswd.dsp. Ported to NT. Used getpid() to seed rand(). nt_debug Minor cleanup. Added "portable.h" include and used <ac/*.h> where appropriate. Added const to char* format argument.
898 lines
20 KiB
C
898 lines
20 KiB
C
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/socket.h>
|
|
#include <ac/errno.h>
|
|
#include <ac/signal.h>
|
|
#include <ac/string.h>
|
|
#include <ac/time.h>
|
|
|
|
#include "slap.h"
|
|
|
|
/* we need LBER internals */
|
|
#include "../../libraries/liblber/lber-int.h"
|
|
|
|
/* protected by connections_mutex */
|
|
static ldap_pvt_thread_mutex_t connections_mutex;
|
|
static Connection *connections = NULL;
|
|
static int conn_index = -1;
|
|
static long conn_nextid = 0;
|
|
|
|
/* structure state (protected by connections_mutex) */
|
|
#define SLAP_C_UNINITIALIZED 0x0 /* MUST BE ZERO (0) */
|
|
#define SLAP_C_UNUSED 0x1
|
|
#define SLAP_C_USED 0x2
|
|
|
|
/* connection state (protected by c_mutex ) */
|
|
#define SLAP_C_INVALID 0x0 /* MUST BE ZERO (0) */
|
|
#define SLAP_C_INACTIVE 0x1 /* zero threads */
|
|
#define SLAP_C_ACTIVE 0x2 /* one or more threads */
|
|
#define SLAP_C_BINDING 0x3 /* binding */
|
|
#define SLAP_C_CLOSING 0x4 /* closing */
|
|
|
|
void slapd_remove(int s);
|
|
static Connection* connection_get( int s );
|
|
|
|
static int connection_input( Connection *c );
|
|
static void connection_close( Connection *c );
|
|
|
|
static int connection_op_activate( Connection *conn, Operation *op );
|
|
static int connection_resched( Connection *conn );
|
|
|
|
struct co_arg {
|
|
Connection *co_conn;
|
|
Operation *co_op;
|
|
};
|
|
|
|
/*
|
|
* Initialize connection management infrastructure.
|
|
*/
|
|
int connections_init(void)
|
|
{
|
|
int i;
|
|
|
|
assert( connections == NULL );
|
|
|
|
if( connections != NULL) {
|
|
Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n",
|
|
0, 0, 0 );
|
|
return -1;
|
|
}
|
|
|
|
/* should check return of every call */
|
|
ldap_pvt_thread_mutex_init( &connections_mutex );
|
|
|
|
connections = (Connection *) calloc( dtblsize, sizeof(Connection) );
|
|
|
|
if( connections == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"connections_init: allocation (%d*%ld) of connection array failed.\n",
|
|
dtblsize, (long) sizeof(Connection), 0 );
|
|
return -1;
|
|
}
|
|
|
|
for ( i = 0; i < dtblsize; i++ )
|
|
memset( &connections[i], 0, sizeof(Connection) );
|
|
|
|
/*
|
|
* per entry initialization of the Connection array initialization
|
|
* will be done by connection_init()
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Destroy connection management infrastructure.
|
|
*/
|
|
int connections_destroy(void)
|
|
{
|
|
int i;
|
|
|
|
/* should check return of every call */
|
|
|
|
if( connections == NULL) {
|
|
Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n",
|
|
0, 0, 0 );
|
|
return -1;
|
|
}
|
|
|
|
for ( i = 0; i < dtblsize; i++ ) {
|
|
if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
|
|
ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
|
|
ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
|
|
ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
|
|
}
|
|
|
|
free( &connections[i] );
|
|
}
|
|
|
|
free( connections );
|
|
connections = NULL;
|
|
|
|
ldap_pvt_thread_mutex_destroy( &connections_mutex );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* shutdown all connections
|
|
*/
|
|
int connections_shutdown(void)
|
|
{
|
|
int i;
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
for ( i = 0; i < dtblsize; i++ ) {
|
|
if( connections[i].c_struct_state != SLAP_C_USED ) {
|
|
continue;
|
|
}
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections[i].c_mutex );
|
|
connection_closing( &connections[i] );
|
|
connection_close( &connections[i] );
|
|
ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex );
|
|
}
|
|
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Connection* connection_get( int s )
|
|
{
|
|
Connection *c = NULL;
|
|
|
|
assert( connections != NULL );
|
|
|
|
if(s < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef HAVE_WINSOCK
|
|
assert( connections[s].c_struct_state == SLAP_C_USED );
|
|
assert( connections[s].c_conn_state != SLAP_C_INVALID );
|
|
assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
|
|
|
|
c = &connections[s];
|
|
#else
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i<dtblsize; i++) {
|
|
if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
|
|
assert( connections[i].c_conn_state == SLAP_C_INVALID );
|
|
assert( connections[i].c_sb == 0 );
|
|
break;
|
|
}
|
|
|
|
if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
|
|
assert( connections[i].c_conn_state == SLAP_C_INVALID );
|
|
assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
|
|
continue;
|
|
}
|
|
|
|
assert( connections[i].c_struct_state == SLAP_C_USED );
|
|
assert( connections[i].c_conn_state != SLAP_C_INVALID );
|
|
assert( ber_pvt_sb_in_use( connections[i].c_sb ) );
|
|
|
|
if( ber_pvt_sb_get_desc( connections[i].c_sb ) == s ) {
|
|
c = &connections[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if( c != NULL ) {
|
|
/* we do this BEFORE locking to aid in debugging */
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_get(%d): got connid=%ld\n",
|
|
s, c->c_connid, 0 );
|
|
|
|
ldap_pvt_thread_mutex_lock( &c->c_mutex );
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static void connection_return( Connection *c )
|
|
{
|
|
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
|
|
}
|
|
|
|
long connection_init(
|
|
int s,
|
|
const char* name,
|
|
const char* addr)
|
|
{
|
|
long id;
|
|
Connection *c;
|
|
assert( connections != NULL );
|
|
|
|
if( s < 0 ) {
|
|
return -1;
|
|
}
|
|
|
|
assert( s >= 0 );
|
|
#ifndef HAVE_WINSOCK
|
|
assert( s < dtblsize );
|
|
#endif
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
#ifndef HAVE_WINSOCK
|
|
c = &connections[s];
|
|
|
|
#else
|
|
{
|
|
int i;
|
|
|
|
for( i=0; i < dtblsize; i++) {
|
|
if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
|
|
assert( connections[i].c_sb == 0 );
|
|
c = &connections[i];
|
|
break;
|
|
}
|
|
|
|
if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
|
|
assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
|
|
c = &connections[i];
|
|
break;
|
|
}
|
|
|
|
assert( connections[i].c_struct_state == SLAP_C_USED );
|
|
assert( connections[i].c_conn_state != SLAP_C_INVALID );
|
|
assert( ber_pvt_sb_in_use( connections[i].c_sb ));
|
|
}
|
|
|
|
if( c == NULL ) {
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return -1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
assert( c != NULL );
|
|
assert( c->c_struct_state != SLAP_C_USED );
|
|
assert( c->c_conn_state == SLAP_C_INVALID );
|
|
|
|
if( c->c_struct_state == SLAP_C_UNINITIALIZED ) {
|
|
c->c_dn = NULL;
|
|
c->c_cdn = NULL;
|
|
c->c_client_name = NULL;
|
|
c->c_client_addr = NULL;
|
|
c->c_ops = NULL;
|
|
c->c_pending_ops = NULL;
|
|
|
|
c->c_sb = ber_sockbuf_alloc( );
|
|
|
|
/* should check status of thread calls */
|
|
ldap_pvt_thread_mutex_init( &c->c_mutex );
|
|
ldap_pvt_thread_mutex_init( &c->c_write_mutex );
|
|
ldap_pvt_thread_cond_init( &c->c_write_cv );
|
|
|
|
c->c_struct_state = SLAP_C_UNUSED;
|
|
}
|
|
|
|
ldap_pvt_thread_mutex_lock( &c->c_mutex );
|
|
|
|
assert( c->c_struct_state == SLAP_C_UNUSED );
|
|
assert( c->c_dn == NULL );
|
|
assert( c->c_cdn == NULL );
|
|
assert( c->c_client_name == NULL );
|
|
assert( c->c_client_addr == NULL );
|
|
assert( c->c_ops == NULL );
|
|
assert( c->c_pending_ops == NULL );
|
|
|
|
c->c_client_name = ch_strdup( name == NULL ? "" : name );
|
|
c->c_client_addr = ch_strdup( addr );
|
|
|
|
c->c_n_ops_received = 0;
|
|
#ifdef LDAP_COUNTERS
|
|
c->c_n_ops_executing = 0;
|
|
c->c_n_ops_pending = 0;
|
|
c->c_n_ops_completed = 0;
|
|
#endif
|
|
|
|
c->c_starttime = slap_get_time();
|
|
|
|
ber_pvt_sb_set_desc( c->c_sb, s );
|
|
ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
|
|
|
|
if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"connection_init(%d, %s, %s): set nonblocking failed\n",
|
|
s, c->c_client_name, c->c_client_addr);
|
|
}
|
|
|
|
id = c->c_connid = conn_nextid++;
|
|
|
|
c->c_conn_state = SLAP_C_INACTIVE;
|
|
c->c_struct_state = SLAP_C_USED;
|
|
|
|
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
|
|
return id;
|
|
}
|
|
|
|
static void
|
|
connection_destroy( Connection *c )
|
|
{
|
|
assert( connections != NULL );
|
|
assert( c != NULL );
|
|
assert( c->c_struct_state != SLAP_C_UNUSED );
|
|
assert( c->c_conn_state != SLAP_C_INVALID );
|
|
assert( c->c_ops == NULL );
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
c->c_struct_state = SLAP_C_UNUSED;
|
|
c->c_conn_state = SLAP_C_INVALID;
|
|
|
|
c->c_version = 0;
|
|
c->c_protocol = 0;
|
|
|
|
c->c_starttime = 0;
|
|
|
|
if(c->c_dn != NULL) {
|
|
free(c->c_dn);
|
|
c->c_dn = NULL;
|
|
}
|
|
if(c->c_cdn != NULL) {
|
|
free(c->c_cdn);
|
|
c->c_cdn = NULL;
|
|
}
|
|
if(c->c_client_name != NULL) {
|
|
free(c->c_client_name);
|
|
c->c_client_name = NULL;
|
|
}
|
|
if(c->c_client_addr != NULL) {
|
|
free(c->c_client_addr);
|
|
c->c_client_addr = NULL;
|
|
}
|
|
|
|
if ( ber_pvt_sb_in_use(c->c_sb) ) {
|
|
int sd = ber_pvt_sb_get_desc(c->c_sb);
|
|
|
|
slapd_remove( sd );
|
|
ber_pvt_sb_close( c->c_sb );
|
|
|
|
Statslog( LDAP_DEBUG_STATS,
|
|
"conn=%d fd=%d closed.\n",
|
|
c->c_connid, sd, 0, 0, 0 );
|
|
}
|
|
|
|
ber_pvt_sb_destroy( c->c_sb );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
}
|
|
|
|
int connection_state_closing( Connection *c )
|
|
{
|
|
/* connection must be locked by caller */
|
|
int state;
|
|
assert( c != NULL );
|
|
assert( c->c_struct_state == SLAP_C_USED );
|
|
|
|
state = c->c_conn_state;
|
|
|
|
assert( state != SLAP_C_INVALID );
|
|
|
|
return state == SLAP_C_CLOSING;
|
|
}
|
|
|
|
void connection_closing( Connection *c )
|
|
{
|
|
assert( connections != NULL );
|
|
assert( c != NULL );
|
|
assert( c->c_struct_state == SLAP_C_USED );
|
|
assert( c->c_conn_state != SLAP_C_INVALID );
|
|
|
|
if( c->c_conn_state != SLAP_C_CLOSING ) {
|
|
Operation *o;
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_closing: readying conn=%ld sd=%d for close.\n",
|
|
c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
|
|
|
|
/* update state to closing */
|
|
c->c_conn_state = SLAP_C_CLOSING;
|
|
|
|
/* don't listen on this port anymore */
|
|
slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 );
|
|
|
|
/* shutdown I/O -- not yet implemented */
|
|
|
|
/* abandon active operations */
|
|
for( o = c->c_ops; o != NULL; o = o->o_next ) {
|
|
ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
|
|
o->o_abandon = 1;
|
|
ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
|
|
}
|
|
|
|
/* remove pending operations */
|
|
for( o = slap_op_pop( &c->c_pending_ops );
|
|
o != NULL;
|
|
o = slap_op_pop( &c->c_pending_ops ) )
|
|
{
|
|
slap_op_free( o );
|
|
}
|
|
|
|
/* wake write blocked operations */
|
|
slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
|
|
ldap_pvt_thread_cond_signal( &c->c_write_cv );
|
|
}
|
|
}
|
|
|
|
static void connection_close( Connection *c )
|
|
{
|
|
assert( connections != NULL );
|
|
assert( c != NULL );
|
|
assert( c->c_struct_state == SLAP_C_USED );
|
|
assert( c->c_conn_state == SLAP_C_CLOSING );
|
|
|
|
if( c->c_ops != NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_close: deferring conn=%ld sd=%d.\n",
|
|
c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
|
|
|
|
return;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n",
|
|
c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
|
|
|
|
connection_destroy( c );
|
|
}
|
|
|
|
long connections_nextid(void)
|
|
{
|
|
long id;
|
|
assert( connections != NULL );
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
id = conn_nextid;
|
|
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
|
|
return id;
|
|
}
|
|
|
|
Connection* connection_first(void)
|
|
{
|
|
assert( connections != NULL );
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
assert( conn_index == -1 );
|
|
conn_index = 0;
|
|
|
|
return connection_next(NULL);
|
|
}
|
|
|
|
Connection* connection_next(Connection *c)
|
|
{
|
|
assert( connections != NULL );
|
|
assert( conn_index != -1 );
|
|
assert( conn_index <= dtblsize );
|
|
|
|
if( c != NULL ) {
|
|
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
|
|
}
|
|
|
|
c = NULL;
|
|
|
|
for(; conn_index < dtblsize; conn_index++) {
|
|
if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) {
|
|
assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
|
|
#ifndef HAVE_WINSOCK
|
|
continue;
|
|
#else
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
if( connections[conn_index].c_struct_state == SLAP_C_USED ) {
|
|
assert( connections[conn_index].c_conn_state != SLAP_C_INVALID );
|
|
c = &connections[conn_index++];
|
|
break;
|
|
}
|
|
|
|
assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED );
|
|
assert( connections[conn_index].c_conn_state == SLAP_C_INVALID );
|
|
}
|
|
|
|
if( c != NULL ) {
|
|
ldap_pvt_thread_mutex_lock( &c->c_mutex );
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
void connection_done(Connection *c)
|
|
{
|
|
assert( connections != NULL );
|
|
assert( conn_index != -1 );
|
|
assert( conn_index <= dtblsize );
|
|
|
|
if( c != NULL ) {
|
|
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
|
|
}
|
|
|
|
conn_index = -1;
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
}
|
|
|
|
/*
|
|
* connection_activity - handle the request operation op on connection
|
|
* conn. This routine figures out what kind of operation it is and
|
|
* calls the appropriate stub to handle it.
|
|
*/
|
|
|
|
static void *
|
|
connection_operation( void *arg_v )
|
|
{
|
|
struct co_arg *arg = arg_v;
|
|
int tag = arg->co_op->o_tag;
|
|
Connection *conn = arg->co_conn;
|
|
|
|
#ifdef LDAP_COUNTERS
|
|
ldap_pvt_thread_mutex_lock( &num_ops_mutex );
|
|
num_ops_initiated++;
|
|
ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
|
|
#endif
|
|
|
|
switch ( tag ) {
|
|
case LDAP_REQ_BIND:
|
|
do_bind( conn, arg->co_op );
|
|
break;
|
|
|
|
#ifdef LDAP_COMPAT30
|
|
case LDAP_REQ_UNBIND_30:
|
|
#endif
|
|
case LDAP_REQ_UNBIND:
|
|
do_unbind( conn, arg->co_op );
|
|
break;
|
|
|
|
case LDAP_REQ_ADD:
|
|
do_add( conn, arg->co_op );
|
|
break;
|
|
|
|
#ifdef LDAP_COMPAT30
|
|
case LDAP_REQ_DELETE_30:
|
|
#endif
|
|
case LDAP_REQ_DELETE:
|
|
do_delete( conn, arg->co_op );
|
|
break;
|
|
|
|
case LDAP_REQ_MODRDN:
|
|
do_modrdn( conn, arg->co_op );
|
|
break;
|
|
|
|
case LDAP_REQ_MODIFY:
|
|
do_modify( conn, arg->co_op );
|
|
break;
|
|
|
|
case LDAP_REQ_COMPARE:
|
|
do_compare( conn, arg->co_op );
|
|
break;
|
|
|
|
case LDAP_REQ_SEARCH:
|
|
do_search( conn, arg->co_op );
|
|
break;
|
|
|
|
#ifdef LDAP_COMPAT30
|
|
case LDAP_REQ_ABANDON_30:
|
|
#endif
|
|
case LDAP_REQ_ABANDON:
|
|
do_abandon( conn, arg->co_op );
|
|
break;
|
|
|
|
default:
|
|
Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
|
|
arg->co_op->o_tag, 0, 0 );
|
|
break;
|
|
}
|
|
|
|
#ifdef LDAP_COUNTERS
|
|
ldap_pvt_thread_mutex_lock( &num_ops_mutex );
|
|
num_ops_completed++;
|
|
ldap_pvt_thread_mutex_unlock( &num_ops_mutex );
|
|
#endif
|
|
|
|
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
|
|
|
|
#ifdef LDAP_COUNTERS
|
|
conn->c_n_ops_completed++;
|
|
#endif
|
|
|
|
slap_op_remove( &conn->c_ops, arg->co_op );
|
|
slap_op_free( arg->co_op );
|
|
arg->co_op = NULL;
|
|
arg->co_conn = NULL;
|
|
free( (char *) arg );
|
|
arg = NULL;
|
|
|
|
switch( tag ) {
|
|
#ifdef LDAP_COMPAT30
|
|
case LDAP_REQ_UNBIND_30:
|
|
#endif
|
|
case LDAP_REQ_UNBIND:
|
|
connection_closing( conn );
|
|
break;
|
|
|
|
case LDAP_REQ_BIND:
|
|
if( conn->c_conn_state == SLAP_C_BINDING) {
|
|
conn->c_conn_state = SLAP_C_ACTIVE;
|
|
}
|
|
}
|
|
|
|
if( conn->c_conn_state == SLAP_C_CLOSING ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_operation: attempting closing conn=%ld sd=%d.\n",
|
|
conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
|
|
|
|
connection_close( conn );
|
|
}
|
|
|
|
ldap_pvt_thread_mutex_lock( &active_threads_mutex );
|
|
active_threads--;
|
|
if( active_threads < 1 ) {
|
|
ldap_pvt_thread_cond_signal(&active_threads_cond);
|
|
}
|
|
ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
|
|
|
|
connection_resched( conn );
|
|
|
|
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int connection_read(int s)
|
|
{
|
|
int rc = 0;
|
|
Connection *c;
|
|
assert( connections != NULL );
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
c = connection_get( s );
|
|
if( c == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"connection_read(%d): no connection!\n",
|
|
s, 0, 0 );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return -1;
|
|
}
|
|
|
|
if( c->c_conn_state == SLAP_C_CLOSING ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_read(%d): closing, ignoring input for id=%ld\n",
|
|
s, c->c_connid, 0 );
|
|
|
|
connection_return( c );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return 0;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_read(%d): checking for input on id=%ld\n",
|
|
s, c->c_connid, 0 );
|
|
|
|
#define CONNECTION_INPUT_LOOP 1
|
|
|
|
#ifdef DATA_READY_LOOP
|
|
while(!rc && ber_pvt_sb_data_ready(&c->c_sb))
|
|
#elif CONNECTION_INPUT_LOOP
|
|
while(!rc)
|
|
#endif
|
|
{
|
|
rc = connection_input( c );
|
|
}
|
|
|
|
if( rc < 0 ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_read(%d): input error=%d id=%ld, closing.\n",
|
|
s, rc, c->c_connid );
|
|
|
|
connection_closing( c );
|
|
connection_close( c );
|
|
}
|
|
|
|
connection_return( c );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
connection_input(
|
|
Connection *conn
|
|
)
|
|
{
|
|
Operation *op;
|
|
unsigned long tag, len;
|
|
long msgid;
|
|
BerElement *ber;
|
|
|
|
if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
|
|
== NULL ) {
|
|
Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
|
|
return -1;
|
|
}
|
|
|
|
errno = 0;
|
|
if ( (tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ))
|
|
!= LDAP_TAG_MESSAGE )
|
|
{
|
|
int err = errno;
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"ber_get_next on fd %d failed errno %d (%s)\n",
|
|
ber_pvt_sb_get_desc( conn->c_sb ), err,
|
|
err > -1 && err < sys_nerr ? sys_errlist[err] : "unknown" );
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"\t*** got %ld of %lu so far\n",
|
|
(long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
|
|
conn->c_currentber->ber_len, 0 );
|
|
|
|
if ( err != EWOULDBLOCK && err != EAGAIN ) {
|
|
/* log, close and send error */
|
|
ber_free( conn->c_currentber, 1 );
|
|
conn->c_currentber = NULL;
|
|
|
|
return -2;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ber = conn->c_currentber;
|
|
conn->c_currentber = NULL;
|
|
|
|
if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
|
|
/* log, close and send error */
|
|
Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
|
|
0 );
|
|
ber_free( ber, 1 );
|
|
return -1;
|
|
}
|
|
|
|
if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
|
|
/* log, close and send error */
|
|
Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
|
|
0 );
|
|
ber_free( ber, 1 );
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef LDAP_COMPAT30
|
|
if ( conn->c_version == 30 ) {
|
|
(void) ber_skip_tag( ber, &len );
|
|
}
|
|
#endif
|
|
|
|
op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
|
|
|
|
if ( conn->c_conn_state == SLAP_C_BINDING
|
|
|| conn->c_conn_state == SLAP_C_CLOSING )
|
|
{
|
|
Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );
|
|
slap_op_add( &conn->c_pending_ops, op );
|
|
|
|
} else {
|
|
connection_op_activate( conn, op );
|
|
}
|
|
|
|
#ifdef NO_THREADS
|
|
if ( conn->c_struct_state != SLAP_C_USED ) {
|
|
/* connection must have got closed underneath us */
|
|
return 1;
|
|
}
|
|
#endif
|
|
assert( conn->c_struct_state == SLAP_C_USED );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
connection_resched( Connection *conn )
|
|
{
|
|
Operation *op;
|
|
|
|
if( conn->c_conn_state != SLAP_C_ACTIVE ) {
|
|
/* other states need different handling */
|
|
return 0;
|
|
}
|
|
|
|
for( op = slap_op_pop( &conn->c_pending_ops );
|
|
op != NULL;
|
|
op = slap_op_pop( &conn->c_pending_ops ) )
|
|
{
|
|
/* pending operations should not be marked for abandonment */
|
|
assert(!op->o_abandon);
|
|
|
|
connection_op_activate( conn, op );
|
|
|
|
if ( conn->c_conn_state == SLAP_C_BINDING ) {
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int connection_op_activate( Connection *conn, Operation *op )
|
|
{
|
|
struct co_arg *arg;
|
|
char *tmpdn;
|
|
int status;
|
|
unsigned long tag = op->o_tag;
|
|
|
|
if ( conn->c_dn != NULL ) {
|
|
tmpdn = ch_strdup( conn->c_dn );
|
|
} else {
|
|
tmpdn = NULL;
|
|
}
|
|
|
|
arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
|
|
arg->co_conn = conn;
|
|
arg->co_op = op;
|
|
|
|
arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
|
|
arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );
|
|
|
|
slap_op_add( &conn->c_ops, arg->co_op );
|
|
|
|
if(tag == LDAP_REQ_BIND) {
|
|
conn->c_conn_state = SLAP_C_BINDING;
|
|
}
|
|
|
|
if ( tmpdn != NULL ) {
|
|
free( tmpdn );
|
|
}
|
|
|
|
ldap_pvt_thread_mutex_lock( &active_threads_mutex );
|
|
active_threads++;
|
|
ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
|
|
|
|
status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
|
|
connection_operation, (void *) arg );
|
|
|
|
if ( status != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
|
|
|
|
/* should move op to pending list */
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int connection_write(int s)
|
|
{
|
|
Connection *c;
|
|
assert( connections != NULL );
|
|
|
|
ldap_pvt_thread_mutex_lock( &connections_mutex );
|
|
|
|
c = connection_get( s );
|
|
if( c == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"connection_write(%d): no connection!\n",
|
|
s, 0, 0 );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return -1;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"connection_write(%d): waking output for id=%ld\n",
|
|
s, c->c_connid, 0 );
|
|
|
|
ldap_pvt_thread_cond_signal( &c->c_write_cv );
|
|
|
|
connection_return( c );
|
|
ldap_pvt_thread_mutex_unlock( &connections_mutex );
|
|
return 0;
|
|
}
|