openldap/servers/slapd/connection.c
1998-08-18 00:41:35 +00:00

233 lines
5.5 KiB
C

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <signal.h>
#include "portable.h"
#include "slap.h"
extern Operation *op_add();
extern int active_threads;
extern pthread_mutex_t active_threads_mutex;
extern pthread_mutex_t new_conn_mutex;
extern long ops_initiated;
extern long ops_completed;
extern pthread_mutex_t ops_mutex;
extern pthread_t listener_tid;
#ifndef SYSERRLIST_IN_STDIO
extern int sys_nerr;
extern char *sys_errlist[];
#endif
struct co_arg {
Connection *co_conn;
Operation *co_op;
};
/*
* 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( struct co_arg *arg )
{
unsigned long len;
pthread_mutex_lock( &arg->co_conn->c_opsmutex );
arg->co_conn->c_opsinitiated++;
pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
pthread_mutex_lock( &ops_mutex );
ops_initiated++;
pthread_mutex_unlock( &ops_mutex );
switch ( arg->co_op->o_tag ) {
case LDAP_REQ_BIND:
do_bind( arg->co_conn, arg->co_op );
break;
#ifdef COMPAT30
case LDAP_REQ_UNBIND_30:
#endif
case LDAP_REQ_UNBIND:
do_unbind( arg->co_conn, arg->co_op );
break;
case LDAP_REQ_ADD:
do_add( arg->co_conn, arg->co_op );
break;
#ifdef COMPAT30
case LDAP_REQ_DELETE_30:
#endif
case LDAP_REQ_DELETE:
do_delete( arg->co_conn, arg->co_op );
break;
case LDAP_REQ_MODRDN:
do_modrdn( arg->co_conn, arg->co_op );
break;
case LDAP_REQ_MODIFY:
do_modify( arg->co_conn, arg->co_op );
break;
case LDAP_REQ_COMPARE:
do_compare( arg->co_conn, arg->co_op );
break;
case LDAP_REQ_SEARCH:
do_search( arg->co_conn, arg->co_op );
break;
#ifdef COMPAT30
case LDAP_REQ_ABANDON_30:
#endif
case LDAP_REQ_ABANDON:
do_abandon( arg->co_conn, arg->co_op );
break;
default:
Debug( LDAP_DEBUG_ANY, "unknown request 0x%x\n",
arg->co_op->o_tag, 0, 0 );
break;
}
pthread_mutex_lock( &arg->co_conn->c_opsmutex );
arg->co_conn->c_opscompleted++;
op_delete( &arg->co_conn->c_ops, arg->co_op );
pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
free( (char *) arg );
pthread_mutex_lock( &ops_mutex );
ops_completed++;
pthread_mutex_unlock( &ops_mutex );
pthread_mutex_lock( &active_threads_mutex );
active_threads--;
pthread_mutex_unlock( &active_threads_mutex );
}
void
connection_activity(
Connection *conn
)
{
pthread_attr_t attr;
struct co_arg *arg;
unsigned long tag, len;
long msgid;
BerElement *ber;
char *tmpdn;
if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
== NULL ) {
Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
return;
}
errno = 0;
if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
!= LDAP_TAG_MESSAGE ) {
Debug( LDAP_DEBUG_TRACE,
"ber_get_next on fd %d failed errno %d (%s)\n",
conn->c_sb.sb_sd, errno, errno > -1 && errno < sys_nerr ?
sys_errlist[errno] : "unknown" );
Debug( LDAP_DEBUG_TRACE, "*** got %d of %d so far\n",
conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf,
conn->c_currentber->ber_len, 0 );
if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
/* log, close and send error */
ber_free( conn->c_currentber, 1 );
conn->c_currentber = NULL;
close_connection( conn, conn->c_connid, -1 );
}
return;
}
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%x\n", tag, 0,
0 );
ber_free( ber, 1 );
close_connection( conn, conn->c_connid, -1 );
return;
}
if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
/* log, close and send error */
Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%x\n", tag, 0,
0 );
ber_free( ber, 1 );
close_connection( conn, conn->c_connid, -1 );
return;
}
#ifdef COMPAT30
if ( conn->c_version == 30 ) {
(void) ber_skip_tag( ber, &len );
}
#endif
arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
arg->co_conn = conn;
pthread_mutex_lock( &conn->c_dnmutex );
if ( conn->c_dn != NULL ) {
tmpdn = strdup( conn->c_dn );
} else {
tmpdn = NULL;
}
pthread_mutex_unlock( &conn->c_dnmutex );
pthread_mutex_lock( &conn->c_opsmutex );
arg->co_op = op_add( &conn->c_ops, ber, msgid, tag, tmpdn,
conn->c_opsinitiated, conn->c_connid );
pthread_mutex_unlock( &conn->c_opsmutex );
if ( tmpdn != NULL ) {
free( tmpdn );
}
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
#ifndef THREAD_MIT_PTHREADS
/* POSIX_THREADS or compatible
* This is a draft 10 or standard pthreads implementation
*/
if ( pthread_create( &arg->co_op->o_tid, &attr,
(void *) connection_operation, (void *) arg ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 );
} else {
pthread_mutex_lock( &active_threads_mutex );
active_threads++;
pthread_mutex_unlock( &active_threads_mutex );
}
#else /* !THREAD_MIT_PTHREAD */
/*
* This is a draft 4 or earlier pthreads implementation
*/
if ( pthread_create( &arg->co_op->o_tid, attr,
(void *) connection_operation, (void *) arg ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 );
} else {
pthread_mutex_lock( &active_threads_mutex );
active_threads++;
pthread_mutex_unlock( &active_threads_mutex );
}
#endif /* !THREAD_MIT_PTHREAD */
pthread_attr_destroy( &attr );
}