/* protected by conn_mutex */ int ldap_int_flush_request( LDAP *ld, LDAPRequest *lr ) { LDAPConn *lc = lr->lr_conn; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) { if ( sock_errno() == EAGAIN ) { /* need to continue write later */ lr->lr_status = LDAP_REQST_WRITING; ldap_mark_select_write( ld, lc->lconn_sb ); ld->ld_errno = LDAP_BUSY; return -2; } else { ld->ld_errno = LDAP_SERVER_DOWN; ldap_free_request( ld, lr ); ldap_free_connection( ld, lc, 0, 0 ); return( -1 ); } } else { if ( lr->lr_parent == NULL ) { 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; /* sent -- waiting for a response */ ldap_mark_select_read( ld, lc->lconn_sb ); ldap_clear_select_write( ld, lc->lconn_sb ); } return 0; }
int ber_flush( Sockbuf *sb, BerElement *ber, int freeit ) { return ber_flush2( sb, ber, freeit ? LBER_FLUSH_FREE_ON_SUCCESS : LBER_FLUSH_FREE_NEVER ); }
/* FIXME: this function is called only by ldap_free_connection(), * which, most of the times, is called with ld_req_mutex locked */ int ldap_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **sctrls, LDAPControl **cctrls ) { BerElement *ber; ber_int_t id; Debug( LDAP_DEBUG_TRACE, "ldap_send_unbind\n", 0, 0, 0 ); #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) return LDAP_SUCCESS; #endif /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( ld->ld_errno ); } LDAP_NEXT_MSGID(ld, id); /* fill it in */ if ( ber_printf( ber, "{itn" /*}*/, id, LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return ld->ld_errno; } if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } ld->ld_errno = LDAP_SUCCESS; /* send the message */ if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { ld->ld_errno = LDAP_SERVER_DOWN; } return( ld->ld_errno ); }
static int WriteBerOnSocket( VDIR_CONNECTION * conn, BerElement * ber ) { long retVal = 0; uint64_t iWriteStartTimeInMSec = 0; iWriteStartTimeInMSec = VmDirGetTimeInMilliSec(); while( VmDirGetTimeInMilliSec() - iWriteStartTimeInMSec < (MAX_NUM_SECONDS_OF_SOCK_WRITE_RETRIES * MSECS_IN_SECOND) ) { if ( (retVal = ber_flush2( conn->sb, ber, LBER_FLUSH_FREE_NEVER )) == 0 ) { break; } #ifdef _WIN32 // in ber_flush2 (liblber) call, sock_errset() call WSASetLastError() errno = WSAGetLastError(); #endif if ( errno == EWOULDBLOCK || errno == EAGAIN ) { continue; } } if (retVal != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "WriteBerOnSocket: ber_flush2() call failed with errno = %d.", errno ); } return retVal; }
static int do_abandon( LDAP *ld, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, int sendabandon ) { BerElement *ber; int i, err; Sockbuf *sb; LDAPRequest *lr; Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); /* find the request that we are abandoning */ start_again:; lr = ld->ld_requests; while ( lr != NULL ) { /* this message */ if ( lr->lr_msgid == msgid ) { break; } /* child: abandon it */ if ( lr->lr_origid == msgid && !lr->lr_abandoned ) { (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid, sctrls, sendabandon ); /* restart, as lr may now be dangling... */ goto start_again; } lr = lr->lr_next; } if ( lr != NULL ) { if ( origid == msgid && lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; return( LDAP_PARAM_ERROR ); } if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } } /* ldap_msgdelete locks the res_mutex. Give up the req_mutex * while we're in there. */ #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif err = ldap_msgdelete( ld, msgid ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif if ( err == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } /* fetch again the request that we are abandoning */ if ( lr != NULL ) { for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { /* this message */ if ( lr->lr_msgid == msgid ) { break; } } } err = 0; if ( sendabandon ) { if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected */ err = -1; ld->ld_errno = LDAP_SERVER_DOWN; } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { /* BER element allocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { /* * We already have the mutex in LDAP_R_COMPILE, so * don't try to get it again. * LDAP_NEXT_MSGID(ld, i); */ i = ++(ld)->ld_msgid; #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr sa = {0}; /* dummy, filled with ldo_peer in request.c */ err = ber_write( ber, &sa, sizeof(sa), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2 ) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{isti", /* '}' */ i, dn, LDAP_REQ_ABANDON, msgid ); } else #endif { /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ i, LDAP_REQ_ABANDON, msgid ); } if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } else { /* Put Server Controls */ if ( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { err = -1; } else { /* close '{' */ err = ber_printf( ber, /*{*/ "N}" ); if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } } } if ( err == -1 ) { ber_free( ber, 1 ); } else { /* send the message */ if ( lr != NULL ) { assert( lr->lr_conn != NULL ); sb = lr->lr_conn->lconn_sb; } else { sb = ld->ld_sb; } if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { err = 0; } } } } if ( lr != NULL ) { if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } if ( origid == msgid ) { ldap_free_request( ld, lr ); } else { lr->lr_abandoned = 1; } } #ifdef LDAP_R_COMPILE /* ld_abandoned is actually protected by the ld_res_mutex; * give up the ld_req_mutex and get the other */ ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); #endif /* use bisection */ i = 0; if ( ld->ld_nabandoned == 0 || ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) { ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); } if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif return( ld->ld_errno ); }
static long send_ldap_ber( Operation *op, BerElement *ber ) { Connection *conn = op->o_conn; ber_len_t bytes; long ret = 0; ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes ); /* write only one pdu at a time - wait til it's our turn */ ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex ); if (( op->o_abandon && !op->o_cancel ) || !connection_valid( conn ) || conn->c_writers < 0 ) { ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); return 0; } conn->c_writers++; while ( conn->c_writers > 0 && conn->c_writing ) { ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex ); } /* connection was closed under us */ if ( conn->c_writers < 0 ) { /* we're the last waiter, let the closer continue */ if ( conn->c_writers == -1 ) ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); conn->c_writers++; ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); return 0; } /* Our turn */ conn->c_writing = 1; /* write the pdu */ while( 1 ) { int err; if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) { ret = bytes; break; } err = sock_errno(); /* * we got an error. if it's ewouldblock, we need to * wait on the socket being writable. otherwise, figure * it's a hard error and return. */ Debug( LDAP_DEBUG_CONNS, "ber_flush2 failed errno=%d reason=\"%s\"\n", err, sock_errstr(err) ); if ( err != EWOULDBLOCK && err != EAGAIN ) { conn->c_writers--; conn->c_writing = 0; ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); ldap_pvt_thread_mutex_lock( &conn->c_mutex ); connection_closing( conn, "connection lost on write" ); ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); return -1; } /* wait for socket to be write-ready */ slap_writewait_play( op ); ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex ); conn->c_writewaiter = 1; slapd_set_write( conn->c_sd, 2 ); ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); ldap_pvt_thread_pool_idle( &connection_pool ); ldap_pvt_thread_cond_wait( &conn->c_write2_cv, &conn->c_write2_mutex ); conn->c_writewaiter = 0; ldap_pvt_thread_mutex_unlock( &conn->c_write2_mutex ); ldap_pvt_thread_pool_unidle( &connection_pool ); ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex ); if ( conn->c_writers < 0 ) { ret = 0; break; } } conn->c_writing = 0; if ( conn->c_writers < 0 ) { conn->c_writers++; if ( !conn->c_writers ) ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); } else { conn->c_writers--; ldap_pvt_thread_cond_signal( &conn->c_write1_cv ); } ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); return ret; }
int main( int argc, char **argv ) { char *s; int tag; int fd, rc; BerElement *ber; Sockbuf *sb; /* enable debugging */ int ival = -1; ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); if ( argc < 2 ) { usage( argv[0] ); return( EXIT_FAILURE ); } #ifdef HAVE_CONSOLE_H ccommand( &argv ); cshow( stdout ); if (( fd = open( "lber-test", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY )) < 0 ) { perror( "open" ); return( EXIT_FAILURE ); } #else fd = fileno(stdout); #endif sb = ber_sockbuf_alloc(); ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, (void *)&fd ); if( sb == NULL ) { perror( "ber_sockbuf_alloc_fd" ); return( EXIT_FAILURE ); } if ( (ber = ber_alloc_t( LBER_USE_DER )) == NULL ) { perror( "ber_alloc" ); return( EXIT_FAILURE ); } fprintf(stderr, "encode: start\n" ); if( ber_printf( ber, "{" /*}*/ ) ) { perror( "ber_printf {" /*}*/ ); return( EXIT_FAILURE ); } for ( s = argv[1]; *s; s++ ) { char *buf; char fmt[2]; fmt[0] = *s; fmt[1] = '\0'; fprintf(stderr, "encode: %s\n", fmt ); switch ( *s ) { case 'i': /* int */ case 'b': /* boolean */ case 'e': /* enumeration */ buf = getbuf(); rc = ber_printf( ber, fmt, atoi(buf) ); break; case 'n': /* null */ case '{': /* begin sequence */ case '}': /* end sequence */ case '[': /* begin set */ case ']': /* end set */ rc = ber_printf( ber, fmt ); break; case 'o': /* octet string (non-null terminated) */ case 'B': /* bit string */ buf = getbuf(); rc = ber_printf( ber, fmt, buf, strlen(buf) ); break; case 's': /* string */ buf = getbuf(); rc = ber_printf( ber, fmt, buf ); break; case 't': /* tag for the next element */ buf = getbuf(); tag = atoi(buf); rc = ber_printf( ber, fmt, tag ); break; default: fprintf( stderr, "encode: unknown fmt %c\n", *fmt ); rc = -1; break; } if( rc == -1 ) { perror( "ber_printf" ); return( EXIT_FAILURE ); } } fprintf(stderr, "encode: end\n" ); if( ber_printf( ber, /*{*/ "N}" ) == -1 ) { perror( /*{*/ "ber_printf }" ); return( EXIT_FAILURE ); } if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { perror( "ber_flush2" ); return( EXIT_FAILURE ); } ber_sockbuf_free( sb ); return( EXIT_SUCCESS ); }