mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
326 lines
6.5 KiB
C++
326 lines
6.5 KiB
C++
/* 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
|