summaryrefslogtreecommitdiff
path: root/vio/VioSocket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'vio/VioSocket.cc')
-rw-r--r--vio/VioSocket.cc326
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