~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/vio.cc

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
/*
17
 
  Note that we can't have assertion on file descriptors;  The reason for
18
 
  this is that during mysql shutdown, another thread can close a file
19
 
  we are working on.  In this case we should just return read errors from
20
 
  the file descriptior.
21
 
*/
22
 
 
23
 
#include "config.h"
24
 
#include "vio.h"
25
 
#include <string.h>
26
 
#include <drizzled/util/test.h>
27
 
#include <sys/socket.h>
28
 
#include <string.h>
29
 
#include <sys/types.h>
30
 
#include <netinet/tcp.h>
31
 
#include <netinet/in.h>
32
 
#include <sys/poll.h>
33
 
#include <unistd.h>
34
 
#include <fcntl.h>
35
 
#include <netdb.h>
36
 
#include <algorithm>
37
 
#include <cstdlib>
38
 
#include <cassert>
39
 
#include <cstdio>
40
 
#include <fcntl.h>
41
 
 
42
 
using namespace std;
43
 
 
44
 
static void _vio_delete(Vio* vio)
45
 
{
46
 
  if (!vio)
47
 
    return; /* It must be safe to delete null pointers. */
48
 
 
49
 
  if (!vio->closed)
50
 
    vio->vioclose(vio);
51
 
  free((unsigned char*) vio);
52
 
}
53
 
 
54
 
static int _vio_errno(Vio *vio)
55
 
{
56
 
  (void)vio;
57
 
  return errno;
58
 
}
59
 
 
60
 
static size_t _vio_read(Vio * vio, unsigned char* buf, size_t size)
61
 
{
62
 
  size_t r;
63
 
 
64
 
  /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
65
 
  assert(vio->read_end == vio->read_pos);
66
 
  r= read(vio->sd, buf, size);
67
 
 
68
 
  return r;
69
 
}
70
 
 
71
 
static size_t _vio_write(Vio * vio, const unsigned char* buf, size_t size)
72
 
{
73
 
  size_t r;
74
 
 
75
 
  r = write(vio->sd, buf, size);
76
 
 
77
 
  return r;
78
 
}
79
 
 
80
 
static int _vio_blocking(Vio * vio, bool set_blocking_mode, bool *old_mode)
81
 
{
82
 
  int r=0;
83
 
 
84
 
  *old_mode= drizzled::test(!(vio->fcntl_mode & O_NONBLOCK));
85
 
 
86
 
  if (vio->sd >= 0)
87
 
  {
88
 
    int old_fcntl=vio->fcntl_mode;
89
 
    if (set_blocking_mode)
90
 
      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
91
 
    else
92
 
      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
93
 
    if (old_fcntl != vio->fcntl_mode)
94
 
    {
95
 
      r= fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
96
 
      if (r == -1)
97
 
      {
98
 
        vio->fcntl_mode= old_fcntl;
99
 
      }
100
 
    }
101
 
  }
102
 
 
103
 
  return r;
104
 
}
105
 
 
106
 
static int _vio_fastsend(Vio * vio)
107
 
{
108
 
  (void)vio;
109
 
  int nodelay = 1;
110
 
  int error;
111
 
 
112
 
  error= setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY,
113
 
                    &nodelay, sizeof(nodelay));
114
 
  if (error != 0)
115
 
  {
116
 
    perror("setsockopt");
117
 
    assert(error == 0);
118
 
  }
119
 
 
120
 
  return error;
121
 
}
122
 
 
123
 
static int32_t _vio_keepalive(Vio* vio, bool set_keep_alive)
124
 
{
125
 
  int r= 0;
126
 
  uint32_t opt= 0;
127
 
 
128
 
  if (set_keep_alive)
129
 
    opt= 1;
130
 
 
131
 
  r= setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt));
132
 
  if (r != 0)
133
 
  {
134
 
    perror("setsockopt");
135
 
    assert(r == 0);
136
 
  }
137
 
 
138
 
  return r;
139
 
}
140
 
 
141
 
static bool _vio_should_retry(Vio * vio)
142
 
{
143
 
  (void)vio;
144
 
  int en = errno;
145
 
  return (en == EAGAIN || en == EINTR ||
146
 
          en == EWOULDBLOCK);
147
 
}
148
 
 
149
 
static bool _vio_was_interrupted(Vio *vio)
150
 
{
151
 
  (void)vio;
152
 
  int en= errno;
153
 
  return (en == EAGAIN || en == EINTR ||
154
 
          en == EWOULDBLOCK || en == ETIMEDOUT);
155
 
}
156
 
 
157
 
static int _vio_close(Vio * vio)
158
 
{
159
 
  int r=0;
160
 
 if (!vio->closed)
161
 
  {
162
 
    assert(vio->sd >= 0);
163
 
    if (shutdown(vio->sd, SHUT_RDWR))
164
 
      r= -1;
165
 
    if (close(vio->sd))
166
 
      r= -1;
167
 
  }
168
 
  vio->closed= true;
169
 
  vio->sd=   -1;
170
 
 
171
 
  return r;
172
 
}
173
 
 
174
 
static bool _vio_peer_addr(Vio *vio, char *buf, uint16_t *port, size_t buflen)
175
 
{
176
 
  int error;
177
 
  char port_buf[NI_MAXSERV];
178
 
  socklen_t addrLen = sizeof(vio->remote);
179
 
 
180
 
  if (getpeername(vio->sd, (struct sockaddr *) (&vio->remote),
181
 
                  &addrLen) != 0)
182
 
  {
183
 
    return true;
184
 
  }
185
 
  vio->addrLen= (int)addrLen;
186
 
 
187
 
  if ((error= getnameinfo((struct sockaddr *)(&vio->remote),
188
 
                          addrLen,
189
 
                          buf, buflen,
190
 
                          port_buf, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV)))
191
 
  {
192
 
    return true;
193
 
  }
194
 
 
195
 
  *port= (uint16_t)strtol(port_buf, (char **)NULL, 10);
196
 
 
197
 
  return false;
198
 
}
199
 
 
200
 
static void _vio_timeout(Vio *vio, bool is_sndtimeo, int32_t timeout)
201
 
{
202
 
  int error;
203
 
 
204
 
  /* POSIX specifies time as struct timeval. */
205
 
  struct timeval wait_timeout;
206
 
  wait_timeout.tv_sec= timeout;
207
 
  wait_timeout.tv_usec= 0;
208
 
 
209
 
  assert(timeout >= 0 && timeout <= INT32_MAX);
210
 
  assert(vio->sd != -1);
211
 
  error= setsockopt(vio->sd, SOL_SOCKET, is_sndtimeo ? SO_SNDTIMEO : SO_RCVTIMEO,
212
 
                    &wait_timeout,
213
 
                    (socklen_t)sizeof(struct timeval));
214
 
  if (error == -1 && errno != ENOPROTOOPT)
215
 
  {
216
 
    perror("setsockopt");
217
 
    assert(error == 0);
218
 
  }
219
 
}
220
 
 
221
 
/* Open the socket or TCP/IP connection and read the fnctl() status */
222
 
Vio *mysql_protocol_vio_new(int sd)
223
 
{
224
 
  Vio *vio = (Vio*) malloc(sizeof(Vio));
225
 
  if (vio == NULL)
226
 
    return NULL;
227
 
 
228
 
  memset(vio, 0, sizeof(*vio));
229
 
  vio->closed= false;
230
 
  vio->sd= sd;
231
 
  vio->viodelete= _vio_delete;
232
 
  vio->vioerrno= _vio_errno;
233
 
  vio->read= _vio_read;
234
 
  vio->write= _vio_write;
235
 
  vio->fastsend= _vio_fastsend;
236
 
  vio->viokeepalive= _vio_keepalive;
237
 
  vio->should_retry= _vio_should_retry;
238
 
  vio->was_interrupted= _vio_was_interrupted;
239
 
  vio->vioclose= _vio_close;
240
 
  vio->peer_addr= _vio_peer_addr;
241
 
  vio->vioblocking= _vio_blocking;
242
 
  vio->timeout= _vio_timeout;
243
 
 
244
 
  /*
245
 
    We call fcntl() to set the flags and then immediately read them back
246
 
    to make sure that we and the system are in agreement on the state of
247
 
    things.
248
 
 
249
 
    An example of why we need to do this is FreeBSD (and apparently some
250
 
    other BSD-derived systems, like Mac OS X), where the system sometimes
251
 
    reports that the socket is set for non-blocking when it really will
252
 
    block.
253
 
  */
254
 
  fcntl(sd, F_SETFL, 0);
255
 
  vio->fcntl_mode= fcntl(sd, F_GETFL);
256
 
 
257
 
  return vio;
258
 
}