summaryrefslogtreecommitdiff
path: root/vio
diff options
context:
space:
mode:
Diffstat (limited to 'vio')
-rw-r--r--vio/.cvsignore1
-rw-r--r--vio/Makefile.am44
-rw-r--r--vio/Vio.cc23
-rw-r--r--vio/Vio.h64
-rw-r--r--vio/VioAcceptorFd.cc18
-rw-r--r--vio/VioAcceptorFd.h23
-rw-r--r--vio/VioConnectorFd.cc22
-rw-r--r--vio/VioConnectorFd.h19
-rw-r--r--vio/VioFd.cc156
-rw-r--r--vio/VioFd.h38
-rw-r--r--vio/VioPipe.cc25
-rw-r--r--vio/VioPipe.h38
-rw-r--r--vio/VioSSL.cc292
-rw-r--r--vio/VioSSL.h54
-rw-r--r--vio/VioSSLAcceptorFd.cc4
-rw-r--r--vio/VioSSLFactoriesFd.cc360
-rw-r--r--vio/VioSSLFactoriesFd.h64
-rw-r--r--vio/VioSocket.cc326
-rw-r--r--vio/VioSocket.h55
-rw-r--r--vio/version.cc7
-rw-r--r--vio/vio-global.h33
-rw-r--r--vio/vioelitexx.cc26
-rw-r--r--vio/violite.h101
-rw-r--r--vio/viotest-ssl.cc106
-rw-r--r--vio/viotest-sslconnect.cc82
-rw-r--r--vio/viotest.cc49
-rw-r--r--vio/viotypes.h32
27 files changed, 2062 insertions, 0 deletions
diff --git a/vio/.cvsignore b/vio/.cvsignore
new file mode 100644
index 00000000000..c17bb8b88e1
--- /dev/null
+++ b/vio/.cvsignore
@@ -0,0 +1 @@
+skr99
diff --git a/vio/Makefile.am b/vio/Makefile.am
new file mode 100644
index 00000000000..dcdfb9c2112
--- /dev/null
+++ b/vio/Makefile.am
@@ -0,0 +1,44 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+INCLUDES = -I$(srcdir)/../include -I../include \
+ @OPENSSL_INCLUDES@
+LDADD = libvio.la
+
+
+pkglib_LTLIBRARIES = libvio.la
+noinst_PROGRAMS =
+noinst_HEADERS =
+libvio_la_SOURCES = \
+ Vio.cc VioAcceptorFd.cc \
+ VioConnectorFd.cc VioFd.cc \
+ VioHandle.cc VioSSL.cc \
+ VioSSLFactoriesFd.cc VioSocket.cc \
+ auto.cc hostnamexx.cc \
+ vdbug.cc version.cc \
+ vmem.cc violitexx.cc
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h \
+ openssl/x509 openssl/ssl.h openssl/err.h \
+ openssl/pem.h openssl/asn1.h
+
diff --git a/vio/Vio.cc b/vio/Vio.cc
new file mode 100644
index 00000000000..b15f9cfa6d2
--- /dev/null
+++ b/vio/Vio.cc
@@ -0,0 +1,23 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+#include "vio-global.h"
+
+VIO_NS_BEGIN
+
+void
+Vio::release()
+{
+ delete this;
+}
+
+Vio::~Vio()
+{
+}
+
+VIO_NS_END
diff --git a/vio/Vio.h b/vio/Vio.h
new file mode 100644
index 00000000000..959d472873f
--- /dev/null
+++ b/vio/Vio.h
@@ -0,0 +1,64 @@
+/*
+ * Abstract Virtual IO interface - class Vio. Heavily
+ * influenced by Berkeley sockets and oriented toward MySQL.
+ */
+
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+** Modified by Monty
+*/
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET,
+ VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL};
+
+class Vio {
+public:
+ virtual bool is_open() const = 0;
+ virtual int read(vio_ptr buf, int size) = 0;
+ virtual int write(const vio_ptr buf, int size) = 0;
+ virtual int blocking(bool onoff) = 0;
+ virtual bool blocking() const = 0;
+ virtual bool fcntl() const = 0;
+ virtual int fastsend(bool onoff = true) = 0;
+ virtual int keepalive(bool onoff) = 0;
+ virtual bool should_retry() const = 0;
+ virtual int close() = 0;
+ virtual void release();
+ virtual const char* description() const = 0;
+ virtual bool peer_addr(char *buf) const = 0;
+ virtual const char* cipher_description() const = 0;
+ virtual int vio_errno();
+ virtual ~Vio();
+};
+
+/* Macros to simulate the violite C interface */
+
+
+Vio *vio_new(my_socket sd, enum enum_vio_type type,
+ my_bool localhost);
+#ifdef __WIN__
+Vio* vio_new_win32pipe(HANDLE hPipe);
+#endif
+
+#define vio_delete(vio) delete vio
+#define vio_read(vio,buf,size) vio->read(buf,size)
+#define vio_write(vio,buf,size) vio->write(buf,size)
+#define vio_blocking(vio,mode) vio->blocking(mode)
+#define vio_is_blocking(vio) vio->is_blocking()
+#define vio_fastsend(vio,mode) vio->fastsend(mode)
+#define vio_keepalive(vio,mode) vio->keepalive(mode)
+#define vio_shouldretry(vio) vio->shouldretry(mode)
+#define vio_close(vio) vio->close()
+#define vio_description(vio) vio->description()
+#define vio_errno(Vio *vio) vio->errno()
+#define vio_peer_addr(vio,buf) vio->peer_addr(buf)
+#define vio_in_addr(vio,in) vio->in_addr(in)
+
+VIO_NS_END
diff --git a/vio/VioAcceptorFd.cc b/vio/VioAcceptorFd.cc
new file mode 100644
index 00000000000..4572e2cb71b
--- /dev/null
+++ b/vio/VioAcceptorFd.cc
@@ -0,0 +1,18 @@
+
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "vio-global.h"
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+VIO_NS_BEGIN
+
+VioAcceptorFd::~VioAcceptorFd()
+{
+}
+
+VIO_NS_END
diff --git a/vio/VioAcceptorFd.h b/vio/VioAcceptorFd.h
new file mode 100644
index 00000000000..e0441780db9
--- /dev/null
+++ b/vio/VioAcceptorFd.h
@@ -0,0 +1,23 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+/*
+ * Abstract acceptor.
+ */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioAcceptorFd
+{
+public:
+ virtual ~VioAcceptorFd();
+ virtual Vio* accept( int fd) = 0;
+};
+
+VIO_NS_END
diff --git a/vio/VioConnectorFd.cc b/vio/VioConnectorFd.cc
new file mode 100644
index 00000000000..49f81077a84
--- /dev/null
+++ b/vio/VioConnectorFd.cc
@@ -0,0 +1,22 @@
+
+/*
+ * Unneccessary virtual destructor.
+ */
+
+#include "vio-global.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "viotypes.h"
+#include "Vio.h"
+#include "VioConnectorFd.h"
+
+VIO_NS_BEGIN
+
+VioConnectorFd::~VioConnectorFd()
+{
+}
+
+VIO_NS_END
+
diff --git a/vio/VioConnectorFd.h b/vio/VioConnectorFd.h
new file mode 100644
index 00000000000..da684df5f1b
--- /dev/null
+++ b/vio/VioConnectorFd.h
@@ -0,0 +1,19 @@
+/*
+ * Abstract connector. The file (or socket) descriptor has to be
+ * prepared.
+ */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioConnectorFd
+{
+public:
+ virtual ~VioConnectorFd();
+ virtual Vio* connect(int fd) = 0;
+};
+
+VIO_NS_END
diff --git a/vio/VioFd.cc b/vio/VioFd.cc
new file mode 100644
index 00000000000..3c6b0108fee
--- /dev/null
+++ b/vio/VioFd.cc
@@ -0,0 +1,156 @@
+/*
+** Virtual I/O library for files
+** Written by Andrei Errapart <andreie@no.spam.ee>
+** Checked and modfied by Monty
+*/
+
+#include "vio-global.h"
+#include <assert.h>
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+VIO_NS_BEGIN
+
+VioFd::VioFd( int fd) : fd_(fd)
+{
+ sprintf(desc_, "VioFd(%d)", fd_);
+}
+
+VioFd:: ~VioFd()
+{
+ if (fd_ >= 0)
+ {
+ it r = ::close(fd_);
+ if ( r < 0)
+ {
+ /* FIXME: error handling (Not Critical for MySQL) */
+ }
+ }
+}
+
+
+bool
+VioFd::open() const
+{
+ return fd_ >= 0;
+}
+
+int
+VioFd::read(vio_ptr buf, int size)
+{
+ assert(fd_>=0);
+ return ::read(fd_, buf, size);
+}
+
+int
+VioFd::write(const vio_ptr buf, int size)
+{
+ assert(fd_>=0);
+ return ::write(fd_, buf, size);
+}
+
+int
+VioFd::blocking(bool onoff)
+{
+ if (onoff)
+ return 0;
+ else
+ return -1;
+}
+
+bool
+VioFd::blocking() const
+{
+ return true;
+}
+
+int
+VioFd::fastsend(bool tmp)
+{
+ return 0;
+}
+
+
+int
+VioFd::keepalive(boolonoff)
+{
+ return -2; // Why -2 ? (monty)
+}
+
+bool
+VioFd::fcntl() const
+{
+ return false;
+}
+
+bool
+VioFd::should_retry() const
+{
+ return false;
+}
+
+int
+VioFd::fcntl(int cmd)
+{
+ assert(fd_>=0);
+ return ::fcntl(fd_, cmd);
+}
+
+int
+VioFd::fcntl(int cmd, long arg)
+{
+ assert(fd_>=0);
+ return ::fcntl(fd_, cmd, arg);
+}
+
+int
+VioFd::fcntl(int cmd, struct flock* lock)
+{
+ assert(fd_>=0);
+ return ::fcntl(fd_, cmd, lock);
+}
+
+int
+VioFd::close()
+{
+ int r = -2;
+ if (fd_>=0)
+ {
+
+ if ((r= ::close(fd_)) == 0)
+ fd_ = -1;
+ }
+ else
+ {
+ /* FIXME: error handling */
+ }
+ return r;
+}
+
+const char*
+VioFd::description() const
+{
+ return desc_;
+}
+
+const char*
+VioFd::peer_addr() const
+{
+ return "";
+}
+
+const char*
+VioFd::peer_name() const
+{
+ return "localhost";
+}
+
+const char*
+VioFd::cipher_description() const
+{
+ return "";
+}
+
+VIO_NS_END
diff --git a/vio/VioFd.h b/vio/VioFd.h
new file mode 100644
index 00000000000..f1c009d848c
--- /dev/null
+++ b/vio/VioFd.h
@@ -0,0 +1,38 @@
+/*
+ * Concrete Vio around a file descriptor.
+ */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioFd : public Vio
+{
+public:
+ VioFd( int fd);
+ virtual ~VioFd();
+ virtual bool open() const;
+ virtual int read( vio_ptr buf, int size);
+ virtual int write( const vio_ptr buf, int size);
+ virtual bool blocking() const;
+ virtual int blocking(bool onoff);
+ virtual int fastsend(bool onoff=true);
+ virtual int keepalive( bool onoff);
+ virtual bool fcntl() const;
+ virtual bool should_retry() const;
+ virtual int fcntl( int cmd);
+ virtual int fcntl( int cmd, long arg);
+ virtual int fcntl( int cmd, struct flock* lock);
+ virtual int close();
+ virtual const char* description() const;
+ virtual const char* peer_addr() const;
+ virtual bool peer_name(char *buf) const;
+ virtual const char* cipher_description() const;
+private:
+ int fd_;
+ char desc_[100];
+};
+
+VIO_NS_END
diff --git a/vio/VioPipe.cc b/vio/VioPipe.cc
new file mode 100644
index 00000000000..5d6f9f36496
--- /dev/null
+++ b/vio/VioPipe.cc
@@ -0,0 +1,25 @@
+/*
+** Virtual I/O library for Windows named pipes
+** Written by Monty
+*/
+
+
+#ifdef __WIN32__
+#include "vio-global.h"
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+VIO_NS_BEGIN
+
+
+
+
+
+
+
+
+VIO_NS_END
+
+#endif /* WIN32 */
diff --git a/vio/VioPipe.h b/vio/VioPipe.h
new file mode 100644
index 00000000000..a6bb587c548
--- /dev/null
+++ b/vio/VioPipe.h
@@ -0,0 +1,38 @@
+/*
+ * Concrete Vio around Handle.
+ */
+
+#ifdef __WIN__
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioPipe : public Vio
+{
+public:
+ VioPipe(int fd);
+ virtual ~VioPipe();
+ virtual bool is_open() const;
+ virtual int read(vio_ptr buf, int size);
+ virtual int write(const vio_ptr buf, int size);
+ virtual int blocking(bool onoff);
+ virtual bool blocking() const;
+ virtual bool fcntl() const;
+ virtual int fastsend(bool onoff = true);
+ virtual int keepalive(bool onoff);
+ virtual bool should_retry() const;
+ virtual int close();
+ virtual void release();
+ virtual const char* description() const;
+ virtual bool peer_addr(char *buf) const;
+ virtual const char* cipher_description() const { return "";}
+ virtual int vio_errno();
+private:
+};
+
+VIO_NS_END
+
+#endif /* WIN32 */
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 */
+
diff --git a/vio/VioSSL.h b/vio/VioSSL.h
new file mode 100644
index 00000000000..6446c10700e
--- /dev/null
+++ b/vio/VioSSL.h
@@ -0,0 +1,54 @@
+/*
+ * Concrete Vio around OpenSSL's SSL structure.
+ */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioSocket;
+
+class VioSSL : public Vio
+{
+public:
+ enum {
+ state_connect = 1,
+ state_accept = 2
+ };
+public:
+ VioSSL(int fd, vio_ptr ssl_context, int state);
+ VioSSL(VioSocket* sd, vio_ptr ssl_context, int state);
+ virtual ~VioSSL();
+ virtual bool open() const;
+ virtual int read( vio_ptr buf, int size);
+ virtual int write( const vio_ptr buf, int size);
+ virtual bool blocking() const;
+ virtual int blocking(bool onoff);
+ virtual int fastsend(bool onoff=true);
+ virtual int keepalive(bool onoff);
+ virtual bool fcntl() const;
+ virtual bool should_retry() const;
+ virtual int close();
+ virtual const char* description() const;
+ virtual const char* peer_addr() const;
+ virtual const char* peer_name() const;
+ virtual const char* cipher_description() const;
+
+private:
+ int init_bio_(int fd,
+ vio_ptr ssl_context,
+ int state,
+ int bio_flags);
+ vio_ptr bio_;
+ vio_ptr ssl_con_;
+ vio_ptr ssl_cip_;
+ char desc_[100];
+ bool open_;
+ VioSocket* sd_;
+};
+
+VIO_NS_END
+
+#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSSLAcceptorFd.cc b/vio/VioSSLAcceptorFd.cc
new file mode 100644
index 00000000000..f821685430e
--- /dev/null
+++ b/vio/VioSSLAcceptorFd.cc
@@ -0,0 +1,4 @@
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
diff --git a/vio/VioSSLFactoriesFd.cc b/vio/VioSSLFactoriesFd.cc
new file mode 100644
index 00000000000..3fa660c049c
--- /dev/null
+++ b/vio/VioSSLFactoriesFd.cc
@@ -0,0 +1,360 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "vio-global.h"
+
+#ifdef VIO_HAVE_OPENSSL
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include <netinet/in.h>
+#include <openssl/x509.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/asn1.h>
+
+VIO_NS_BEGIN
+
+#define this_ssl_method my_static_cast(SSL_METHOD*)(this->ssl_method_)
+#define this_ssl_context my_static_cast(SSL_CTX*)(this->ssl_context_)
+typedef unsigned char* ssl_data_ptr_t;
+
+static bool ssl_algorithms_added = false;
+static bool ssl_error_strings_loaded= false;
+static int verify_depth = 0;
+static int verify_error = X509_V_OK;
+
+static int
+vio_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+ DBUG_ENTER("vio_verify_callback");
+ DBUG_PRINT("enter", ("ok=%d, ctx=%p", ok, ctx));
+ char buf[256];
+ X509* err_cert;
+ int err,depth;
+
+ err_cert=X509_STORE_CTX_get_current_cert(ctx);
+ err= X509_STORE_CTX_get_error(ctx);
+ depth= X509_STORE_CTX_get_error_depth(ctx);
+
+ X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buff));
+ if (!ok)
+ {
+ DBUG_PRINT("error",("verify error:num=%d:%s\n",err,
+ X509_verify_cert_error_string(err)));
+ if (verify_depth >= depth)
+ {
+ ok=1;
+ verify_error=X509_V_OK;
+ }
+ else
+ {
+ ok=0;
+ verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG;
+ }
+ }
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256);
+ DBUG_PRINT("info",("issuer= %s\n",buf));
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ DBUG_PRINT("error", ("notBefore"));
+ //ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert));
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ DBUG_PRINT("error", ("notAfter error"));
+ //ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert));
+ break;
+ }
+ DBUG_PRINT("exit", ("r=%d", ok));
+ DBUG_RETURN(ok);
+}
+
+
+static int
+vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file)
+{
+ DBUG_ENTER("vio_set_cert_stuff");
+ DBUG_PRINT("enter", ("ctx=%p, cert_file=%p, key_file=%p",
+ ctx, cert_file, key_file));
+ if (cert_file != NULL)
+ {
+ if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <= 0)
+ {
+ DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file));
+ /* FIX stderr */
+ ERR_print_errors_fp(stderr);
+ DBUG_RETURN(0);
+ }
+ if (key_file == NULL)
+ key_file = cert_file;
+ if (SSL_CTX_use_PrivateKey_file(ctx,key_file,
+ SSL_FILETYPE_PEM) <= 0)
+ {
+ DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file));
+ /* FIX stderr */
+ ERR_print_errors_fp(stderr);
+ DBUG_RETURN(0);
+ }
+
+ /* If we are using DSA, we can copy the parameters from
+ * the private key */
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if (!SSL_CTX_check_private_key(ctx))
+ {
+ DBUG_PRINT("error", ("Private key does not match the certificate public key\n"));
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1);
+}
+
+/************************ VioSSLConnectorFd **********************************/
+VioSSLConnectorFd::VioSSLConnectorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path)
+:ssl_context_(0),ssl_method_(0)
+{
+ DBUG_ENTER("VioSSLConnectorFd::VioSSLConnectorFd");
+ DBUG_PRINT("enter",
+ ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s",
+ this, key_file, cert_file, ca_path, ca_file));
+
+ /* FIXME: constants! */
+ int verify = SSL_VERIFY_PEER;
+
+ if (!ssl_algorithms_added)
+ {
+ DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()"));
+ ssl_algorithms_added = true;
+ SSLeay_add_ssl_algorithms();
+ }
+ if (!ssl_error_strings_loaded)
+ {
+ DBUG_PRINT("info", ("todo:SSL_load_error_strings()"));
+ ssl_error_strings_loaded = true;
+ SSL_load_error_strings();
+ }
+ ssl_method_ = SSLv3_client_method();
+ ssl_context_ = SSL_CTX_new(this_ssl_method);
+ if (ssl_context_ == 0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_new failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ /*
+ * SSL_CTX_set_options
+ * SSL_CTX_set_info_callback
+ * SSL_CTX_set_cipher_list
+ */
+ SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback);
+ if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1)
+ {
+ DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file,ca_path)==0)
+ {
+ DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
+ if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ }
+ DBUG_VOID_RETURN;
+ctor_failure:
+ DBUG_PRINT("exit", ("there was an error"));
+ DBUG_VOID_RETURN;
+}
+
+VioSSLConnectorFd::~VioSSLConnectorFd()
+{
+ DBUG_ENTER("VioSSLConnectorFd::~VioSSLConnectorFd");
+ DBUG_PRINT("enter", ("this=%p", this));
+ if (ssl_context_!=0)
+ SSL_CTX_free(this_ssl_context);
+ DBUG_VOID_RETURN;
+}
+
+VioSSL* VioSSLConnectorFd::connect( int fd)
+{
+ DBUG_ENTER("VioSSLConnectorFd::connect");
+ DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd));
+ DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_connect));
+}
+
+VioSSL*
+VioSSLConnectorFd::connect( VioSocket* sd)
+{
+ DBUG_ENTER("VioSSLConnectorFd::connect");
+ DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description()));
+ DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_connect));
+}
+
+void
+VioSSLConnectorFd::report_errors()
+{
+ unsigned long l;
+ const char* file;
+ const char* data;
+ int line,flags;
+
+ DBUG_ENTER("VioSSLConnectorFd::report_errors");
+ DBUG_PRINT("enter", ("this=%p", this));
+
+ 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;
+}
+
+/************************ VioSSLAcceptorFd **********************************/
+
+VioSSLAcceptorFd::VioSSLAcceptorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path)
+ :ssl_context_(0), ssl_method_(0)
+{
+ DBUG_ENTER("VioSSLAcceptorFd::VioSSLAcceptorFd");
+ DBUG_PRINT("enter",
+ ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s",
+ this, key_file, cert_file, ca_path, ca_file));
+
+ /* FIXME: constants! */
+ int verify = (SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+ SSL_VERIFY_CLIENT_ONCE);
+ session_id_context_ = static_cast<vio_ptr>(this);
+
+ if (!ssl_algorithms_added)
+ {
+ DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()"));
+ ssl_algorithms_added = true;
+ SSLeay_add_ssl_algorithms();
+ }
+ if (!ssl_error_strings_loaded)
+ {
+ DBUG_PRINT("info", ("todo: SSL_load_error_strings()"));
+ ssl_error_strings_loaded = true;
+ SSL_load_error_strings();
+ }
+ ssl_method_ = SSLv3_server_method();
+ ssl_context_ = SSL_CTX_new(this_ssl_method);
+ if (ssl_context_==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_new failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ /*
+ * SSL_CTX_set_quiet_shutdown(ctx,1);
+ *
+ */
+ SSL_CTX_sess_set_cache_size(this_ssl_context,128);
+
+ /* DH?
+ */
+ SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback);
+ /*
+ * Double cast needed at least for egcs-1.1.2 to
+ * supress warnings:
+ * 1) ANSI C++ blaah implicit cast from 'void*' to 'unsigned char*'
+ * 2) static_cast from 'void**' to 'unsigned char*'
+ * Wish I had a copy of standard handy...
+ */
+ SSL_CTX_set_session_id_context(this_ssl_context,
+ my_static_cast(ssl_data_ptr_t)
+ (my_static_cast(void*)(&session_id_context_)),
+ sizeof(session_id_context_));
+
+ /*
+ * SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
+ */
+ if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1)
+ {
+ DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file, ca_path)==0)
+ {
+ DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
+ if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0)
+ {
+ DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed"));
+ report_errors();
+ goto ctor_failure;
+ }
+ }
+ DBUG_VOID_RETURN;
+ctor_failure:
+ DBUG_PRINT("exit", ("there was an error"));
+ DBUG_VOID_RETURN;
+}
+
+VioSSLAcceptorFd::~VioSSLAcceptorFd()
+{
+ DBUG_ENTER("VioSSLAcceptorFd::~VioSSLAcceptorFd");
+ DBUG_PRINT("enter", ("this=%p", this));
+ if (ssl_context_!=0)
+ SSL_CTX_free(this_ssl_context);
+ DBUG_VOID_RETURN;
+}
+
+VioSSL*
+VioSSLAcceptorFd::accept(int fd)
+{
+ DBUG_ENTER("VioSSLAcceptorFd::accept");
+ DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd));
+ DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_accept));
+}
+
+VioSSL*
+VioSSLAcceptorFd::accept(VioSocket* sd)
+{
+ DBUG_ENTER("VioSSLAcceptorFd::accept");
+ DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description()));
+ DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_accept));
+}
+
+void
+VioSSLAcceptorFd::report_errors()
+{
+ unsigned long l;
+ const char* file;
+ const char* data;
+ int line,flags;
+
+ DBUG_ENTER("VioSSLConnectorFd::report_errors");
+ DBUG_PRINT("enter", ("this=%p", this));
+
+ 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;
+}
+
+VIO_NS_END
+
+#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSSLFactoriesFd.h b/vio/VioSSLFactoriesFd.h
new file mode 100644
index 00000000000..ed5a24f6b4a
--- /dev/null
+++ b/vio/VioSSLFactoriesFd.h
@@ -0,0 +1,64 @@
+/*
+ * Wrapper around SSL_CTX.
+ */
+
+#ifdef VIO_HAVE_OPENSSL
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+VIO_NS_BEGIN
+
+class VioSSLAcceptorFd : public VioAcceptorFd
+{
+public:
+ VioSSLAcceptorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path);
+
+ virtual ~VioSSLAcceptorFd();
+ virtual VioSSL* accept(int fd);
+ virtual VioSSL* accept(VioSocket* sd);
+private:
+ VioSSLAcceptorFd(const VioSSLAcceptorFd& rhs);//undefined
+ VioSSLAcceptorFd& operator=(const VioSSLAcceptorFd& rhs);//undefined
+private:
+ void report_errors();
+ vio_ptr ssl_;
+ vio_ptr ssl_context_;
+ vio_ptr ssl_method_;
+ vio_ptr session_id_context_;
+};
+
+VIO_NS_END
+
+/*
+ * The Factory where Vio's are made!
+ */
+
+class VioSSLConnectorFd : public VioConnectorFd
+{
+public:
+ VioSSLConnectorFd(const char* key_file,
+ const char* cert_file,
+ const char* ca_file,
+ const char* ca_path);
+
+ virtual ~VioSSLConnectorFd();
+ virtual VioSSL* connect(int fd);
+ virtual VioSSL* connect(VioSocket* sd);
+private:
+ VioSSLConnectorFd(const VioSSLConnectorFd& rhs);//undefined
+ VioSSLConnectorFd& operator=(const VioSSLConnectorFd& rhs);//undefined
+private:
+ void report_errors();
+ vio_ptr ssl_context_;
+ vio_ptr ssl_method_;
+ vio_ptr ssl_;
+};
+
+VIO_NS_END
+
+#endif /* VIO_HAVE_OPENSSL */
diff --git a/vio/VioSocket.cc b/vio/VioSocket.cc
new file mode 100644
index 00000000000..cefb0b4bdc1
--- /dev/null
+++ b/vio/VioSocket.cc
@@ -0,0 +1,326 @@
+/* Copyright Abandoned 2000 Monty Program KB
+
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "vio-global.h"
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+#include <assert.h>
+
+/*
+ * Probably no need to clean this up
+ */
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <sys/types.h>
+#if !defined(__WIN32__) && !defined(MSDOS)
+#include <sys/socket.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES)
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#if !defined(alpha_linux_port)
+#include <netinet/tcp.h>
+#endif
+#if defined(__EMX__)
+#include <sys/ioctl.h>
+#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
+#undef HAVE_FCNTL
+#endif
+#endif
+
+#if defined(MSDOS) || defined(__WIN32__)
+#ifdef __WIN32__
+#undef errno
+#undef EINTR
+#undef EAGAIN
+#define errno WSAGetLastError()
+#define EINTR WSAEINTR
+#define EAGAIN WSAEINPROGRESS
+#endif
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#ifdef __cplusplus
+extern "C" { // Because of SCO 3.2V4.2
+#endif
+#ifndef __WIN32__
+#include <sys/resource.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#include <netdb.h>
+#include <sys/utsname.h>
+#endif // __WIN32__
+#ifdef __cplusplus
+}
+#endif
+
+VIO_NS_BEGIN
+
+#define this_ssl_cip my_static_cast(SSL_CIPHER*)(this->ssl_cip_)
+
+VioSocket::VioSocket(vio_socket sd, enum_vio_type type, bool localhost)
+:sd_(sd), localhost_(localhost), fcntl_(0),
+ fcntl_set_(false), cipher_description_(0)
+{
+ DBUG_ENTER("VioSocket::VioSocket");
+ DBUG_PRINT("enter", ("sd=%d", sd));
+ if (type == VIO_TYPE_SOCKET)
+ sprintf(desc_,"Socket (%d)",sd_);
+ else
+ sprintf(desc_,"TCP/IP (%d)",sd_);
+ DBUG_VOID_RETURN;
+}
+
+VioSocket::~VioSocket()
+{
+ DBUG_ENTER("VioSocket::~VioSocket");
+ DBUG_PRINT("enter", ("sd_=%d", sd_));
+ if (sd_>=0)
+ close();
+ DBUG_VOID_RETURN;
+}
+
+bool
+VioSocket::is_open() const
+{
+ return sd_>=0;
+}
+
+int
+VioSocket::read(vio_ptr buf, int size)
+{
+ int r;
+ DBUG_ENTER("VioSocket::read");
+ DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size));
+ assert(sd_>=0);
+#if defined(MSDOS) || defined(__WIN32__)
+ r = ::recv(sd_, buf, size,0);
+#else
+ r = ::read(sd_, buf, size);
+#endif
+#ifndef DBUG_OFF
+ if ( r < 0)
+ {
+ DBUG_PRINT("error", ("Got error %d during read",errno));
+ }
+#endif /* DBUG_OFF */
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(r);
+}
+
+int
+VioSocket::write(vio_ptr buf, int size)
+{
+ int r;
+ DBUG_ENTER("VioSocket::write");
+ DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size));
+ assert(sd_>=0);
+#if defined(__WIN32__)
+ r = ::send(sd_, buf, size,0);
+#else
+ r = ::write(sd_, buf, size);
+#endif /* __WIN32__ */
+#ifndef DBUG_OFF
+ if (r < 0)
+ {
+ DBUG_PRINT("error", ("Got error %d on write",errno));
+ }
+#endif /* DBUG_OFF */
+ DBUG_RETURN(r);
+}
+
+int
+VioSocket::blocking(bool set_blocking_mode)
+{
+ int r= 0;
+ DBUG_ENTER("VioSocket::blocking");
+ DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
+
+#if !defined(___WIN32__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+ assert(sd_>=0);
+
+ int old_fcntl=fcntl_;
+ if (!fcntl_set_)
+ {
+ fcntl_set_ = true;
+ old_fcntl= fcntl_ = fcntl(F_GETFL);
+ }
+ if (set_blocking_mode)
+ fcntl_&=~O_NONBLOCK; //clear bit
+ else
+ fcntl_|=O_NONBLOCK; //set bit
+ if (old_fcntl != fcntl_)
+ r = ::fcntl(sd_, F_SETFL, fcntl_);
+#endif /* !defined(NO_FCNTL_NONBLOCK) */
+#else /* !defined(__WIN32__) && !defined(__EMX__) */
+ {
+ ulong arg;
+ int old_fcntl=vio->fcntl_mode;
+ if (!vio->fcntl_set)
+ {
+ vio->fcntl_set = TRUE;
+ old_fnctl=vio->fcntl_mode=0;
+ }
+ if (set_blocking_mode)
+ {
+ arg = 0;
+ fcntl_&=~ O_NONBLOCK; //clear bit
+ }
+ else
+ {
+ arg = 1;
+ fcntl_|= O_NONBLOCK; //set bit
+ }
+ if (old_fcntl != fcntl_)
+ r = ioctlsocket(sd_,FIONBIO,(void*)&arg,sizeof(arg));
+ }
+#endif
+ DBUG_RETURN(r);
+}
+
+bool
+VioSocket::blocking() const
+{
+ DBUG_ENTER("VioSocket::blocking");
+ bool r = !(fcntl_ & O_NONBLOCK);
+ DBUG_PRINT("exit", ("%d", (int)r));
+ DBUG_RETURN(r);
+}
+
+int
+VioSocket::fastsend(bool onoff)
+{
+ int r=0;
+ DBUG_ENTER("VioSocket::fastsend");
+ DBUG_PRINT("enter", ("onoff:%d", (int)onoff));
+ assert(sd_>=0);
+
+#ifdef IPTOS_THROUGHPUT
+#ifndef __EMX__
+ int tos = IPTOS_THROUGHPUT;
+ if (!setsockopt(sd_, IPPROTO_IP, IP_TOS, (void*) &tos, sizeof(tos)))
+#endif /* !__EMX__ */
+ {
+ int nodelay = 1;
+ if (setsockopt(sd_, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay,
+ sizeof(nodelay)))
+ {
+ DBUG_PRINT("warning",
+ ("Couldn't set socket option for fast send"));
+ r= -1;
+ }
+ }
+#endif /* IPTOS_THROUGHPUT */
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(0);
+}
+
+
+int
+VioSocket::keepalive(bool set_keep_alive)
+{
+ DBUG_ENTER("VioSocket::keepalive");
+ DBUG_PRINT("enter", ("sd_=%d, set_keep_alive=%d", sd_,
+ (int) set_keep_alive));
+ assert(sd_>=0);
+ uint opt= set_keep_alive ? 1 : 0;
+ DBUG_RETURN(setsockopt(sd_, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt,
+ sizeof(opt)));
+}
+
+
+bool
+VioSocket::should_retry() const
+{
+ int en = errno;
+ return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
+}
+
+int
+VioSocket::close()
+{
+ DBUG_ENTER("VioSocket::close");
+ assert(sd_>=0);
+ int r=0;
+ if (::shutdown(sd_,2))
+ r= -1;
+ if (::closesocket(sd_))
+ r= -1;
+ if (r)
+ {
+ DBUG_PRINT("error", ("close() failed, error: %d",errno));
+ /* FIXME: error handling (not critical for MySQL) */
+ }
+ sd_ = -1;
+ DBUG_RETURN(r);
+}
+
+
+int
+VioSocket::shutdown(int how)
+{
+ DBUG_ENTER("VioSocket::shutdown");
+ DBUG_PRINT("enter", ("how=%d", how));
+ assert(sd_>=0);
+ int r = ::shutdown(sd_, how);
+ DBUG_PRINT("exit", ("%d", r));
+ DBUG_RETURN(r);
+}
+
+
+const char*
+VioSocket::description() const
+{
+ return desc_;
+}
+
+
+bool
+VioSocket::peer_addr(char *buf) const
+{
+ DBUG_ENTER("VioSocket::peer_addr");
+ DBUG_PRINT("enter", ("sd_=%d", sd_));
+ if (localhost_)
+ {
+ strmov(buf,"127.0.0.1");
+ }
+ else
+ {
+ size_socket addrLen= sizeof(struct sockaddr);
+ if (getpeername(sd_, my_reinterpret_cast(struct sockaddr *) (&remote_),
+ &addrLen) != 0)
+ {
+ DBUG_PRINT("exit", ("getpeername, error: %d", errno));
+ DBUG_RETURN(1);
+ }
+ my_inet_ntoa(remote_.sin_addr,buf);
+ }
+ DBUG_PRINT("exit", ("addr=%s", buf));
+ DBUG_RETURN(0);
+}
+
+
+const char*
+VioSocket::cipher_description() const
+{
+ DBUG_ENTER("VioSocket::cipher_description");
+ char *r = cipher_description_ ? cipher_description_:"";
+ DBUG_PRINT("exit", ("name: %s", r));
+ DBUG_RETURN(r);
+}
+
+VIO_NS_END
diff --git a/vio/VioSocket.h b/vio/VioSocket.h
new file mode 100644
index 00000000000..e2c6eafa516
--- /dev/null
+++ b/vio/VioSocket.h
@@ -0,0 +1,55 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+/*
+ * Concrete Vio around socket. Doesn't differ much from VioFd.
+ */
+
+#ifdef WIN32
+ typedef SOCKET vio_socket;
+#else
+ typedef int vio_socket;
+#endif /* WIN32 */
+
+VIO_NS_BEGIN
+
+class VioSSL;
+class VioSocket : public Vio
+{
+public:
+ VioSocket(vio_socket sd, bool localhost=true);
+ virtual ~VioSocket();
+ virtual bool is_open() const;
+ virtual int read(vio_ptr buf, int size);
+ virtual int write(const vio_ptr buf, int size);
+ virtual int blocking(bool onoff);
+ virtual bool blocking() const;
+ virtual int fastsend(bool onoff=true);
+ virtual int keepalive(bool onoff);
+ virtual bool should_retry() const;
+ virtual int close();
+ virtual const char* description() const;
+ virtual bool peer_addr(char *buf) const;
+ virtual const char* cipher_description() const;
+ virtual int vio_errno();
+ int shutdown(int how);
+
+private:
+ vio_socket sd_;
+ const bool localhost_;
+ int fcntl_;
+ bool fcntl_set_;
+ char desc_[30];
+ mutable struct sockaddr_in local_;
+ mutable struct sockaddr_in remote_;
+ mutable char* cipher_description_;
+
+ friend class VioSSL; // he wants to tinker with this->sd_;
+};
+
+VIO_NS_END
+
+#endif /* vio_VioSocket_h_ */
+
diff --git a/vio/version.cc b/vio/version.cc
new file mode 100644
index 00000000000..7c09d431a9d
--- /dev/null
+++ b/vio/version.cc
@@ -0,0 +1,7 @@
+#include "vio-global.h"
+
+extern "C" const char*
+vio_version()
+{
+ return "0.2";
+}
diff --git a/vio/vio-global.h b/vio/vio-global.h
new file mode 100644
index 00000000000..0c3d279695d
--- /dev/null
+++ b/vio/vio-global.h
@@ -0,0 +1,33 @@
+#include <global.h>
+
+#if !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL)
+#define VIO_HAVE_OPENSSL HAVE_OPENSSL
+#endif /* !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL) */
+
+#include "viotypes.h"
+#include "Vio.h"
+#include "VioAcceptorFd.h"
+#include "VioFd.h"
+#include "VioPipe.h"
+#include "VioSocket.h"
+#ifdef VIO_HAVE_OPENSSL
+#include "VioSSL.h"
+#include "VioSSLFactoriesFd.h"
+#endif /* VIO_HAVE_OPENSSL */
+
+
+#if VIO_HAVE_NAMESPACES
+#define VIO_STD_NS std
+#define VIO_STD_NS_USING using namespace std;
+#define VIO_NS VirtualIO
+#define VIO_NS_BEGIN namespace VIO_NS {
+#define VIO_NS_END }
+#define VIO_NS_USING using namespace VIO_NS;
+#else
+#define VIO_STD_NS
+#define VIO_STD_NS_USING
+#define VIO_NS
+#define VIO_NS_BEGIN
+#define VIO_NS_END
+#define VIO_NS_USING
+#endif
diff --git a/vio/vioelitexx.cc b/vio/vioelitexx.cc
new file mode 100644
index 00000000000..0eac28eaf55
--- /dev/null
+++ b/vio/vioelitexx.cc
@@ -0,0 +1,26 @@
+/* Copyright Abandoned 2000 Monty Program KB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+ * Renamed of violite.cc to violitexx.cc because of clashes
+ * with violite.c
+ * This file implements the same functions as in violite.c, but now using
+ * the Vio class
+ */
+
+#include "vio-global.h"
+
+Vio*
+vio_new(my_socket sd, enum_vio_type type, my_bool localhost)
+{
+ return my_reinterpret_cast(Vio*) (new VioSocket(sd, type, localhost));
+}
+
+
+#ifdef __WIN32__
+Vio
+*vio_new_win32pipe(HANDLE hPipe)
+{
+ return my_reinterpret_cast(Vio*) (new VioPipe(hPipe));
+}
+#endif
diff --git a/vio/violite.h b/vio/violite.h
new file mode 100644
index 00000000000..fc480f59db1
--- /dev/null
+++ b/vio/violite.h
@@ -0,0 +1,101 @@
+/* Copyright Abandoned 2000 Monty Program KB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+ * Vio Lite.
+ * Purpose: include file for Vio that will work with C and C++
+ */
+
+#ifndef vio_violite_h_
+#define vio_violite_h_
+
+#include "my_net.h" /* needed because of struct in_addr */
+
+#ifdef HAVE_VIO
+#include <Vio.h> /* Full VIO interface */
+#else
+
+/* Simple vio interface in C; The functions are implemented in violite.c */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef Vio_defined
+#define Vio_defined
+struct st_vio; /* Only C */
+typedef struct st_vio Vio;
+#endif
+
+enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET,
+ VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL};
+
+Vio* vio_new(my_socket sd,
+ enum enum_vio_type type,
+ my_bool localhost);
+#ifdef __WIN__
+Vio* vio_new_win32pipe(HANDLE hPipe);
+#endif
+void vio_delete(Vio* vio);
+
+/*
+ * vio_read and vio_write should have the same semantics
+ * as read(2) and write(2).
+ */
+int vio_read( Vio* vio,
+ gptr buf, int size);
+int vio_write( Vio* vio,
+ const gptr buf,
+ int size);
+/*
+ * Whenever the socket is set to blocking mode or not.
+ */
+int vio_blocking( Vio* vio,
+ my_bool onoff);
+my_bool vio_is_blocking( Vio* vio);
+/*
+ * setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible.
+ */
+int vio_fastsend( Vio* vio,
+ my_bool onoff);
+/*
+ * setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible.
+ */
+int vio_keepalive( Vio* vio,
+ my_bool onoff);
+/*
+ * Whenever we should retry the last read/write operation.
+ */
+my_bool vio_should_retry( Vio* vio);
+/*
+ * When the workday is over...
+ */
+int vio_close( Vio* vio);
+/*
+ * Short text description of the socket for those, who are curious..
+ */
+const char* vio_description( Vio* vio);
+
+/* Return the type of the connection */
+ enum enum_vio_type vio_type(Vio* vio);
+
+/* Return last error number */
+int vio_errno(Vio *vio);
+
+/* Get socket number */
+my_socket vio_fd(Vio *vio);
+
+/*
+ * Remote peer's address and name in text form.
+ */
+my_bool vio_peer_addr(Vio * vio, char *buf);
+
+/* Remotes in_addr */
+
+void vio_in_addr(Vio *vio, struct in_addr *in);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* HAVE_VIO */
+#endif /* vio_violite_h_ */
diff --git a/vio/viotest-ssl.cc b/vio/viotest-ssl.cc
new file mode 100644
index 00000000000..a708831ba67
--- /dev/null
+++ b/vio/viotest-ssl.cc
@@ -0,0 +1,106 @@
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+VIO_RCSID(vio, viotest_ssl, "$Id$")
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+void
+print_usage()
+{
+ printf("viossltest: testing SSL virtual IO. Usage:\n");
+ printf("viossltest server-key server-cert client-key client-cert [CAfile] [CApath]\n");
+}
+
+int
+main( int argc,
+ char** argv)
+{
+ char* server_key = 0;
+ char* server_cert = 0;
+ char* client_key = 0;
+ char* client_cert = 0;
+ char* ca_file = 0;
+ char* ca_path = 0;
+ int sv[2];
+
+ if (argc<5)
+ {
+ print_usage();
+ return 1;
+ }
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1)
+ fatal_error("socketpair");
+
+ server_key = argv[1];
+ server_cert = argv[2];
+ client_key = argv[3];
+ client_cert = argv[4];
+ if (argc>5)
+ ca_file = argv[5];
+ if (argc>6)
+ ca_path = argv[6];
+ printf("Server key/cert : %s/%s\n", server_key, server_cert);
+ printf("Client key/cert : %s/%s\n", client_key, client_cert);
+ if (ca_file!=0)
+ printf("CAfile : %s\n", ca_file);
+ if (ca_path!=0)
+ printf("CApath : %s\n", ca_path);
+
+ VIO_NS::VioSSLAcceptorFd* ssl_acceptor = new VIO_NS::VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path);
+ VIO_NS::VioSSLConnectorFd* ssl_connector = new VIO_NS::VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path);
+
+ printf("Socketpair: %d , %d\n", sv[0], sv[1]);
+
+ VIO_NS::VioSSL* client_vio = ssl_connector->connect(sv[0]);
+ VIO_NS::VioSSL* server_vio = ssl_acceptor->accept(sv[1]);
+
+
+ int child_pid = fork();
+ if (child_pid==-1) {
+ delete ssl_acceptor;
+ delete ssl_connector;
+ fatal_error("fork");
+ }
+ if (child_pid==0) {
+ //child, therefore, client
+ char xbuf[100];
+ int r = client_vio->read(xbuf, sizeof(xbuf));
+ if (r<=0) {
+ delete ssl_acceptor;
+ delete ssl_connector;
+ fatal_error("client:SSL_read");
+ }
+ printf("*** client cipher %s\n",client_vio->cipher_description());
+ xbuf[r] = 0;
+ printf("client:got %s\n", xbuf);
+ delete client_vio;
+ delete ssl_acceptor;
+ delete ssl_connector;
+ sleep(1);
+ } else {
+ const char* s = "Huhuhuh";
+ int r = server_vio->write((void *)s, strlen(s));
+ if (r<=0) {
+ delete ssl_acceptor;
+ delete ssl_connector;
+ fatal_error("server:SSL_write");
+ }
+ printf("*** server cipher %s\n",server_vio->cipher_description());
+ delete server_vio;
+ delete ssl_acceptor;
+ delete ssl_connector;
+ sleep(1);
+ }
+}
diff --git a/vio/viotest-sslconnect.cc b/vio/viotest-sslconnect.cc
new file mode 100644
index 00000000000..505aac024f7
--- /dev/null
+++ b/vio/viotest-sslconnect.cc
@@ -0,0 +1,82 @@
+
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+VIO_RCSID(vio, viotest_sslconnect, "$Id$")
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+void
+print_usage()
+{
+ printf("viotest-sslconnect: testing SSL virtual IO. Usage:\n");
+ printf("viotest-sslconnect key cert\n");
+}
+
+int
+main( int argc,
+ char** argv)
+{
+ char* key = 0;
+ char* cert = 0;
+
+ if (argc<3)
+ {
+ print_usage();
+ return 1;
+ }
+
+ char ip[4] = {127, 0, 0, 1};
+ unsigned long addr = (unsigned long)
+ ((unsigned long)ip[0]<<24L)|
+ ((unsigned long)ip[1]<<16L)|
+ ((unsigned long)ip[2]<< 8L)|
+ ((unsigned long)ip[3]);
+ int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd<0)
+ fatal_error("socket");
+ struct sockaddr_in sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port=htons(4433);
+ sa.sin_addr.s_addr=htonl(addr);
+ int sa_size = sizeof sa;
+ if (connect(fd, reinterpret_cast<const sockaddr*>(&sa), sa_size)==-1)
+ fatal_error("connect");
+ key = argv[1];
+ cert = argv[2];
+ printf("Key : %s\n", key);
+ printf("Cert : %s\n", cert);
+
+ VIO_NS::VioSSLConnectorFd* ssl_connector = new VIO_NS::VioSSLConnectorFd(cert, key,0,0);
+
+ VIO_NS::VioSSL* vio = ssl_connector->connect(fd);
+
+ char xbuf[100];
+ int r = vio->read(xbuf, sizeof(xbuf));
+ if (r<=0) {
+ delete ssl_connector;
+ delete vio;
+ fatal_error("client:SSL_read");
+ }
+ xbuf[r] = 0;
+ printf("client:got %s\n", xbuf);
+ delete vio;
+ delete ssl_connector;
+ return 0;
+}
diff --git a/vio/viotest.cc b/vio/viotest.cc
new file mode 100644
index 00000000000..f675267665d
--- /dev/null
+++ b/vio/viotest.cc
@@ -0,0 +1,49 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include <string.h>
+
+VIO_RCSID(vio, Vio, "$Id$")
+
+VIO_NS_USING;
+
+int
+main( int argc,
+ char** argv)
+{
+ VioFd* fs = 0;
+ VioSocket* ss = 0;
+ int fd = -1;
+ char* hh = "hshshsh\n";
+
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH("d:t");
+
+ fd = open("/dev/tty", O_WRONLY);
+ if (fd<0)
+ {
+ perror("open");
+ return 1;
+ }
+ fs = new VioFd(fd);
+ ss = new VioSocket(fd);
+ if (fs->write(hh,strlen(hh)) < 0)
+ perror("write");
+ ss->write(hh,strlen(hh));
+ printf("peer_name:%s\n", ss->peer_name());
+ printf("cipher_description:%s\n", ss->cipher_description());
+ delete fs;
+ delete ss;
+
+ DBUG_RETURN(0);
+}
+
diff --git a/vio/viotypes.h b/vio/viotypes.h
new file mode 100644
index 00000000000..8d36a35c86f
--- /dev/null
+++ b/vio/viotypes.h
@@ -0,0 +1,32 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+/*
+ * Some typedefs to external types.
+ */
+#ifndef vio_viotypes_h_
+#define vio_viotypes_h_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+typedef int vio_bool_t;
+typedef void* vio_ptr_t;
+
+#ifdef __cplusplus
+VIO_NS_BEGIN
+
+typedef vio_ptr_t vio_ptr;
+typedef char* vio_cstring;
+typedef int32_t vio_int32;
+typedef u_int32_t vio_uint32;
+typedef vio_bool_t vio_bool;
+
+VIO_NS_END
+#endif /* __cplusplus */
+
+#endif /* vio_types_h_ */
+