diff options
Diffstat (limited to 'vio')
-rw-r--r-- | vio/.cvsignore | 1 | ||||
-rw-r--r-- | vio/Makefile.am | 44 | ||||
-rw-r--r-- | vio/Vio.cc | 23 | ||||
-rw-r--r-- | vio/Vio.h | 64 | ||||
-rw-r--r-- | vio/VioAcceptorFd.cc | 18 | ||||
-rw-r--r-- | vio/VioAcceptorFd.h | 23 | ||||
-rw-r--r-- | vio/VioConnectorFd.cc | 22 | ||||
-rw-r--r-- | vio/VioConnectorFd.h | 19 | ||||
-rw-r--r-- | vio/VioFd.cc | 156 | ||||
-rw-r--r-- | vio/VioFd.h | 38 | ||||
-rw-r--r-- | vio/VioPipe.cc | 25 | ||||
-rw-r--r-- | vio/VioPipe.h | 38 | ||||
-rw-r--r-- | vio/VioSSL.cc | 292 | ||||
-rw-r--r-- | vio/VioSSL.h | 54 | ||||
-rw-r--r-- | vio/VioSSLAcceptorFd.cc | 4 | ||||
-rw-r--r-- | vio/VioSSLFactoriesFd.cc | 360 | ||||
-rw-r--r-- | vio/VioSSLFactoriesFd.h | 64 | ||||
-rw-r--r-- | vio/VioSocket.cc | 326 | ||||
-rw-r--r-- | vio/VioSocket.h | 55 | ||||
-rw-r--r-- | vio/version.cc | 7 | ||||
-rw-r--r-- | vio/vio-global.h | 33 | ||||
-rw-r--r-- | vio/vioelitexx.cc | 26 | ||||
-rw-r--r-- | vio/violite.h | 101 | ||||
-rw-r--r-- | vio/viotest-ssl.cc | 106 | ||||
-rw-r--r-- | vio/viotest-sslconnect.cc | 82 | ||||
-rw-r--r-- | vio/viotest.cc | 49 | ||||
-rw-r--r-- | vio/viotypes.h | 32 |
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_ */ + |