/* 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 */ #include "vio-global.h" #ifdef __GNUC__ #pragma implementation // gcc: Class implementation #endif #include /* * Probably no need to clean this up */ #ifdef _WIN32 #include #endif #include #if !defined(__WIN32__) && !defined(MSDOS) #include #endif #if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) #include #include #include #if !defined(alpha_linux_port) #include #endif #if defined(__EMX__) #include #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 #ifdef HAVE_SYS_UN_H #include #endif #include #include #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