~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/vio.cc

  • Committer: Brian Aker
  • Date: 2010-03-15 21:50:05 UTC
  • mto: This revision was merged to the branch mainline in revision 1343.
  • Revision ID: brian@gaz-20100315215005-oqoblpbll9n0albj
Merge of table cache/def DD.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Note that we can't have assertion on file descriptors;  The reason for
19
19
  we are working on.  In this case we should just return read errors from
20
20
  the file descriptior.
21
21
*/
 
22
 
 
23
#define DONT_MAP_VIO
22
24
#include "config.h"
23
25
#include "vio.h"
24
26
#include <string.h>
25
 
#include <drizzled/util/test.h>
26
 
#include <sys/socket.h>
27
 
#include <string.h>
28
 
#include <sys/types.h>
29
 
#include <netinet/tcp.h>
30
 
#include <netinet/in.h>
31
 
#include <sys/poll.h>
32
 
#include <unistd.h>
33
 
#include <fcntl.h>
34
 
#include <netdb.h>
35
 
#include <algorithm>
 
27
 
36
28
#include <cstdlib>
37
29
#include <cassert>
38
30
#include <cstdio>
39
31
#include <fcntl.h>
40
32
 
41
 
using namespace std;
42
 
 
43
 
namespace drizzle_plugin
44
 
{
45
 
 
46
 
Vio::Vio(int nsd) :
47
 
  closed(false),
48
 
  sd(nsd),
49
 
  fcntl_mode(0),
50
 
  local(),
51
 
  remote(),
52
 
  read_pos(NULL),
53
 
  read_end(NULL)
54
 
{
55
 
  /*
56
 
    We call fcntl() to set the flags and then immediately read them back
57
 
    to make sure that we and the system are in agreement on the state of
58
 
    things.
59
 
 
60
 
    An example of why we need to do this is FreeBSD (and apparently some
61
 
    other BSD-derived systems, like Mac OS X), where the system sometimes
62
 
    reports that the socket is set for non-blocking when it really will
63
 
    block.
64
 
  */
65
 
  fcntl(sd, F_SETFL, 0);
66
 
  fcntl_mode= fcntl(sd, F_GETFL);
67
 
}
68
 
 
69
 
Vio::~Vio()
70
 
{
71
 
 if (!closed)
72
 
    close();
73
 
}
74
 
 
75
 
int Vio::close()
76
 
{
77
 
  int r=0;
78
 
  if (!closed)
79
 
  {
80
 
    assert(sd >= 0);
81
 
    if (shutdown(sd, SHUT_RDWR))
82
 
      r= -1;
83
 
    if (::close(sd))
84
 
      r= -1;
85
 
  }
86
 
  closed= true;
87
 
  sd=   -1;
88
 
 
89
 
  return r;
90
 
}
91
 
 
92
 
size_t Vio::read(unsigned char* buf, size_t size)
93
 
{
94
 
  size_t r;
95
 
 
96
 
  /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
97
 
  assert(read_end == read_pos);
98
 
  r= ::read(sd, buf, size);
99
 
 
100
 
  return r;
101
 
}
102
 
 
103
 
size_t Vio::write(const unsigned char* buf, size_t size)
104
 
{
105
 
  size_t r;
106
 
 
107
 
  r = ::write(sd, buf, size);
108
 
 
109
 
  return r;
110
 
}
111
 
 
112
 
int Vio::blocking(bool set_blocking_mode, bool *old_mode)
113
 
{
114
 
  int r=0;
115
 
 
116
 
  // make sure ptr is not NULL:
117
 
  if (NULL != old_mode)
118
 
    *old_mode= drizzled::test(!(fcntl_mode & O_NONBLOCK));
119
 
 
120
 
  if (sd >= 0)
121
 
  {
122
 
    int old_fcntl=fcntl_mode;
123
 
    if (set_blocking_mode)
124
 
      fcntl_mode &= ~O_NONBLOCK; /* clear bit */
125
 
    else
126
 
      fcntl_mode |= O_NONBLOCK; /* set bit */
127
 
    if (old_fcntl != fcntl_mode)
128
 
    {
129
 
      r= fcntl(sd, F_SETFL, fcntl_mode);
130
 
      if (r == -1)
131
 
      {
132
 
        fcntl_mode= old_fcntl;
133
 
      }
134
 
    }
135
 
  }
136
 
 
137
 
  return r;
138
 
}
139
 
 
140
 
int Vio::fastsend()
141
 
{
142
 
  int nodelay = 1;
143
 
  int error;
144
 
 
145
 
  error= setsockopt(sd, IPPROTO_TCP, TCP_NODELAY,
146
 
                    &nodelay, sizeof(nodelay));
147
 
  if (error != 0)
148
 
  {
149
 
    perror("setsockopt");
150
 
  }
151
 
 
152
 
  return error;
153
 
}
154
 
 
155
 
int32_t Vio::keepalive(bool set_keep_alive)
156
 
{
157
 
  int r= 0;
158
 
  uint32_t opt= 0;
159
 
 
160
 
  if (set_keep_alive)
161
 
    opt= 1;
162
 
 
163
 
  r= setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt));
164
 
  if (r != 0)
165
 
  {
166
 
    perror("setsockopt");
167
 
    assert(r == 0);
168
 
  }
169
 
 
170
 
  return r;
171
 
}
172
 
 
173
 
bool Vio::should_retry() const
174
 
{
175
 
  int en = errno;
176
 
  return (en == EAGAIN || en == EINTR ||
177
 
          en == EWOULDBLOCK);
178
 
}
179
 
 
180
 
bool Vio::was_interrupted() const
181
 
{
182
 
  int en= errno;
183
 
  return (en == EAGAIN || en == EINTR ||
184
 
          en == EWOULDBLOCK || en == ETIMEDOUT);
185
 
}
186
 
 
187
 
bool Vio::peer_addr(char *buf, uint16_t *port, size_t buflen) const
188
 
{
189
 
  int error;
190
 
  char port_buf[NI_MAXSERV];
191
 
  socklen_t al = sizeof(remote);
192
 
 
193
 
  if (getpeername(sd, (struct sockaddr *) (&remote),
194
 
                  &al) != 0)
195
 
  {
196
 
    return true;
197
 
  }
198
 
 
199
 
  if ((error= getnameinfo((struct sockaddr *)(&remote),
200
 
                          al,
201
 
                          buf, buflen,
202
 
                          port_buf, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV)))
203
 
  {
204
 
    return true;
205
 
  }
206
 
 
207
 
  *port= (uint16_t)strtol(port_buf, (char **)NULL, 10);
208
 
 
209
 
  return false;
210
 
}
211
 
 
212
 
void Vio::timeout(bool is_sndtimeo, int32_t t)
213
 
{
214
 
  int error;
215
 
 
216
 
  /* POSIX specifies time as struct timeval. */
217
 
  struct timeval wait_timeout;
218
 
  wait_timeout.tv_sec= t;
219
 
  wait_timeout.tv_usec= 0;
220
 
 
221
 
  assert(t >= 0 && t <= INT32_MAX);
222
 
  assert(sd != -1);
223
 
  error= setsockopt(sd, SOL_SOCKET, is_sndtimeo ? SO_SNDTIMEO : SO_RCVTIMEO,
224
 
                    &wait_timeout,
225
 
                    (socklen_t)sizeof(struct timeval));
226
 
  if (error == -1 && errno != ENOPROTOOPT)
227
 
  {
228
 
    perror("setsockopt");
229
 
    assert(error == 0);
230
 
  }
231
 
}
232
 
 
233
 
int Vio::get_errno() const
234
 
{
235
 
  return errno;
236
 
}
237
 
 
238
 
int Vio::get_fd() const
239
 
{
240
 
  return sd;
241
 
}
242
 
 
243
 
 
244
 
char *Vio::get_read_pos() const
245
 
{
246
 
  return read_pos;
247
 
}
248
 
 
249
 
char *Vio::get_read_end() const
250
 
{
251
 
  return read_end;
252
 
}
253
 
 
254
 
} /* namespace drizzle_plugin */
 
33
/*
 
34
 * Helper to fill most of the Vio* with defaults.
 
35
 */
 
36
 
 
37
static void drizzleclient_vio_init(Vio* vio, enum enum_vio_type type,
 
38
                     int sd, uint32_t flags)
 
39
{
 
40
  memset(vio, 0, sizeof(*vio));
 
41
  vio->type     = type;
 
42
  vio->sd       = sd;
 
43
  if ((flags & VIO_BUFFERED_READ) &&
 
44
      !(vio->read_buffer= (char*)malloc(VIO_READ_BUFFER_SIZE)))
 
45
    flags&= ~VIO_BUFFERED_READ;
 
46
  {
 
47
    vio->viodelete      =drizzleclient_vio_delete;
 
48
    vio->vioerrno       =drizzleclient_vio_errno;
 
49
    vio->read= (flags & VIO_BUFFERED_READ) ? drizzleclient_vio_read_buff : drizzleclient_vio_read;
 
50
    vio->write          =drizzleclient_vio_write;
 
51
    vio->fastsend       =drizzleclient_vio_fastsend;
 
52
    vio->viokeepalive   =drizzleclient_vio_keepalive;
 
53
    vio->should_retry   =drizzleclient_vio_should_retry;
 
54
    vio->was_interrupted=drizzleclient_vio_was_interrupted;
 
55
    vio->vioclose       =drizzleclient_vio_close;
 
56
    vio->peer_addr      =drizzleclient_vio_peer_addr;
 
57
    vio->vioblocking    =drizzleclient_vio_blocking;
 
58
    vio->is_blocking    =drizzleclient_vio_is_blocking;
 
59
    vio->timeout        =drizzleclient_vio_timeout;
 
60
  }
 
61
}
 
62
 
 
63
 
 
64
/* Reset initialized VIO to use with another transport type */
 
65
 
 
66
void drizzleclient_vio_reset(Vio* vio, enum enum_vio_type type,
 
67
               int sd, uint32_t flags)
 
68
{
 
69
  free(vio->read_buffer);
 
70
  drizzleclient_vio_init(vio, type, sd, flags);
 
71
}
 
72
 
 
73
 
 
74
/* Open the socket or TCP/IP connection and read the fnctl() status */
 
75
 
 
76
Vio *drizzleclient_vio_new(int sd, enum enum_vio_type type, uint32_t flags)
 
77
{
 
78
  Vio *vio = (Vio*) malloc(sizeof(Vio));
 
79
 
 
80
  if (vio != NULL)
 
81
  {
 
82
    drizzleclient_vio_init(vio, type, sd, flags);
 
83
    sprintf(vio->desc, "TCP/IP (%d)", vio->sd);
 
84
    /*
 
85
      We call fcntl() to set the flags and then immediately read them back
 
86
      to make sure that we and the system are in agreement on the state of
 
87
      things.
 
88
 
 
89
      An example of why we need to do this is FreeBSD (and apparently some
 
90
      other BSD-derived systems, like Mac OS X), where the system sometimes
 
91
      reports that the socket is set for non-blocking when it really will
 
92
      block.
 
93
    */
 
94
    fcntl(sd, F_SETFL, 0);
 
95
    vio->fcntl_mode= fcntl(sd, F_GETFL);
 
96
  }
 
97
  return vio;
 
98
}
 
99
 
 
100
 
 
101
void drizzleclient_vio_delete(Vio* vio)
 
102
{
 
103
  if (!vio)
 
104
    return; /* It must be safe to delete null pointers. */
 
105
 
 
106
  if (vio->type != VIO_CLOSED)
 
107
    vio->vioclose(vio);
 
108
  free((unsigned char*) vio->read_buffer);
 
109
  free((unsigned char*) vio);
 
110
}
 
111
 
 
112
 
 
113
/*
 
114
  Cleanup memory allocated by vio or the
 
115
  components below it when application finish
 
116
 
 
117
*/
 
118
void drizzleclient_vio_end(void)
 
119
{
 
120
}