Fix bug # 140182 - async I/O improvements.

A queue of pending outbound requests is kept. UnBind requests are NOT
   queued however.
  Abandon requests are not sent if a request is not outstanding.
  Cleaned up the code in result.c to avoid use of magic return values
	such as -1 and -2.  Also removed some dead code and dead files.
ltest (test.c) now supports SSL and async I/O options.
This commit is contained in:
mcs%netscape.com 2003-10-01 17:19:11 +00:00
parent acf075ad8c
commit 2aa4fa531d
11 changed files with 645 additions and 472 deletions

View File

@ -38,6 +38,8 @@ static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of
static int do_abandon( LDAP *ld, int origid, int msgid,
LDAPControl **serverctrls, LDAPControl **clientctrls );
static int nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc,
BerElement *ber, int abandon_msgid );
/*
* ldap_abandon - perform an ldap abandon operation. Parameters:
@ -111,7 +113,6 @@ do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls,
{
BerElement *ber;
int i, bererr, lderr, sendabandon;
Sockbuf *sb;
LDAPRequest *lr = NULL;
/*
@ -124,92 +125,60 @@ do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls,
/* optimistic */
lderr = LDAP_SUCCESS;
/*
* this is not the best implementation...
* the code special cases the when async io is enabled.
* The logic is clear this way, at the cost of code bloat.
* This logic should be cleaned up post nova 4.5 rtm
*/
if (ld->ld_options & LDAP_BITOPT_ASYNC)
{
/* Don't send an abandon message unless there is something to abandon. */
/*
* Find the request that we are abandoning. Don't send an
* abandon message unless there is something to abandon.
*/
sendabandon = 0;
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
if ( lr->lr_msgid == msgid ) { /* this message */
if ( origid == msgid && lr->lr_parent != NULL ) {
/* don't let caller abandon child requests! */
lderr = LDAP_PARAM_ERROR;
goto set_errorcode_and_return;
}
if ( lr->lr_status == LDAP_REQST_INPROGRESS ) {
/*
* We only need to send an abandon message if
* the request is in progress.
*/
sendabandon = 1;
}
break;
}
if ( lr->lr_origid == msgid ) { /* child: abandon it */
(void)do_abandon( ld, msgid, lr->lr_msgid,
serverctrls, clientctrls );
/* we ignore errors from child abandons... */
}
}
/* Find the request that we are abandoning. */
if (ld->ld_requests != NULL) {
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
if ( lr->lr_msgid == msgid ) { /* this message */
if ( origid == msgid && lr->lr_parent != NULL ) {
/* don't let caller abandon child requests! */
lderr = LDAP_PARAM_ERROR;
goto set_errorcode_and_return;
}
if ( lr->lr_status == LDAP_REQST_INPROGRESS ) {
/* We only need to send an abandon message if the request
* is in progress.
*/
sendabandon = 1;
}
break;
}
if ( lr->lr_origid == msgid ) { /* child: abandon it */
(void)do_abandon( ld, msgid, lr->lr_msgid,
serverctrls, clientctrls );
/* we ignore errors from child abandons... */
}
}
}
}
else
{
sendabandon = 1;
/* find the request that we are abandoning */
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
if ( lr->lr_msgid == msgid ) { /* this message */
break;
}
if ( lr->lr_origid == msgid ) { /* child: abandon it */
(void)do_abandon( ld, msgid, lr->lr_msgid,
serverctrls, clientctrls );
/* we ignore errors from child abandons... */
}
}
if ( lr != NULL ) {
if ( origid == msgid && lr->lr_parent != NULL ) {
/* don't let caller abandon child requests! */
lderr = LDAP_PARAM_ERROR;
goto set_errorcode_and_return;
}
if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
/* no need to send abandon message */
sendabandon = 0;
}
}
}
if ( ldap_msgdelete( ld, msgid ) == 0 ) {
/* we had all the results and deleted them */
goto set_errorcode_and_return;
}
if ( sendabandon ) {
if ( lr != NULL && sendabandon ) {
/* create a message to send */
if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) ==
LDAP_SUCCESS ) {
int abandon_msgid;
LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
abandon_msgid = ++ld->ld_msgid;
LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
#ifdef CLDAP
if ( ld->ld_dbp->sb_naddr > 0 ) {
bererr = ber_printf( ber, "{isti",
++ld->ld_msgid, ld->ld_cldapdn,
abandon_msgid, ld->ld_cldapdn,
LDAP_REQ_ABANDON, msgid );
} else {
#endif /* CLDAP */
bererr = ber_printf( ber, "{iti",
++ld->ld_msgid, LDAP_REQ_ABANDON, msgid );
abandon_msgid, LDAP_REQ_ABANDON, msgid );
#ifdef CLDAP
}
#endif /* CLDAP */
LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
if ( bererr == -1 ||
( lderr = nsldapi_put_controls( ld, serverctrls,
@ -217,31 +186,36 @@ do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls,
lderr = LDAP_ENCODING_ERROR;
ber_free( ber, 1 );
} else {
/* send the message */
if ( lr != NULL ) {
sb = lr->lr_conn->lconn_sb;
} else {
sb = ld->ld_sbp;
}
if ( nsldapi_ber_flush( ld, sb, ber, 1, 0 )
!= 0 ) {
lderr = LDAP_SERVER_DOWN;
}
/* try to send the message */
lderr = nsldapi_send_abandon_message( ld,
lr->lr_conn, ber, abandon_msgid );
}
}
}
if ( lr != NULL ) {
if ( sendabandon ) {
nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL,
0, 1 );
}
/*
* Always call nsldapi_free_connection() so that the connection's
* ref count is correctly decremented. It is OK to always pass
* 1 for the "unbind" parameter because doing so will only affect
* connections that resulted from a child request (because the
* default connection's ref count never goes to zero).
*/
nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL,
0 /* do not force */, 1 /* send unbind before closing */ );
/*
* Free the entire request chain if we finished abandoning everything.
*/
if ( origid == msgid ) {
nsldapi_free_request( ld, lr, 0 );
}
}
/*
* Record the abandoned message ID (used to discard any server responses
* that arrive later).
*/
LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK );
if ( ld->ld_abandoned == NULL ) {
if ( (ld->ld_abandoned = (int *)NSLDAPI_MALLOC( 2
@ -269,3 +243,46 @@ set_errorcode_and_return:
LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
return( lderr );
}
/*
* Try to send the abandon message that is encoded in ber. Returns an
* LDAP result code.
*/
static int
nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc, BerElement *ber,
int abandon_msgid )
{
int lderr = LDAP_SUCCESS;
int err = 0;
err = nsldapi_send_ber_message( ld, lc->lconn_sb,
ber, 1 /* free ber */ );
if ( err == -2 ) {
/*
* "Would block" error. Queue the abandon as
* a pending request.
*/
LDAPRequest *lr;
lr = nsldapi_new_request( lc, ber, abandon_msgid,
0 /* no response expected */ );
if ( lr == NULL ) {
lderr = LDAP_NO_MEMORY;
ber_free( ber, 1 );
} else {
lr->lr_status = LDAP_REQST_WRITING;
nsldapi_queue_request_nolock( ld, lr );
++lc->lconn_pending_requests;
nsldapi_iostatus_interest_write( ld,
lc->lconn_sb );
}
} else if ( err != 0 ) {
/*
* Fatal error (not a "would block" error).
*/
lderr = LDAP_SERVER_DOWN;
ber_free( ber, 1 );
}
return( lderr );
}

View File

@ -201,6 +201,12 @@ ldap_get_option( LDAP *ld, int option, void *optdata )
*((struct ldap_thread_fns *) optdata) = ld->ld_thread;
break;
/* extra thread function pointers */
case LDAP_OPT_EXTRA_THREAD_FN_PTRS:
/* struct copy */
*((struct ldap_extra_thread_fns *) optdata) = ld->ld_thread2;
break;
/* DNS function pointers */
case LDAP_OPT_DNS_FN_PTRS:
/* struct copy */

View File

@ -1,33 +0,0 @@
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* Copyright (c) 1996 Regents of the University of Michigan.
* All rights reserved.
*/
/*
* LIBLDAP globals.c -- LDAP library global variables
*/
#ifdef LDAP_DEBUG
int ldap_debug;
#endif

View File

@ -170,13 +170,13 @@ typedef struct ldap_conn {
int lconn_refcnt;
unsigned long lconn_lastused; /* time */
int lconn_status;
#define LDAP_CONNST_NEEDSOCKET 1
#define LDAP_CONNST_CONNECTING 2
#define LDAP_CONNST_CONNECTED 3
#define LDAP_CONNST_DEAD 4
LDAPServer *lconn_server;
char *lconn_binddn; /* DN of last successful bind */
int lconn_bound; /* has a bind been done? */
int lconn_pending_requests; /* count of unsent req*/
char *lconn_krbinstance;
struct ldap_conn *lconn_next;
} LDAPConn;
@ -190,13 +190,13 @@ typedef struct ldapreq {
int lr_status; /* status of request */
#define LDAP_REQST_INPROGRESS 1
#define LDAP_REQST_CHASINGREFS 2
#define LDAP_REQST_NOTCONNECTED 3
#define LDAP_REQST_WRITING 4
#define LDAP_REQST_CONNDEAD 5 /* associated conn. has failed */
int lr_outrefcnt; /* count of outstanding referrals */
int lr_origid; /* original request's message id */
int lr_parentcnt; /* count of parent requests */
int lr_res_msgtype; /* result message type */
int lr_expect_resp; /* if non-zero, expect a response */
int lr_res_errno; /* result LDAP errno */
char *lr_res_error; /* result error string */
char *lr_res_matched;/* result matched DN string */
@ -241,7 +241,10 @@ struct ldap_x_ext_io_fns_rev0 {
/*
* structure representing an ldap connection
* Structure representing an ldap connection.
*
* This is an opaque struct; the fields are not visible to
* applications that use the LDAP API.
*/
struct ldap {
struct sockbuf *ld_sbp; /* pointer to socket desc. & buffer */
@ -261,13 +264,12 @@ struct ldap {
char *ld_matched;
int ld_msgid;
/* do not mess with these */
/* Note: the ld_requests list is ordered old to new */
LDAPRequest *ld_requests; /* list of outstanding requests */
LDAPMessage *ld_responses; /* list of outstanding responses */
int *ld_abandoned; /* array of abandoned requests */
char *ld_cldapdn; /* DN used in connectionless search */
/* it is OK to change these next four values directly */
int ld_cldaptries; /* connectionless search retry count */
int ld_cldaptimeout;/* time between retries */
int ld_refhoplimit; /* limit on referral nesting */
@ -280,7 +282,6 @@ struct ldap {
#define LDAP_BITOPT_RECONNECT 0x08000000
#define LDAP_BITOPT_ASYNC 0x04000000
/* do not mess with the rest though */
char *ld_defhost; /* full name of default server */
int ld_defport; /* port of default server */
BERTranslateProc ld_lber_encode_translate_proc;
@ -365,11 +366,11 @@ struct ldap {
/* extra thread function pointers */
struct ldap_extra_thread_fns ld_thread2;
/* With the 4.0 version of the LDAP SDK */
/* the extra thread functions except for */
/* the ld_threadid_fn has been disabled */
/* Look at the release notes for the full */
/* explanation */
/*
* With the 4.0 and later versions of the LDAP SDK, the extra thread
* functions except for the ld_threadid_fn have been disabled.
* Look at the release notes for the full explanation.
*/
#define ld_mutex_trylock_fn ld_thread2.ltf_mutex_trylock
#define ld_sema_alloc_fn ld_thread2.ltf_sema_alloc
#define ld_sema_free_fn ld_thread2.ltf_sema_free
@ -701,17 +702,21 @@ int nsldapi_post_result( LDAP *ld, int msgid, LDAPMessage *result );
*/
int nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
char *dn, BerElement *ber );
int nsldapi_send_pending_requests_nolock( LDAP *ld, LDAPConn *lc );
int nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp );
void nsldapi_set_ber_options( LDAP *ld, BerElement *ber );
int nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
int async );
int nsldapi_send_ber_message( LDAP *ld, Sockbuf *sb, BerElement *ber,
int freeit );
int nsldapi_send_server_request( LDAP *ld, BerElement *ber, int msgid,
LDAPRequest *parentreq, LDAPServer *srvlist, LDAPConn *lc,
char *bindreqdn, int bind );
LDAPConn *nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
int connect, int bind );
LDAPRequest *nsldapi_find_request_by_msgid( LDAP *ld, int msgid );
LDAPRequest *nsldapi_new_request( LDAPConn *lc, BerElement *ber, int msgid,
int expect_resp );
void nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn );
void nsldapi_queue_request_nolock( LDAP *ld, LDAPRequest *lr );
void nsldapi_free_connection( LDAP *ld, LDAPConn *lc,
LDAPControl **serverctrls, LDAPControl **clientctrls,
int force, int unbind );

View File

@ -795,21 +795,23 @@ nsldapi_host_connected_to( Sockbuf *sb )
int
nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
{
int rc = 0;
NSLDAPIIOStatus *iosp;
LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
if ( ld->ld_iostatus == NULL
&& nsldapi_iostatus_init_nolock( ld ) < 0 ) {
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( -1 );
rc = -1;
goto unlock_and_return;
}
iosp = ld->ld_iostatus;
if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
#ifdef NSLDAPI_AVOID_OS_SOCKETS
return( -1 );
rc = -1;
goto unlock_and_return;
#else /* NSLDAPI_AVOID_OS_SOCKETS */
#ifdef NSLDAPI_HAVE_POLL
if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
@ -838,9 +840,9 @@ nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
iosp->ios_type, 0, 0 );
}
unlock_and_return:
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( 0 );
return( rc );
}
@ -851,21 +853,23 @@ nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
int
nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
{
int rc = 0;
NSLDAPIIOStatus *iosp;
LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
if ( ld->ld_iostatus == NULL
&& nsldapi_iostatus_init_nolock( ld ) < 0 ) {
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( -1 );
rc = -1;
goto unlock_and_return;
}
iosp = ld->ld_iostatus;
if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
#ifdef NSLDAPI_AVOID_OS_SOCKETS
return( -1 );
rc = -1;
goto unlock_and_return;
#else /* NSLDAPI_AVOID_OS_SOCKETS */
#ifdef NSLDAPI_HAVE_POLL
if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
@ -893,9 +897,9 @@ nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
iosp->ios_type, 0, 0 );
}
unlock_and_return:
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( 0 );
return( rc );
}
@ -906,21 +910,23 @@ nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
int
nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
{
int rc = 0;
NSLDAPIIOStatus *iosp;
LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
if ( ld->ld_iostatus == NULL
&& nsldapi_iostatus_init_nolock( ld ) < 0 ) {
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( -1 );
rc = -1;
goto unlock_and_return;
}
iosp = ld->ld_iostatus;
if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
#ifdef NSLDAPI_AVOID_OS_SOCKETS
return( -1 );
rc = -1;
goto unlock_and_return;
#else /* NSLDAPI_AVOID_OS_SOCKETS */
#ifdef NSLDAPI_HAVE_POLL
if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
@ -962,9 +968,9 @@ nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
iosp->ios_type, 0, 0 );
}
unlock_and_return:
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( 0 );
return( rc );
}
@ -974,15 +980,18 @@ nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
int
nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
{
int rc;
int rc = 0;
NSLDAPIIOStatus *iosp;
LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
iosp = ld->ld_iostatus;
if ( iosp == NULL ) {
goto unlock_and_return;
}
if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
#ifdef NSLDAPI_AVOID_OS_SOCKETS
return 0;
goto unlock_and_return;
#else /* NSLDAPI_AVOID_OS_SOCKETS */
#ifdef NSLDAPI_HAVE_POLL
/*
@ -1013,6 +1022,7 @@ nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
rc = 0;
}
unlock_and_return:
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( rc );
}
@ -1024,15 +1034,18 @@ nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
int
nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
{
int rc;
int rc = 0;
NSLDAPIIOStatus *iosp;
LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
iosp = ld->ld_iostatus;
if ( iosp == NULL ) {
goto unlock_and_return;
}
if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
#ifdef NSLDAPI_AVOID_OS_SOCKETS
return 0;
goto unlock_and_return;
#else /* NSLDAPI_AVOID_OS_SOCKETS */
#ifdef NSLDAPI_HAVE_POLL
/*
@ -1063,6 +1076,7 @@ nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
rc = 0;
}
unlock_and_return:
LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
return( rc );
}
@ -1208,7 +1222,7 @@ nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
iosp = ld->ld_iostatus;
if ( iosp == NULL ||
( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
( iosp->ios_read_count <= 0 && iosp->ios_write_count <= 0 )) {
rc = 0; /* simulate a timeout */
} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {

View File

@ -36,7 +36,6 @@ static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of
#include "ldap-int.h"
static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
static void use_connection( LDAP *ld, LDAPConn *lc );
static void free_servers( LDAPServer *srvlist );
static int chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
char *refurl, char *desc, int *unknownp );
@ -195,22 +194,18 @@ nsldapi_send_server_request(
}
/*
* the logic here is:
* if
* 1. no connections exists,
* or
* 2. if the connection is either not in the connected
* or connecting state in an async io model
* or
* 3. the connection is notin a connected state with normal (non async io)
*/
/*
* return a fatal error if:
* 1. no connections exists
* or
* 2. the connection is dead
* or
* 3. it is not in the connected state with normal (non async) I/O
*/
if ( lc == NULL
|| ( (ld->ld_options & LDAP_BITOPT_ASYNC
&& lc->lconn_status != LDAP_CONNST_CONNECTING
&& lc->lconn_status != LDAP_CONNST_CONNECTED)
|| (!(ld->ld_options & LDAP_BITOPT_ASYNC )
&& lc->lconn_status != LDAP_CONNST_CONNECTED) ) ) {
|| ( lc->lconn_status == LDAP_CONNST_DEAD )
|| ( 0 == (ld->ld_options & LDAP_BITOPT_ASYNC) &&
lc->lconn_status != LDAP_CONNST_CONNECTED) ) {
ber_free( ber, 1 );
if ( lc != NULL ) {
@ -224,9 +219,9 @@ nsldapi_send_server_request(
return( -1 );
}
use_connection( ld, lc );
if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) ==
NULL || ( bindreqdn != NULL && ( bindreqdn =
if (( lr = nsldapi_new_request( lc, ber, msgid,
1 /* expect a response */)) == NULL
|| ( bindreqdn != NULL && ( bindreqdn =
nsldapi_strdup( bindreqdn )) == NULL )) {
if ( lr != NULL ) {
NSLDAPI_FREE( lr );
@ -242,11 +237,6 @@ nsldapi_send_server_request(
return( -1 );
}
lr->lr_binddn = bindreqdn;
lr->lr_msgid = msgid;
lr->lr_status = LDAP_REQST_INPROGRESS;
lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */
lr->lr_ber = ber;
lr->lr_conn = lc;
if ( parentreq != NULL ) { /* sub-request */
if ( !incparent ) {
@ -265,40 +255,100 @@ nsldapi_send_server_request(
}
LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
if (( lr->lr_next = ld->ld_requests ) != NULL ) {
lr->lr_next->lr_prev = lr;
/* add new request to the end of the list of outstanding requests */
nsldapi_queue_request_nolock( ld, lr );
/*
* Issue a non-blocking poll() if we need to check this
* connection's status.
*/
if ( lc->lconn_status == LDAP_CONNST_CONNECTING ||
lc->lconn_pending_requests > 0 ) {
struct timeval tv;
tv.tv_sec = tv.tv_usec = 0;
(void)nsldapi_iostatus_poll( ld, &tv );
}
ld->ld_requests = lr;
lr->lr_prev = NULL;
if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) {
/*
* If the connect is pending, check to see if it has now completed.
*/
if ( lc->lconn_status == LDAP_CONNST_CONNECTING &&
nsldapi_iostatus_is_write_ready( ld, lc->lconn_sb )) {
lc->lconn_status = LDAP_CONNST_CONNECTED;
LDAPDebug( LDAP_DEBUG_TRACE,
"nsldapi_send_server_request: connection 0x%x -"
" LDAP_CONNST_CONNECTING -> LDAP_CONNST_CONNECTED\n",
lc, 0, 0 );
}
if ( lc->lconn_status == LDAP_CONNST_CONNECTING ||
lc->lconn_pending_requests > 0 ) {
/*
* The connect is not yet complete, or there are existing
* requests that have not yet been sent to the server.
* Delay sending this request.
*/
lr->lr_status = LDAP_REQST_WRITING;
++lc->lconn_pending_requests;
nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
/*
* If the connection is now connected, and it is ready
* to accept some more outbound data, send as many
* pending requests as possible.
*/
if ( lc->lconn_status != LDAP_CONNST_CONNECTING
&& nsldapi_iostatus_is_write_ready( ld, lc->lconn_sb )) {
if ( nsldapi_send_pending_requests_nolock( ld, lc )
== -1 ) { /* error */
/*
* Since nsldapi_send_pending_requests_nolock()
* sets LDAP errno, there is no need to do so
* here.
*/
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
return( -1 );
}
}
} else {
if (( err = nsldapi_send_ber_message( ld, lc->lconn_sb,
ber, 0 /* do not free ber */ )) != 0 ) {
/* need to continue write later */
if (err == -2 ) {
lr->lr_status = LDAP_REQST_WRITING;
++lc->lconn_pending_requests;
nsldapi_iostatus_interest_write( ld,
lc->lconn_sb );
} else {
LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
NULL, NULL );
nsldapi_free_request( ld, lr, 0 );
nsldapi_free_connection( ld, lc, NULL, NULL,
0, 0 );
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
return( -1 );
}
/* need to continue write later */
if (ld->ld_options & LDAP_BITOPT_ASYNC && err == -2 ) {
lr->lr_status = LDAP_REQST_WRITING;
nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
} else {
if ( parentreq == NULL ) {
ber->ber_end = ber->ber_ptr;
ber->ber_ptr = ber->ber_buf;
}
LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
nsldapi_free_request( ld, lr, 0 );
nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
return( -1 );
/* sent -- waiting for a response */
if (ld->ld_options & LDAP_BITOPT_ASYNC) {
lc->lconn_status = LDAP_CONNST_CONNECTED;
}
nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
}
} else {
if ( parentreq == NULL ) {
ber->ber_end = ber->ber_ptr;
ber->ber_ptr = ber->ber_buf;
}
/* sent -- waiting for a response */
if (ld->ld_options & LDAP_BITOPT_ASYNC) {
lc->lconn_status = LDAP_CONNST_CONNECTED;
}
nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
}
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
@ -309,16 +359,22 @@ nsldapi_send_server_request(
/*
* returns -1 if a fatal error occurs. If async is non-zero and the flush
* would block, -2 is returned.
* nsldapi_send_ber_message(): Attempt to send a BER-encoded message.
* If freeit is non-zero, ber is freed when the send succeeds.
*
* Return values:
* 0: message sent successfully.
* -1: a fatal error occurred while trying to send.
* -2: async. I/O is enabled and the send would block.
*/
int
nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
int async )
nsldapi_send_ber_message( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit )
{
int terrno;
int rc = 0; /* optimistic */
int async = ( 0 != (ld->ld_options & LDAP_BITOPT_ASYNC));
int more_to_send = 1;
for ( ;; ) {
while ( more_to_send) {
/*
* ber_flush() doesn't set errno on EOF, so we pre-set it to
* zero to avoid getting tricked by leftover "EAGAIN" errors
@ -326,29 +382,116 @@ nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
LDAP_SET_ERRNO( ld, 0 );
if ( ber_flush( sb, ber, freeit ) == 0 ) {
return( 0 ); /* success */
more_to_send = 0; /* success */
} else {
int terrno = LDAP_GET_ERRNO( ld );
if ( NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
if ( async ) {
rc = -2;
break;
}
} else {
nsldapi_connection_lost_nolock( ld, sb );
rc = -1; /* fatal error */
break;
}
}
terrno = LDAP_GET_ERRNO( ld );
if (ld->ld_options & LDAP_BITOPT_ASYNC) {
if ( terrno != 0 && !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
nsldapi_connection_lost_nolock( ld, sb );
return( -1 ); /* fatal error */
}
}
else if ( !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
nsldapi_connection_lost_nolock( ld, sb );
return( -1 ); /* fatal error */
return( rc );
}
/*
* nsldapi_send_pending_requests_nolock(): Send one or more pending requests
* that are associated with connection 'lc'.
*
* Return values: 0 -- success.
* -1 -- fatal error; connection closed.
*
* Must be called with these two mutexes locked, in this order:
* LDAP_CONN_LOCK
* LDAP_REQ_LOCK
*/
int
nsldapi_send_pending_requests_nolock( LDAP *ld, LDAPConn *lc )
{
int err;
int waiting_for_a_response = 0;
int rc = 0;
LDAPRequest *lr;
char *logname = "nsldapi_send_pending_requests_nolock";
LDAPDebug( LDAP_DEBUG_TRACE, "%s\n", logname, 0, 0 );
for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
/*
* This code relies on the fact that the ld_requests list
* is in order from oldest to newest request (the oldest
* requests that have not yet been sent to the server are
* sent first).
*/
if ( lr->lr_status == LDAP_REQST_WRITING
&& lr->lr_conn == lc ) {
err = nsldapi_send_ber_message( ld, lc->lconn_sb,
lr->lr_ber, 0 /* do not free ber */ );
if ( err == 0 ) { /* send succeeded */
LDAPDebug( LDAP_DEBUG_TRACE,
"%s: 0x%x SENT\n", logname, lr, 0 );
lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
lr->lr_status = LDAP_REQST_INPROGRESS;
--lc->lconn_pending_requests;
} else if ( err == -2 ) { /* would block */
rc = 0; /* not an error */
LDAPDebug( LDAP_DEBUG_TRACE,
"%s: 0x%x WOULD BLOCK\n", logname, lr, 0 );
break;
} else { /* fatal error */
LDAPDebug( LDAP_DEBUG_TRACE,
"%s: 0x%x FATAL ERROR\n", logname, lr, 0 );
LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
NULL, NULL );
nsldapi_free_request( ld, lr, 0 );
lr = NULL;
nsldapi_free_connection( ld, lc, NULL, NULL,
0, 0 );
lc = NULL;
rc = -1;
break;
}
}
if ( async ) {
return( -2 ); /* would block */
if (lr->lr_status == LDAP_REQST_INPROGRESS ) {
if (lr->lr_expect_resp) {
++waiting_for_a_response;
} else {
LDAPDebug( LDAP_DEBUG_TRACE,
"%s: 0x%x NO RESPONSE EXPECTED;"
" freeing request \n", logname, lr, 0 );
nsldapi_free_request( ld, lr, 0 );
lr = NULL;
}
}
}
if ( lc != NULL ) {
if ( lc->lconn_pending_requests < 1 ) {
/* no need to poll for "write ready" any longer */
nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
}
if ( waiting_for_a_response ) {
/* need to poll for "read ready" */
nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
}
}
LDAPDebug( LDAP_DEBUG_TRACE, "%s <- %d\n", logname, rc, 0 );
return( rc );
}
LDAPConn *
nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
int connect, int bind )
@ -437,11 +580,15 @@ nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
lc->lconn_server = srv;
}
if (ld->ld_options & LDAP_BITOPT_ASYNC && rc == -2)
{
if ( 0 != (ld->ld_options & LDAP_BITOPT_ASYNC)) {
/*
* Technically, the socket may already be connected but we are
* not sure. By setting the state to LDAP_CONNST_CONNECTING, we
* ensure that we will check the socket status to make sure it
* is connected before we try to send any LDAP messages.
*/
lc->lconn_status = LDAP_CONNST_CONNECTING;
}
else {
} else {
lc->lconn_status = LDAP_CONNST_CONNECTED;
}
@ -550,15 +697,6 @@ find_connection( LDAP *ld, LDAPServer *srv, int any )
}
static void
use_connection( LDAP *ld, LDAPConn *lc )
{
++lc->lconn_refcnt;
lc->lconn_lastused = time( 0 );
}
void
nsldapi_free_connection( LDAP *ld, LDAPConn *lc, LDAPControl **serverctrls,
LDAPControl **clientctrls, int force, int unbind )
@ -568,8 +706,8 @@ nsldapi_free_connection( LDAP *ld, LDAPConn *lc, LDAPControl **serverctrls,
LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection\n", 0, 0, 0 );
if ( force || --lc->lconn_refcnt <= 0 ) {
nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
if ( unbind ) {
nsldapi_send_unbind( ld, lc->lconn_sb,
serverctrls, clientctrls );
@ -634,8 +772,8 @@ nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
ber_err_print( msg );
for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
if ( lc->lconn_server != NULL ) {
sprintf( msg, "* host: %s port: %d secure: %s%s\n",
( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
sprintf( msg, "* 0x%x - host: %s port: %d secure: %s%s\n",
lc, ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
: lc->lconn_server->lsrv_host,
lc->lconn_server->lsrv_port,
( lc->lconn_server->lsrv_options &
@ -644,10 +782,10 @@ nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
" (default)" : "" );
ber_err_print( msg );
}
sprintf( msg, " refcnt: %d status: %s\n", lc->lconn_refcnt,
( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
"NeedSocket" : ( lc->lconn_status ==
LDAP_CONNST_CONNECTING ) ? "Connecting" :
sprintf( msg, " refcnt: %d pending: %d status: %s\n",
lc->lconn_refcnt, lc->lconn_pending_requests,
( lc->lconn_status == LDAP_CONNST_CONNECTING )
? "Connecting" :
( lc->lconn_status == LDAP_CONNST_DEAD ) ? "Dead" :
"Connected" );
ber_err_print( msg );
@ -681,11 +819,10 @@ nsldapi_dump_requests_and_responses( LDAP *ld )
ber_err_print( " Empty\n" );
}
for ( ; lr != NULL; lr = lr->lr_next ) {
sprintf( msg, " * msgid %d, origid %d, status %s\n",
lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
sprintf( msg, " * 0x%x - msgid %d, origid %d, status %s\n",
lr, lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
LDAP_REQST_INPROGRESS ) ? "InProgress" :
( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
( lr->lr_status == LDAP_REQST_CONNDEAD ) ? "Dead" :
"Writing" );
ber_err_print( msg );
@ -705,15 +842,15 @@ nsldapi_dump_requests_and_responses( LDAP *ld )
ber_err_print( " Empty\n" );
}
for ( ; lm != NULLMSG; lm = lm->lm_next ) {
sprintf( msg, " * msgid %d, type %d\n",
lm->lm_msgid, lm->lm_msgtype );
sprintf( msg, " * 0x%x - msgid %d, type %d\n",
lm, lm->lm_msgid, lm->lm_msgtype );
ber_err_print( msg );
if (( l = lm->lm_chain ) != NULL ) {
ber_err_print( " chained responses:\n" );
for ( ; l != NULLMSG; l = l->lm_chain ) {
sprintf( msg,
" * msgid %d, type %d\n",
l->lm_msgid, l->lm_msgtype );
" * 0x%x - msgid %d, type %d\n",
l, l->lm_msgid, l->lm_msgtype );
ber_err_print( msg );
}
}
@ -723,6 +860,31 @@ nsldapi_dump_requests_and_responses( LDAP *ld )
#endif /* LDAP_DEBUG */
LDAPRequest *
nsldapi_new_request( LDAPConn *lc, BerElement *ber, int msgid, int expect_resp )
{
LDAPRequest *lr;
lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ));
if ( lr != NULL ) {
lr->lr_conn = lc;
lr->lr_ber = ber;
lr->lr_msgid = lr->lr_origid = msgid;
lr->lr_expect_resp = expect_resp;
lr->lr_status = LDAP_REQST_INPROGRESS;
lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */
if ( lc != NULL ) { /* mark connection as in use */
++lc->lconn_refcnt;
lc->lconn_lastused = time( 0 );
}
}
return( lr );
}
void
nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
{
@ -736,6 +898,10 @@ nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
--lr->lr_parent->lr_outrefcnt;
}
if ( lr->lr_status == LDAP_REQST_WRITING ) {
--lr->lr_conn->lconn_pending_requests;
}
/* free all of our spawned referrals (child requests) */
for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = nextlr ) {
nextlr = tmplr->lr_sibling;
@ -775,6 +941,31 @@ nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
}
/*
* Add a request to the end of the list of outstanding requests.
* This function must be called with these two locks in hand, acquired in
* this order:
* LDAP_CONN_LOCK
* LDAP_REQ_LOCK
*/
void
nsldapi_queue_request_nolock( LDAP *ld, LDAPRequest *lr )
{
if ( NULL == ld->ld_requests ) {
ld->ld_requests = lr;
} else {
LDAPRequest *tmplr;
for ( tmplr = ld->ld_requests; tmplr->lr_next != NULL;
tmplr = tmplr->lr_next ) {
;
}
tmplr->lr_next = lr;
lr->lr_prev = tmplr;
}
}
static void
free_servers( LDAPServer *srvlist )
{

View File

@ -35,6 +35,13 @@ static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of
#include "ldap-int.h"
/*
* Special return values used by some functions (wait4msg() and read1msg()).
*/
#define NSLDAPI_RESULT_TIMEOUT 0
#define NSLDAPI_RESULT_ERROR (-1)
#define NSLDAPI_RESULT_NOT_FOUND (-2)
static int check_response_queue( LDAP *ld, int msgid, int all,
int do_abandon_check, LDAPMessage **result );
static int ldap_abandoned( LDAP *ld, int msgid );
@ -51,10 +58,6 @@ static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
static int cldap_select1( LDAP *ld, struct timeval *timeout );
#endif
static void link_pend( LDAP *ld, LDAPPend *lp );
#if 0 /* these functions are no longer used */
static void unlink_pend( LDAP *ld, LDAPPend *lp );
static int unlink_msg( LDAP *ld, int msgid, int all );
#endif /* 0 */
/*
* ldap_result - wait for an ldap result response to a message from the
@ -259,14 +262,23 @@ check_response_queue( LDAP *ld, int msgid, int all, int do_abandon_check,
}
/*
* wait4msg(): Poll for incoming LDAP messages, respecting the timeout.
*
* Return values:
* > 0: message received; value is the tag of the message.
* NSLDAPI_RESULT_TIMEOUT timeout exceeded.
* NSLDAPI_RESULT_ERROR fatal error occurred such as connection closed.
*/
static int
wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
struct timeval *timeout, LDAPMessage **result )
{
int rc;
int err, rc = NSLDAPI_RESULT_NOT_FOUND;
struct timeval tv, *tvp;
long start_time = 0, tmp_time;
LDAPConn *lc, *nextlc;
/* lr points to the specific request we are waiting for, if any */
LDAPRequest *lr = NULL;
#ifdef LDAP_DEBUG
@ -286,12 +298,12 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
rc = (ld->ld_cache_result)( ld, msgid, all, timeout, result );
LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
/* if ( unlock_permitted ) LDAP_MUTEX_LOCK( ld ); */
if ( rc != 0 ) {
if ( rc != NSLDAPI_RESULT_TIMEOUT ) {
return( rc );
}
if ( ld->ld_cache_strategy == LDAP_CACHE_LOCALDB ) {
LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL, NULL );
return( 0 ); /* timeout */
return( NSLDAPI_RESULT_TIMEOUT );
}
}
@ -306,14 +318,14 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL,
nsldapi_strdup( "unknown message id" ));
return( -1 ); /* could not find request for msgid */
return( NSLDAPI_RESULT_ERROR ); /* could not find request for msgid */
}
if ( lr->lr_conn != NULL &&
lr->lr_conn->lconn_status == LDAP_CONNST_DEAD ) {
nsldapi_free_request( ld, lr, 1 );
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
return( -1 ); /* connection dead */
return( NSLDAPI_RESULT_ERROR ); /* connection dead */
}
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
}
@ -326,14 +338,19 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
start_time = (long)time( NULL );
}
rc = -2;
while ( rc == -2 ) {
rc = NSLDAPI_RESULT_NOT_FOUND;
while ( rc == NSLDAPI_RESULT_NOT_FOUND ) {
#ifdef LDAP_DEBUG
if ( ldap_debug & LDAP_DEBUG_TRACE ) {
nsldapi_dump_connection( ld, ld->ld_conns, 1 );
nsldapi_dump_requests_and_responses( ld );
}
#endif /* LDAP_DEBUG */
/*
* Check if we have some data in a connection's BER buffer.
* If so, use it.
*/
LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
@ -348,10 +365,14 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
if ( lc == NULL ) {
rc = nsldapi_iostatus_poll( ld, tvp );
/*
* There was no buffered data. Poll to check connection
* status (read/write readiness).
*/
err = nsldapi_iostatus_poll( ld, tvp );
#if defined( LDAP_DEBUG ) && !defined( macintosh ) && !defined( DOS )
if ( rc == -1 ) {
if ( err == -1 ) {
LDAPDebug( LDAP_DEBUG_TRACE,
"nsldapi_iostatus_poll returned -1: errno %d\n",
LDAP_GET_ERRNO( ld ), 0, 0 );
@ -359,67 +380,100 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
#endif
#if !defined( macintosh ) && !defined( DOS )
if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
LDAP_BITOPT_RESTART ) == 0 ||
LDAP_GET_ERRNO( ld ) != EINTR ))) {
#else
if ( rc == -1 || rc == 0 ) {
/*
* If the restart option is enabled and the error
* was EINTR, try again.
*/
if ( err == -1
&& 0 != ( ld->ld_options & LDAP_BITOPT_RESTART )
&& LDAP_GET_ERRNO( ld ) == EINTR ) {
continue;
}
#endif
LDAP_SET_LDERRNO( ld, (rc == -1 ?
/*
* Handle timeouts (no activity) and fatal errors.
*/
if ( err == -1 || err == 0 ) {
LDAP_SET_LDERRNO( ld, (err == -1 ?
LDAP_SERVER_DOWN : LDAP_TIMEOUT), NULL,
NULL );
if ( rc == -1 ) {
if ( err == -1 ) {
LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
nsldapi_connection_lost_nolock( ld,
NULL );
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
rc = NSLDAPI_RESULT_ERROR;
} else {
rc = NSLDAPI_RESULT_TIMEOUT;
}
return( rc );
}
if ( rc == -1 ) {
rc = -2; /* select interrupted: loop */
} else {
rc = -2;
LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
lc = nextlc ) {
nextlc = lc->lconn_next;
if ( lc->lconn_status ==
LDAP_CONNST_CONNECTED &&
nsldapi_iostatus_is_read_ready( ld,
lc->lconn_sb )) {
rc = read1msg( ld, msgid, all,
lc->lconn_sb, lc, result );
}
else if (ld->ld_options & LDAP_BITOPT_ASYNC) {
if ( lr
&& lc->lconn_status == LDAP_CONNST_CONNECTING
&& nsldapi_iostatus_is_write_ready( ld,
lc->lconn_sb ) ) {
rc = nsldapi_ber_flush( ld, lc->lconn_sb, lr->lr_ber, 0, 1 );
if ( rc == 0 ) {
rc = LDAP_RES_BIND;
lc->lconn_status = LDAP_CONNST_CONNECTED;
lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
}
else if ( rc == -1 ) {
LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
nsldapi_free_request( ld, lr, 0 );
nsldapi_free_connection( ld, lc, NULL, NULL,
0, 0 );
}
}
/*
* Check each connection for interesting activity.
*/
LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
for ( lc = ld->ld_conns;
rc == NSLDAPI_RESULT_NOT_FOUND && lc != NULL;
lc = nextlc ) {
nextlc = lc->lconn_next;
/*
* For connections that are in the CONNECTING
* state, check for write ready (which
* indicates that the connection completed) and
* transition to the CONNECTED state.
*/
if ( lc->lconn_status == LDAP_CONNST_CONNECTING
&& nsldapi_iostatus_is_write_ready( ld,
lc->lconn_sb ) ) {
lc->lconn_status = LDAP_CONNST_CONNECTED;
LDAPDebug( LDAP_DEBUG_TRACE,
"wait4msg: connection 0x%x -"
" LDAP_CONNST_CONNECTING ->"
" LDAP_CONNST_CONNECTED\n",
lc, 0, 0 );
}
if ( lc->lconn_status
!= LDAP_CONNST_CONNECTED ) {
continue;
}
/*
* For connections that are CONNECTED, check
* for read ready (which indicates that data
* from server is available), and, for
* connections with associated requests that
* have not yet been sent, write ready (okay
* to send some data to the server).
*/
if ( nsldapi_iostatus_is_read_ready( ld,
lc->lconn_sb )) {
rc = read1msg( ld, msgid, all,
lc->lconn_sb, lc, result );
}
/*
* Send pending requests if possible.
*/
if ( lc->lconn_pending_requests > 0
&& nsldapi_iostatus_is_write_ready( ld,
lc->lconn_sb )) {
err = nsldapi_send_pending_requests_nolock(
ld, lc );
if ( err == -1 &&
rc == NSLDAPI_RESULT_NOT_FOUND ) {
rc = NSLDAPI_RESULT_ERROR;
}
}
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
}
LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
}
/*
@ -430,7 +484,7 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
* waiting on the network for a message that we already
* received!
*/
if ( rc == -2 &&
if ( rc == NSLDAPI_RESULT_NOT_FOUND &&
check_response_queue( ld, msgid, all, 0, result ) != 0 ) {
LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
rc = (*result)->lm_msgtype;
@ -439,10 +493,10 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
/*
* honor the timeout if specified
*/
if ( rc == -2 && tvp != NULL ) {
if ( rc == NSLDAPI_RESULT_NOT_FOUND && tvp != NULL ) {
tmp_time = (long)time( NULL );
if (( tv.tv_sec -= ( tmp_time - start_time )) <= 0 ) {
rc = 0; /* timed out */
rc = NSLDAPI_RESULT_TIMEOUT;
LDAP_SET_LDERRNO( ld, LDAP_TIMEOUT, NULL,
NULL );
break;
@ -458,7 +512,6 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
}
#define NSLDAPI_REQUEST_COMPLETE( lr ) \
( (lr)->lr_outrefcnt <= 0 && \
(lr)->lr_res_msgtype != LDAP_RES_SEARCH_ENTRY && \
@ -466,6 +519,12 @@ wait4msg( LDAP *ld, int msgid, int all, int unlock_permitted,
/*
* read1msg() should be called with LDAP_CONN_LOCK and LDAP_REQ_LOCK locked.
*
* Return values:
* > 0: message received; value is the tag of the message.
* NSLDAPI_RESULT_TIMEOUT timeout exceeded.
* NSLDAPI_RESULT_ERROR fatal error occurred such as connection closed.
* NSLDAPI_RESULT_NOT_FOUND message not yet complete; keep waiting.
*/
static int
read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
@ -490,7 +549,7 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
*/
if ( lc->lconn_ber == NULLBER && nsldapi_alloc_ber_with_options( ld,
&lc->lconn_ber ) != LDAP_SUCCESS ) {
return( -1 );
return( NSLDAPI_RESULT_ERROR );
}
/*
@ -504,14 +563,14 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
!= LDAP_TAG_MESSAGE ) {
terrno = LDAP_GET_ERRNO( ld );
if ( terrno == EWOULDBLOCK || terrno == EAGAIN ) {
return( -2 ); /* try again */
return( NSLDAPI_RESULT_NOT_FOUND ); /* try again */
}
LDAP_SET_LDERRNO( ld, (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
LDAP_LOCAL_ERROR), NULL, NULL );
if ( tag == LBER_DEFAULT ) {
nsldapi_connection_lost_nolock( ld, sb );
}
return( -1 );
return( NSLDAPI_RESULT_ERROR );
}
/*
@ -525,13 +584,13 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
ber_free( ber, 1 );
LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
return( -1 );
return( NSLDAPI_RESULT_ERROR );
}
/* if it's been abandoned, toss it */
if ( ldap_abandoned( ld, (int)id ) ) {
ber_free( ber, 1 );
return( -2 ); /* continue looking */
return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */
}
if ( id == LDAP_RES_UNSOLICITED ) {
@ -541,14 +600,14 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
"no request for response with msgid %ld (tossing)\n",
id, 0, 0 );
ber_free( ber, 1 );
return( -2 ); /* continue looking */
return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */
}
/* the message type */
if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
ber_free( ber, 1 );
LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
return( -1 );
return( NSLDAPI_RESULT_ERROR );
}
LDAPDebug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
( tag == LDAP_RES_SEARCH_ENTRY ) ? "ENTRY" :
@ -559,7 +618,7 @@ read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
id = lr->lr_origid;
lr->lr_res_msgtype = tag;
}
rc = -2; /* default is to keep looking (no response found) */
rc = NSLDAPI_RESULT_NOT_FOUND; /* default is to keep looking (no response found) */
if ( id != LDAP_RES_UNSOLICITED && ( tag == LDAP_RES_SEARCH_REFERENCE ||
tag != LDAP_RES_SEARCH_ENTRY )) {
@ -657,7 +716,7 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
}
if ( build_result_ber( ld, &ber, lr )
!= LDAP_SUCCESS ) {
rc = -1; /* fatal error */
rc = NSLDAPI_RESULT_ERROR;
} else {
manufactured_result = 1;
}
@ -678,7 +737,7 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
if ( (new = (LDAPMessage*)NSLDAPI_CALLOC( 1, sizeof(struct ldapmsg) ))
== NULL ) {
LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
return( -1 );
return( NSLDAPI_RESULT_ERROR );
}
new->lm_msgid = (int)id;
new->lm_msgtype = tag;
@ -744,12 +803,13 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
if( message_can_be_returned )
POST( ld, new->lm_msgid, new );
return( -2 ); /* continue looking */
return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */
}
LDAPDebug( LDAP_DEBUG_TRACE,
"adding response id %d type %d (looking for id %d)\n",
new->lm_msgid, new->lm_msgtype, msgid );
"adding response 0x%x - id %d type %d",
new, new->lm_msgid, new->lm_msgtype );
LDAPDebug( LDAP_DEBUG_TRACE, " (looking for id %d)\n", msgid, 0, 0 );
/*
* part of a search response - add to end of list of entries
@ -864,7 +924,7 @@ lr->lr_res_matched ? lr->lr_res_matched : "" );
return( tag );
}
LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
return( -2 ); /* continue looking */
return( NSLDAPI_RESULT_NOT_FOUND ); /* continue looking */
}
@ -1354,98 +1414,3 @@ link_pend( LDAP *ld, LDAPPend *lp )
ld->ld_pend = lp;
lp->lp_prev = NULL;
}
#if 0 /* these functions are no longer used */
static void
unlink_pend( LDAP *ld, LDAPPend *lp )
{
if ( lp->lp_prev == NULL ) {
ld->ld_pend = lp->lp_next;
} else {
lp->lp_prev->lp_next = lp->lp_next;
}
if ( lp->lp_next != NULL ) {
lp->lp_next->lp_prev = lp->lp_prev;
}
}
static int
unlink_msg( LDAP *ld, int msgid, int all )
{
int rc;
LDAPMessage *lm, *lastlm, *nextlm;
lastlm = NULL;
LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
for ( lm = ld->ld_responses; lm != NULL; lm = nextlm )
{
nextlm = lm->lm_next;
if ( lm->lm_msgid == msgid )
{
LDAPMessage *tmp;
if ( all == 0
|| (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
&& lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE
&& lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
break;
for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) {
if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
break;
}
if( tmp != NULL )
break;
}
lastlm = lm;
}
if( lm != NULL )
{
if ( all == 0 )
{
if ( lm->lm_chain == NULL )
{
if ( lastlm == NULL )
ld->ld_responses = lm->lm_next;
else
lastlm->lm_next = lm->lm_next;
}
else
{
if ( lastlm == NULL )
{
ld->ld_responses = lm->lm_chain;
ld->ld_responses->lm_next = lm->lm_next;
}
else
{
lastlm->lm_next = lm->lm_chain;
lastlm->lm_next->lm_next = lm->lm_next;
}
}
}
else
{
if ( lastlm == NULL )
ld->ld_responses = lm->lm_next;
else
lastlm->lm_next = lm->lm_next;
}
if ( all == 0 )
lm->lm_chain = NULL;
lm->lm_next = NULL;
rc = lm->lm_msgtype;
}
else
{
rc = -2;
}
LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
return ( rc );
}
#endif /* 0 */

View File

@ -1,35 +0,0 @@
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/* This stub function allows us to get around
the linking error we were seeing on OSF
because of the svrcore component. This
module should be deleted as soon as the
svrcore mess is cleaned up */
#ifdef OSF1
void SVRPLCY_InstallSSLPolicy()
{
return;
}
#endif

View File

@ -59,13 +59,6 @@
#endif /* DOS */
#endif /* MACOS */
#undef NET_SSL
#if defined(NET_SSL)
#include <sec.h>
static SECCertDBHandle certdbhandle;
#endif
#include "ldap.h"
#include "disptmpl.h"
#include "ldaplog.h"
@ -74,6 +67,13 @@ static SECCertDBHandle certdbhandle;
#include "lcache.h"
#endif /* !NO_LIBLCACHE */
#undef NET_SSL
#if defined(NET_SSL)
#include <nss.h>
#include <ldap_ssl.h>
#endif
#if !defined( PCNFS ) && !defined( WINSOCK ) && !defined( MACOS )
#define MOD_USE_BVALS
#endif /* !PCNFS && !WINSOCK && !MACOS */
@ -315,12 +315,13 @@ bind_prompt( LDAP *ld, char **dnp, char **passwdp, int *authmethodp,
}
#define HEX2BIN( h ) ( (h) >= '0' && (h) <='0' ? (h) - '0' : (h) - 'A' + 10 )
#define HEX2BIN( h ) ( (h) >= '0' && (h) <='9' ? (h) - '0' : (h) - 'A' + 10 )
void
berval_from_hex( struct berval *bvp, char *hexstr )
{
char *src, *dst, c, abyte;
char *src, *dst, c;
unsigned char abyte;
dst = bvp->bv_val;
bvp->bv_len = 0;
@ -803,9 +804,13 @@ main(
getline( oid, sizeof(oid), stdin, "oid? " );
getline( value, sizeof(value), stdin, "value? " );
val.bv_val = value;
val.bv_len = strlen( value );
if ( strncmp( value, "0x", 2 ) == 0 ) {
val.bv_val = (char *)malloc( strlen( value ) / 2 );
berval_from_hex( &val, value + 2 );
} else {
val.bv_val = strdup( value );
val.bv_len = strlen( value );
}
if ( ldap_extended_operation( ld, oid, &val, NULL,
NULL, &id ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_extended_operation" );
@ -813,6 +818,7 @@ main(
printf( "Extended op initiated with id %d\n",
id );
}
free( val.bv_val );
}
break;
@ -1267,7 +1273,7 @@ main(
getline( line, sizeof(line), stdin,
"security DB path?" );
if ( ldapssl_client_init( (*line == '\0') ?
NULL : line, &certdbhandle ) < 0 ) {
NULL : line, NULL ) < 0 ) {
perror( "ldapssl_client_init" );
optval = 0; /* SSL not avail. */
} else if ( ldapssl_install_routines( ld )
@ -1280,12 +1286,38 @@ main(
ldap_set_option( ld, LDAP_OPT_SSL,
optval ? LDAP_OPT_ON : LDAP_OPT_OFF );
getline( line, sizeof(line), stdin,
"Set SSL options (0=no, 1=yes)?" );
optval = ( atoi( line ) != 0 );
while ( 1 ) {
PRInt32 sslopt;
PRBool on;
getline( line, sizeof(line), stdin,
"Option to set (0 if done)?" );
sslopt = atoi(line);
if ( sslopt == 0 ) {
break;
}
getline( line, sizeof(line), stdin,
"On=1, Off=0?" );
on = ( atoi( line ) != 0 );
if ( ldapssl_set_option( ld, sslopt, on ) != 0 ) {
ldap_perror( ld, "ldapssl_set_option" );
}
}
#endif
getline( line, sizeof(line), stdin, "Reconnect?" );
ldap_set_option( ld, LDAP_OPT_RECONNECT,
( atoi( line ) == 0 ) ? LDAP_OPT_OFF :
LDAP_OPT_ON );
getline( line, sizeof(line), stdin, "Async I/O?" );
ldap_set_option( ld, LDAP_OPT_ASYNC_CONNECT,
( atoi( line ) == 0 ) ? LDAP_OPT_OFF :
LDAP_OPT_ON );
break;
case 'I': /* initialize display templates */

View File

@ -205,11 +205,21 @@ nsldapi_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **serverctrls,
}
/* send the message */
if ( nsldapi_ber_flush( ld, sb, ber, 1, 0 ) != 0 ) {
err = nsldapi_send_ber_message( ld, sb, ber, 1 /* free ber */ );
if ( err != 0 ) {
ber_free( ber, 1 );
err = LDAP_SERVER_DOWN;
LDAP_SET_LDERRNO( ld, err, NULL, NULL );
return( err );
if (err != -2 ) {
/*
* Message could not be sent, and the reason is
* something other than a "would block" error.
* Note that we ignore "would block" errors because
* it is not critical that an UnBind request
* actually reach the LDAP server.
*/
err = LDAP_SERVER_DOWN;
LDAP_SET_LDERRNO( ld, err, NULL, NULL );
return( err );
}
}
return( LDAP_SUCCESS );

View File

@ -340,7 +340,8 @@ prldap_try_one_address( struct lextiof_socket_private *prsockp,
* Try to open the TCP connection itself:
*/
if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) {
prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))
&& PR_IN_PROGRESS_ERROR != PR_GetError() ) {
PR_Close( prsockp->prsock_prfd );
prsockp->prsock_prfd = NULL;
return( -1 );