Drizzled Public API Documentation

vio.cc
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /*
00017   Note that we can't have assertion on file descriptors;  The reason for
00018   this is that during mysql shutdown, another thread can close a file
00019   we are working on.  In this case we should just return read errors from
00020   the file descriptior.
00021 */
00022 #include <config.h>
00023 #include "vio.h"
00024 #include <string.h>
00025 #include <drizzled/util/test.h>
00026 #include <sys/socket.h>
00027 #include <string.h>
00028 #include <sys/types.h>
00029 #include <netinet/tcp.h>
00030 #include <netinet/in.h>
00031 #include <sys/poll.h>
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034 #include <netdb.h>
00035 #include <algorithm>
00036 #include <cstdlib>
00037 #include <cassert>
00038 #include <cstdio>
00039 #include <fcntl.h>
00040 
00041 using namespace std;
00042 
00043 namespace drizzle_plugin
00044 {
00045 
00046 Vio::Vio(int nsd) :
00047   closed(false),
00048   sd(nsd),
00049   fcntl_mode(0),
00050   local(),
00051   remote(),
00052   read_pos(NULL),
00053   read_end(NULL)
00054 {
00055   /*
00056     We call fcntl() to set the flags and then immediately read them back
00057     to make sure that we and the system are in agreement on the state of
00058     things.
00059 
00060     An example of why we need to do this is FreeBSD (and apparently some
00061     other BSD-derived systems, like Mac OS X), where the system sometimes
00062     reports that the socket is set for non-blocking when it really will
00063     block.
00064   */
00065   fcntl(sd, F_SETFL, 0);
00066   fcntl_mode= fcntl(sd, F_GETFL);
00067 }
00068 
00069 Vio::~Vio()
00070 {
00071  if (!closed)
00072     close();
00073 }
00074 
00075 int Vio::close()
00076 {
00077   int r=0;
00078   if (!closed)
00079   {
00080     assert(sd >= 0);
00081     if (shutdown(sd, SHUT_RDWR))
00082       r= -1;
00083     if (::close(sd))
00084       r= -1;
00085   }
00086   closed= true;
00087   sd=   -1;
00088 
00089   return r;
00090 }
00091 
00092 size_t Vio::read(unsigned char* buf, size_t size)
00093 {
00094   size_t r;
00095 
00096   /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
00097   assert(read_end == read_pos);
00098   r= ::read(sd, buf, size);
00099 
00100   return r;
00101 }
00102 
00103 size_t Vio::write(const unsigned char* buf, size_t size)
00104 {
00105   size_t r;
00106 
00107   r = ::write(sd, buf, size);
00108 
00109   return r;
00110 }
00111 
00112 int Vio::blocking(bool set_blocking_mode, bool *old_mode)
00113 {
00114   int r=0;
00115 
00116   // make sure ptr is not NULL:
00117   if (NULL != old_mode)
00118     *old_mode= drizzled::test(!(fcntl_mode & O_NONBLOCK));
00119 
00120   if (sd >= 0)
00121   {
00122     int old_fcntl=fcntl_mode;
00123     if (set_blocking_mode)
00124       fcntl_mode &= ~O_NONBLOCK; /* clear bit */
00125     else
00126       fcntl_mode |= O_NONBLOCK; /* set bit */
00127     if (old_fcntl != fcntl_mode)
00128     {
00129       r= fcntl(sd, F_SETFL, fcntl_mode);
00130       if (r == -1)
00131       {
00132         fcntl_mode= old_fcntl;
00133       }
00134     }
00135   }
00136 
00137   return r;
00138 }
00139 
00140 int Vio::fastsend()
00141 {
00142   int nodelay = 1;
00143   int error;
00144 
00145   error= setsockopt(sd, IPPROTO_TCP, TCP_NODELAY,
00146                     &nodelay, sizeof(nodelay));
00147   if (error != 0)
00148   {
00149     perror("setsockopt");
00150   }
00151 
00152   return error;
00153 }
00154 
00155 int32_t Vio::keepalive(bool set_keep_alive)
00156 {
00157   int r= 0;
00158   uint32_t opt= 0;
00159 
00160   if (set_keep_alive)
00161     opt= 1;
00162 
00163   r= setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt));
00164   if (r != 0)
00165   {
00166     perror("setsockopt");
00167     assert(r == 0);
00168   }
00169 
00170   return r;
00171 }
00172 
00173 bool Vio::should_retry() const
00174 {
00175   int en = errno;
00176   return (en == EAGAIN || en == EINTR ||
00177           en == EWOULDBLOCK);
00178 }
00179 
00180 bool Vio::was_interrupted() const
00181 {
00182   int en= errno;
00183   return (en == EAGAIN || en == EINTR ||
00184           en == EWOULDBLOCK || en == ETIMEDOUT);
00185 }
00186 
00187 bool Vio::peer_addr(char *buf, uint16_t *port, size_t buflen) const
00188 {
00189   int error;
00190   char port_buf[NI_MAXSERV];
00191   socklen_t al = sizeof(remote);
00192 
00193   if (getpeername(sd, (struct sockaddr *) (&remote),
00194                   &al) != 0)
00195   {
00196     return true;
00197   }
00198 
00199   if ((error= getnameinfo((struct sockaddr *)(&remote),
00200                           al,
00201                           buf, buflen,
00202                           port_buf, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV)))
00203   {
00204     return true;
00205   }
00206 
00207   *port= (uint16_t)strtol(port_buf, (char **)NULL, 10);
00208 
00209   return false;
00210 }
00211 
00212 void Vio::timeout(bool is_sndtimeo, int32_t t)
00213 {
00214   int error;
00215 
00216   /* POSIX specifies time as struct timeval. */
00217   struct timeval wait_timeout;
00218   wait_timeout.tv_sec= t;
00219   wait_timeout.tv_usec= 0;
00220 
00221   assert(t >= 0 && t <= INT32_MAX);
00222   assert(sd != -1);
00223   error= setsockopt(sd, SOL_SOCKET, is_sndtimeo ? SO_SNDTIMEO : SO_RCVTIMEO,
00224                     &wait_timeout,
00225                     (socklen_t)sizeof(struct timeval));
00226   if (error == -1 && errno != ENOPROTOOPT)
00227   {
00228     perror("setsockopt");
00229     assert(error == 0);
00230   }
00231 }
00232 
00233 int Vio::get_errno() const
00234 {
00235   return errno;
00236 }
00237 
00238 int Vio::get_fd() const
00239 {
00240   return sd;
00241 }
00242 
00243 
00244 char *Vio::get_read_pos() const
00245 {
00246   return read_pos;
00247 }
00248 
00249 char *Vio::get_read_end() const
00250 {
00251   return read_end;
00252 }
00253 
00254 } /* namespace drizzle_plugin */