Beispiel #1
0
int
ldap_send_server_request(
	LDAP *ld,
	BerElement *ber,
	ber_int_t msgid,
	LDAPRequest *parentreq,
	LDAPURLDesc **srvlist,
	LDAPConn *lc,
	LDAPreqinfo *bind,
	int m_noconn,
	int m_res )
{
	LDAPRequest	*lr;
	int		incparent, rc;

	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
	Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );

	incparent = 0;
	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */

	LDAP_CONN_LOCK_IF(m_noconn);
	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			lc = ld->ld_defconn;
		} else {
			lc = find_connection( ld, *srvlist, 1 );
			if ( lc == NULL ) {
				if ( (bind != NULL) && (parentreq != NULL) ) {
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}
				lc = ldap_new_connection( ld, srvlist, 0,
					1, bind, 1, m_res );
			}
		}
	}

	/* async connect... */
	if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
		ber_socket_t	sd = AC_SOCKET_ERROR;
		struct timeval	tv = { 0 };

		ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );

		/* poll ... */
		switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
		case 0:
			/* go on! */
			lc->lconn_status = LDAP_CONNST_CONNECTED;
			break;

		case -2:
			/* async only occurs if a network timeout is set */

			/* honor network timeout */
			LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
			if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
			{
				/* caller will have to call again */
				ld->ld_errno = LDAP_X_CONNECTING;
			}
			LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
			/* fallthru */

		default:
			/* error */
			break;
		}
	}

	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
		if ( ld->ld_errno == LDAP_SUCCESS ) {
			ld->ld_errno = LDAP_SERVER_DOWN;
		}

		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return( -1 );
	}

	use_connection( ld, lc );

#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP( ld )) {
		BerElement tmpber = *ber;
		ber_rewind( &tmpber );
		LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
		rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
			sizeof( struct sockaddr_storage ), 0 );
		LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
		if ( rc == -1 ) {
			ld->ld_errno = LDAP_ENCODING_ERROR;
			LDAP_CONN_UNLOCK_IF(m_noconn);
			return rc;
		}
	}
#endif

	/* If we still have an incomplete write, try to finish it before
	 * dealing with the new request. If we don't finish here, return
	 * LDAP_BUSY and let the caller retry later. We only allow a single
	 * request to be in WRITING state.
	 */
	rc = 0;
	if ( ld->ld_requests &&
		ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
		ldap_int_flush_request( ld, ld->ld_requests ) < 0 )
	{
		rc = -1;
	}
	if ( rc ) {
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return rc;
	}

	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
	if ( lr == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		ldap_free_connection( ld, lc, 0, 0 );
		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_CONN_UNLOCK_IF(m_noconn);
		return( -1 );
	} 
	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 ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
		lr->lr_origid = parentreq->lr_origid;
		lr->lr_parentcnt = ++parentreq->lr_parentcnt;
		lr->lr_parent = parentreq;
		lr->lr_refnext = parentreq->lr_child;
		parentreq->lr_child = lr;
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

	/* Extract requestDN for future reference */
#ifdef LDAP_CONNECTIONLESS
	if ( !LDAP_IS_UDP(ld) )
#endif
	{
		BerElement tmpber = *ber;
		ber_int_t	bint;
		ber_tag_t	tag, rtag;

		ber_reset( &tmpber, 1 );
		rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag );
		switch ( tag ) {
		case LDAP_REQ_BIND:
			rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint );
			break;
		case LDAP_REQ_DELETE:
			break;
		default:
			rtag = ber_scanf( &tmpber, "{" /*}*/ );
		case LDAP_REQ_ABANDON:
			break;
		}
		if ( tag != LDAP_REQ_ABANDON ) {
			ber_skip_tag( &tmpber, &lr->lr_dn.bv_len );
			lr->lr_dn.bv_val = tmpber.ber_ptr;
		}
	}

	lr->lr_prev = NULL;
	lr->lr_next = ld->ld_requests;
	if ( lr->lr_next != NULL ) {
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;

	ld->ld_errno = LDAP_SUCCESS;
	if ( ldap_int_flush_request( ld, lr ) == -1 ) {
		msgid = -1;
	}

	LDAP_CONN_UNLOCK_IF(m_noconn);
	return( msgid );
}
Beispiel #2
0
/* returns the message id of the request or -1 if an error occurs */
int
nsldapi_send_server_request(
    LDAP *ld,			/* session handle */
    BerElement *ber,		/* message to send */
    int msgid,			/* ID of message to send */
    LDAPRequest *parentreq,	/* non-NULL for referred requests */
    LDAPServer *srvlist,	/* servers to connect to (NULL for default) */
    LDAPConn *lc,		/* connection to use (NULL for default) */
    char *bindreqdn,		/* non-NULL for bind requests */
    int bind			/* perform a bind after opening new conn.? */
)
{
	LDAPRequest	*lr;
	int		err;
	int		incparent;	/* did we bump parent's ref count? */

	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 );

	incparent = 0;
	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
	if ( lc == NULL ) {
		if ( srvlist == NULL ) {
			if ( ld->ld_defconn == NULL ) {
				LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
				if ( bindreqdn == NULL && ( ld->ld_options
				    & LDAP_BITOPT_RECONNECT ) != 0 ) {
					LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
					    NULL, NULL );
					ber_free( ber, 1 );
					LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
					return( -1 );
				}
				LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );

				if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
					ber_free( ber, 1 );
					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
					return( -1 );
				}
			}
			lc = ld->ld_defconn;
		} else {
			if (( lc = find_connection( ld, srvlist, 1 )) ==
			    NULL ) {
				if ( bind && (parentreq != NULL) ) {
					/* Remember the bind in the parent */
					incparent = 1;
					++parentreq->lr_outrefcnt;
				}

				lc = nsldapi_new_connection( ld, &srvlist, 0,
					1, bind );
			}
			free_servers( srvlist );
		}
	}


    /*
     * 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)
     */
	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) ) ) {

		ber_free( ber, 1 );
		if ( lc != NULL ) {
			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
		}
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
		return( -1 );
	}

	use_connection( ld, lc );
	if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) ==
	    NULL || ( bindreqdn != NULL && ( bindreqdn =
	    nsldapi_strdup( bindreqdn )) == NULL )) {
		if ( lr != NULL ) {
			NSLDAPI_FREE( lr );
		}
		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
		nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
		ber_free( ber, 1 );
		if ( incparent ) {
			/* Forget about the bind */
			--parentreq->lr_outrefcnt; 
		}
		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
		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 ) { 
			/* Increment if we didn't do it before the bind */
			++parentreq->lr_outrefcnt;
		}
		lr->lr_origid = parentreq->lr_origid;
		lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
		lr->lr_parent = parentreq;
		if ( parentreq->lr_child != NULL ) {
			lr->lr_sibling = parentreq->lr_child;
		}
		parentreq->lr_child = lr;
	} else {			/* original request */
		lr->lr_origid = lr->lr_msgid;
	}

	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
	if (( lr->lr_next = ld->ld_requests ) != NULL ) {
		lr->lr_next->lr_prev = lr;
	}
	ld->ld_requests = lr;
	lr->lr_prev = NULL;

	if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) {

		/* 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 {

			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 );
		}

	} 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 );

	LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
	return( msgid );
}