+static int
+sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+ struct tls_data *p;
+
+ assert( sbiod != NULL );
+ assert( sbiod->sbiod_pvt != NULL );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ if ( opt == LBER_SB_OPT_GET_SSL ) {
+ *((SSL **)arg) = p->ssl;
+ return 1;
+
+ } else if ( opt == LBER_SB_OPT_DATA_READY ) {
+ if( SSL_pending( p->ssl ) > 0 ) {
+ return 1;
+ }
+ }
+
+ return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
+}
+
+static ber_slen_t
+sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct tls_data *p;
+ ber_slen_t ret;
+ int err;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ ret = SSL_read( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+ errno = WSAGetLastError();
+#endif
+ err = SSL_get_error( p->ssl, ret );
+ if (err == SSL_ERROR_WANT_READ ) {
+ sbiod->sbiod_sb->sb_trans_needs_read = 1;
+#ifdef WIN32
+ errno = EWOULDBLOCK;
+#endif
+ }
+ else
+ sbiod->sbiod_sb->sb_trans_needs_read = 0;
+ return ret;
+}
+
+static ber_slen_t
+sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct tls_data *p;
+ ber_slen_t ret;
+ int err;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ ret = SSL_write( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+ errno = WSAGetLastError();
+#endif
+ err = SSL_get_error( p->ssl, ret );
+ if (err == SSL_ERROR_WANT_WRITE ) {
+ sbiod->sbiod_sb->sb_trans_needs_write = 1;
+#ifdef WIN32
+ errno = EWOULDBLOCK;
+#endif
+ }
+ else
+ sbiod->sbiod_sb->sb_trans_needs_write = 0;
+ return ret;
+}
+
+Sockbuf_IO ldap_pvt_sockbuf_io_tls =
+{
+ sb_tls_setup, /* sbi_setup */
+ sb_tls_remove, /* sbi_remove */
+ sb_tls_ctrl, /* sbi_ctrl */
+ sb_tls_read, /* sbi_read */
+ sb_tls_write, /* sbi_write */
+ sb_tls_close /* sbi_close */
+};
+
+static int
+sb_tls_bio_create( BIO *b ) {
+ b->init = 1;
+ b->num = 0;
+ b->ptr = NULL;
+ b->flags = 0;
+ return 1;
+}
+
+static int
+sb_tls_bio_destroy( BIO *b )
+{
+ if ( b == NULL )
+ return 0;
+
+ b->ptr = NULL; /* sb_tls_remove() will free it */
+ b->init = 0;
+ b->flags = 0;
+ return 1;
+}
+
+static int
+sb_tls_bio_read( BIO *b, char *buf, int len )
+{
+ struct tls_data *p;
+ int ret;
+
+ if ( buf == NULL || len <= 0 )
+ return 0;
+
+ p = (struct tls_data *)b->ptr;
+
+ if ( p == NULL || p->sbiod == NULL )
+ return 0;
+
+ ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
+
+ BIO_clear_retry_flags( b );
+ if ( ret < 0 && errno == EWOULDBLOCK )
+ BIO_set_retry_read( b );
+
+ return ret;
+}
+
+static int
+sb_tls_bio_write( BIO *b, const char *buf, int len )
+{
+ struct tls_data *p;
+ int ret;
+
+ if ( buf == NULL || len <= 0 )
+ return 0;
+
+ p = (struct tls_data *)b->ptr;
+
+ if ( p == NULL || p->sbiod == NULL )
+ return 0;
+
+ ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
+
+ BIO_clear_retry_flags( b );
+ if ( ret < 0 && errno == EWOULDBLOCK )
+ BIO_set_retry_write( b );
+
+ return ret;
+}
+
+static long
+sb_tls_bio_ctrl( BIO *b, int cmd, long num, void *ptr )
+{
+ if ( cmd == BIO_CTRL_FLUSH ) {
+ /* The OpenSSL library needs this */
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sb_tls_bio_gets( BIO *b, char *buf, int len )
+{
+ return -1;
+}
+
+static int
+sb_tls_bio_puts( BIO *b, const char *str )
+{
+ return sb_tls_bio_write( b, str, strlen( str ) );
+}
+
+BIO_METHOD ldap_pvt_sb_bio_method =
+{
+ ( 100 | 0x400 ), /* it's a source/sink BIO */
+ "sockbuf glue",
+ sb_tls_bio_write,
+ sb_tls_bio_read,
+ sb_tls_bio_puts,
+ sb_tls_bio_gets,
+ sb_tls_bio_ctrl,
+ sb_tls_bio_create,
+ sb_tls_bio_destroy
+};
+