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