diff options
Diffstat (limited to 'vio/VioSocket.cc')
-rw-r--r-- | vio/VioSocket.cc | 326 |
1 files changed, 326 insertions, 0 deletions
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 |