--- /dev/null
+/*
+ * DEBUG: section 83 SSL accelerator support
+ *
+ */
+
+#include "squid.h"
+
+/* support.cc says this is needed */
+#if USE_SSL
+
+#include "comm.h"
+#include "Mem.h"
+#include "ssl/bio.h"
+#if HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+
+// TODO: fde.h should probably export these for wrappers like ours
+extern int default_read_method(int, char *, int);
+extern int default_write_method(int, const char *, int);
+#if _SQUID_WINDOWS_
+extern int socket_read_method(int, char *, int);
+extern int socket_write_method(int, const char *, int);
+#endif
+
+/* BIO callbacks */
+static int squid_bio_write(BIO *h, const char *buf, int num);
+static int squid_bio_read(BIO *h, char *buf, int size);
+static int squid_bio_puts(BIO *h, const char *str);
+//static int squid_bio_gets(BIO *h, char *str, int size);
+static long squid_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int squid_bio_create(BIO *h);
+static int squid_bio_destroy(BIO *data);
+/* SSL callbacks */
+static void squid_ssl_info(const SSL *ssl, int where, int ret);
+
+/// Initialization structure for the BIO table with
+/// Squid-specific methods and BIO method wrappers.
+static BIO_METHOD SquidMethods = {
+ BIO_TYPE_SOCKET,
+ "squid",
+ squid_bio_write,
+ squid_bio_read,
+ squid_bio_puts,
+ NULL, // squid_bio_gets not supported
+ squid_bio_ctrl,
+ squid_bio_create,
+ squid_bio_destroy,
+ NULL // squid_callback_ctrl not supported
+};
+
+BIO *
+Ssl::Bio::Create(const int fd)
+{
+ if (BIO *bio = BIO_new(&SquidMethods)) {
+ BIO_int_ctrl(bio, BIO_C_SET_FD, BIO_NOCLOSE, fd);
+ return bio;
+ }
+ return NULL;
+}
+
+void
+Ssl::Bio::Link(SSL *ssl, BIO *bio)
+{
+ SSL_set_bio(ssl, bio, bio); // cannot fail
+ SSL_set_info_callback(ssl, &squid_ssl_info); // does not provide diagnostic
+}
+
+
+Ssl::Bio::Bio(const int anFd): fd_(anFd)
+{
+ debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_);
+}
+
+Ssl::Bio::~Bio()
+{
+ debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_);
+ // XXX: seems wrong: we do not own this fd and callers do conn->close()!
+ comm_close(fd_);
+}
+
+int Ssl::Bio::write(const char *buf, int size, BIO *table)
+{
+ errno = 0;
+#if _SQUID_WINDOWS_
+ const int result = socket_write_method(fd_, buf, size);
+#else
+ const int result = default_write_method(fd_, buf, size);
+#endif
+ const int xerrno = errno;
+ debugs(83, 5, "FD " << fd_ << " wrote " << result << " <= " << size);
+
+ BIO_clear_retry_flags(table);
+ if (result < 0) {
+ const bool ignoreError = ignoreErrno(xerrno) != 0;
+ debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
+ if (ignoreError)
+ BIO_set_retry_write(table);
+ }
+
+ return result;
+}
+
+int
+Ssl::Bio::read(char *buf, int size, BIO *table)
+{
+ errno = 0;
+#if _SQUID_WINDOWS_
+ const int result = socket_read_method(fd_, buf, size);
+#else
+ const int result = default_read_method(fd_, buf, size);
+#endif
+ const int xerrno = errno;
+ debugs(83, 5, "FD " << fd_ << " read " << result << " <= " << size);
+
+ BIO_clear_retry_flags(table);
+ if (result < 0) {
+ const bool ignoreError = ignoreErrno(xerrno) != 0;
+ debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
+ if (ignoreError)
+ BIO_set_retry_read(table);
+ }
+
+ return result;
+}
+
+/// Called whenever the SSL connection state changes, an alert appears, or an
+/// error occurs. See SSL_set_info_callback().
+void
+Ssl::Bio::stateChanged(const SSL *ssl, int where, int ret)
+{
+ // Here we can use (where & STATE) to check the current state.
+ // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP,
+ // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE.
+ // For example:
+ // if (where & SSL_CB_HANDSHAKE_START)
+ // debugs(83, 9, "Trying to establish the SSL connection");
+ // else if (where & SSL_CB_HANDSHAKE_DONE)
+ // debugs(83, 9, "SSL connection established");
+
+ debugs(83, 7, "FD " << fd_ << " now: " << where << ' ' <<
+ SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
+}
+
+/// initializes BIO table after allocation
+static int
+squid_bio_create(BIO *bi)
+{
+ bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
+ bi->num = 0;
+ bi->ptr = NULL;
+ bi->flags = 0;
+ return 1;
+}
+
+/// cleans BIO table before deallocation
+static int
+squid_bio_destroy(BIO *table)
+{
+ delete static_cast<Ssl::Bio*>(table->ptr);
+ table->ptr = NULL;
+ return 1;
+}
+
+/// wrapper for Bio::write()
+static int
+squid_bio_write(BIO *table, const char *buf, int size)
+{
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ assert(bio);
+ return bio->write(buf, size, table);
+}
+
+/// wrapper for Bio::read()
+static int
+squid_bio_read(BIO *table, char *buf, int size)
+{
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ assert(bio);
+ return bio->read(buf, size, table);
+}
+
+/// implements puts() via write()
+static int
+squid_bio_puts(BIO *table, const char *str)
+{
+ assert(str);
+ return squid_bio_write(table, str, strlen(str));
+}
+
+/// other BIO manipulations (those without dedicated callbacks in BIO table)
+static long
+squid_bio_ctrl(BIO *table, int cmd, long arg1, void *arg2)
+{
+ debugs(83, 5, table << ' ' << cmd << '(' << arg1 << ", " << arg2 << ')');
+
+ switch (cmd) {
+ case BIO_C_SET_FD: {
+ assert(arg2);
+ const int fd = *static_cast<int*>(arg2);
+ Ssl::Bio *bio = new Ssl::Bio(fd);
+ assert(!table->ptr);
+ table->ptr = bio;
+ table->init = 1;
+ return 0;
+ }
+
+ case BIO_C_GET_FD:
+ if (table->init) {
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ assert(bio);
+ if (arg2)
+ *static_cast<int*>(arg2) = bio->fd();
+ return bio->fd();
+ }
+ return -1;
+
+ case BIO_CTRL_DUP: // XXX: Should this really do what FLUSH does?
+ case BIO_CTRL_FLUSH:
+ if (table->init) {
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ assert(bio);
+ bio->flush();
+ return 1;
+ }
+ return 0;
+
+/* we may also need to implement these:
+ case BIO_CTRL_RESET:
+ case BIO_C_FILE_SEEK:
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ case BIO_CTRL_GET_CLOSE:
+ case BIO_CTRL_SET_CLOSE:
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+*/
+ default:
+ return 0;
+
+ }
+
+ return 0; /* NOTREACHED */
+}
+
+/// wrapper for Bio::stateChanged()
+static void
+squid_ssl_info(const SSL *ssl, int where, int ret)
+{
+ if (BIO *table = SSL_get_rbio(ssl)) {
+ if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr))
+ bio->stateChanged(ssl, where, ret);
+ }
+}
+
+#endif /* USE_SSL */