summaryrefslogtreecommitdiff
path: root/vio/VioSSL.cc
diff options
context:
space:
mode:
Diffstat (limited to 'vio/VioSSL.cc')
-rw-r--r--vio/VioSSL.cc292
1 files changed, 292 insertions, 0 deletions
diff --git a/vio/VioSSL.cc b/vio/VioSSL.cc
new file mode 100644
index 00000000000..a8efacf912f
--- /dev/null
+++ b/vio/VioSSL.cc
@@ -0,0 +1,292 @@
+/*
+** Virtual I/O library for SSL wrapper
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+/*
+ * This file has some huge DBUG_ statements. Boy, this is silly...
+ */
+
+#include "vio-global.h"
+#ifdef VIO_HAVE_OPENSSL
+#include <assert.h>
+#include <netinet/in.h>
+#include <openssl/x509.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+VIO_NS_BEGIN
+
+#define this_ssl_con my_static_cast(SSL*)(this->ssl_con_)
+#define this_bio my_static_cast(BIO*)(this->bio_)
+typedef char* dataptr_t;
+
+static void
+report_errors()
+{
+ unsigned long l;
+ const char* file;
+ const char* data;
+ int line,flags;
+ DBUG_ENTER("VioSSLConnectorFd::report_errors");
+
+ while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
+ {
+ char buf[200];
+ DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
+ file,line,(flags&ERR_TXT_STRING)?data:"")) ;
+ }
+ DBUG_VOID_RETURN;
+}
+
+//FIXME: duplicate code!
+VioSSL::VioSSL(int fd,
+ vio_ptr ssl_context,
+ int state)
+ : bio_(0), ssl_con_(0), open_(false), sd_(new VioSocket(fd))
+{
+ DBUG_ENTER("VioSSL::VioSSL");
+ DBUG_PRINT("enter", ("this=%p, fd=%d, ssl_context=%p, state=%d",
+ this, fd, ssl_context, state));
+ assert(fd!=0);
+ assert(ssl_context!=0);
+ assert(state==state_connect || state==state_accept);
+
+ if (!init_bio_(fd, ssl_context, state, BIO_NOCLOSE))
+ open_ = true;
+ DBUG_VOID_RETURN;
+}
+
+
+VioSSL::VioSSL(VioSocket* sd,
+ vio_ptr ssl_context,
+ int state)
+ :bio_(0), ssl_con_(0), open_(false), sd_(sd)
+{
+ DBUG_ENTER("VioSSL::VioSSL");
+ DBUG_PRINT("enter",
+ ("this=%p, sd=%s, ssl_context=%p, state=%d",
+ this, sd ? sd->description() : "0", ssl_context, state));
+ assert(sd != 0);
+ assert(ssl_context != 0);
+ assert(state == state_connect || state==state_accept);
+
+ if (!init_bio_(sd->sd_, ssl_context, state, BIO_NOCLOSE))
+ open_ = true;
+ DBUG_VOID_RETURN;
+}
+
+VioSSL::~VioSSL()
+{
+ DBUG_ENTER("VioSSL::~VioSSL");
+ DBUG_PRINT("enter", ("this=%p", this));
+ if (ssl_con_!=0)
+ {
+ SSL_shutdown(this_ssl_con);
+ SSL_free(this_ssl_con);
+ }
+ if (sd_!=0)
+ delete sd_;
+ /* FIXME: no need to close bio? */
+ /*
+ if (bio_!=0)
+ BIO_free(this_bio);
+ */
+ DBUG_VOID_RETURN;
+}
+
+bool
+VioSSL::is_open() const
+{
+ return open_;
+}
+
+int
+VioSSL::read(vio_ptr buf, int size)
+{
+ int r;
+ DBUG_ENTER("VioSSL::read");
+ DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size));
+ assert(this_ssl_con != 0);
+ r = SSL_read(this_ssl_con, my_static_cast(dataptr_t)(buf), size);
+ if ( r< 0)
+ report_errors();
+ DBUG_PRINT("exit", ("r=%d", r));
+ DBUG_RETURN(r);
+}
+
+int
+VioSSL::write(const vio_ptr buf, int size)
+{
+ int r;
+ DBUG_ENTER("VioSSL::write");
+ DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size));
+ assert(this_ssl_con!=0);
+ r = SSL_write(this_ssl_con, my_static_cast(dataptr_t)(buf), size);
+ if (r<0)
+ report_errors();
+ DBUG_PRINT("exit", ("r=%d", r));
+ DBUG_RETURN(r);
+}
+
+int
+VioSSL::blocking(bool onoff)
+{
+ int r;
+ DBUG_ENTER("VioSSL::blocking");
+ DBUG_PRINT("enter", ("this=%p, onoff=%s", this, onoff?"true":"false"));
+ r = sd_->blocking(onoff);
+ DBUG_PRINT("exit", ("r=%d", (int)r ));
+ DBUG_RETURN(r);
+}
+
+bool
+VioSSL::blocking() const
+{
+ bool r;
+ DBUG_ENTER("VioSSL::blocking");
+ DBUG_PRINT("enter", ("this=%p", this));
+ r = sd_->blocking();
+ DBUG_PRINT("exit", ("r=%d", (int)r ));
+ DBUG_RETURN(r);
+}
+
+int
+VioSSL::fastsend(bool onoff)
+{
+ int r;
+ DBUG_ENTER("VioSSL::fastsend");
+ DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff));
+ r = sd_->fastsend(onoff);
+ DBUG_PRINT("exit", ("r=%d", (int)r ));
+ DBUG_RETURN(r);
+}
+
+int VioSSL::keepalive(bool onoff)
+{
+ int r;
+ DBUG_ENTER("VioSSL::keepalive");
+ DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff));
+ r = sd_->keepalive(onoff);
+ DBUG_PRINT("exit", ("r=%d", int(r) ));
+ DBUG_RETURN(r);
+}
+
+bool
+VioSSL::fcntl() const
+{
+ bool r;
+ DBUG_ENTER("VioSSL::fcntl");
+ DBUG_PRINT("enter", ("this=%p", this));
+ r = sd_->fcntl();
+ DBUG_PRINT("exit", ("r=%d", (int)r ));
+ DBUG_RETURN(r);
+}
+
+bool
+VioSSL::should_retry() const
+{
+ bool r;
+ DBUG_ENTER("VioSSL::should_retry");
+ DBUG_PRINT("enter", ("this=%p", this));
+ r = sd_->should_retry();
+ DBUG_PRINT("exit", ("r=%d", (int)r ));
+ DBUG_RETURN(r);
+}
+
+int
+VioSSL::close()
+{
+ int r= -2;
+ DBUG_ENTER("VioSSL::close");
+ DBUG_PRINT("enter", ("this=%p", this));
+ if (ssl_con)
+ {
+ r = SSL_shutdown(this_ssl_con);
+ SSL_free(this_ssl_con);
+ ssl_con_ = 0;
+ BIO_free(this_bio);
+ bio_ = 0;
+ }
+ DBUG_PRINT("exit", ("r=%d", r));
+ DBUG_RETURN(r);
+}
+
+const char*
+VioSSL::description() const
+{
+ return desc_;
+}
+
+const char*
+VioSSL::peer_addr() const
+{
+ if (sd_!=0)
+ return sd != 0 ? sd_->peer_addr() : "";
+}
+
+const char*
+VioSSL::peer_name() const
+{
+ return sd != 0 ? sd_->peer_name() : "";
+}
+
+const char*
+VioSSL::cipher_description() const
+{
+ return SSL_get_cipher_name(this_ssl_con);
+}
+
+
+int
+VioSSL::init_bio_(int fd,
+ vio_ptr ssl_context,
+ int state,
+ int bio_flags)
+{
+ DBUG_ENTER("VioSSL::init_bio_");
+ DBUG_PRINT("enter",
+ ("this=%p, fd=%p, ssl_context=%p, state=%d, bio_flags=%d",
+ this, fd, ssl_context, state, bio_flags));
+
+
+ if (!(ssl_con_ = SSL_new(my_static_cast(SSL_CTX*)(ssl_context))))
+ {
+ DBUG_PRINT("error", ("SSL_new failure"));
+ report_errors();
+ DBUG_RETURN(-1);
+ }
+ if (!(bio_ = BIO_new_socket(fd, bio_flags)))
+ {
+ DBUG_PRINT("error", ("BIO_new_socket failure"));
+ report_errors();
+ SSL_free(ssl_con_);
+ ssl_con_ =0;
+ DBUG_RETURN(-1);
+ }
+ SSL_set_bio(this_ssl_con, this_bio, this_bio);
+ switch(state) {
+ case state_connect:
+ SSL_set_connect_state(this_ssl_con);
+ break;
+ case state_accept:
+ SSL_set_accept_state(this_ssl_con);
+ break;
+ default:
+ assert(0);
+ }
+ sprintf(desc_, "VioSSL(%d)", fd);
+ ssl_cip_ = new SSL_CIPHER ;
+ DBUG_RETURN(0);
+}
+
+
+VIO_NS_END
+
+#endif /* VIO_HAVE_OPENSSL */
+