MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
socket_wrapper.cpp
1 /*
2  Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to the
15  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
16  MA 02110-1301 USA.
17 */
18 
19 
20 /* The socket wrapper source implements a Socket class that hides the
21  * differences between Berkely style sockets and Windows sockets, allowing
22  * transparent TCP access.
23  */
24 
25 
26 #include "runtime.hpp"
27 #include "socket_wrapper.hpp"
28 
29 #ifndef _WIN32
30  #include <errno.h>
31  #include <netdb.h>
32  #include <unistd.h>
33  #include <arpa/inet.h>
34  #include <netinet/in.h>
35  #include <sys/ioctl.h>
36  #include <string.h>
37  #include <fcntl.h>
38 #endif // _WIN32
39 
40 #if defined(__sun) || defined(__SCO_VERSION__)
41  #include <sys/filio.h>
42 #endif
43 
44 #ifdef _WIN32
45  const int SOCKET_EINVAL = WSAEINVAL;
46  const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK;
47  const int SOCKET_EAGAIN = WSAEWOULDBLOCK;
48 #else
49  const int SOCKET_EINVAL = EINVAL;
50  const int SOCKET_EWOULDBLOCK = EWOULDBLOCK;
51  const int SOCKET_EAGAIN = EAGAIN;
52 #endif // _WIN32
53 
54 
55 namespace {
56 
57 
58 extern "C" long system_recv(void *ptr, void *buf, size_t count)
59 {
60  yaSSL::socket_t *socket = (yaSSL::socket_t *) ptr;
61  return ::recv(*socket, reinterpret_cast<char *>(buf), count, 0);
62 }
63 
64 
65 extern "C" long system_send(void *ptr, const void *buf, size_t count)
66 {
67  yaSSL::socket_t *socket = (yaSSL::socket_t *) ptr;
68  return ::send(*socket, reinterpret_cast<const char *>(buf), count, 0);
69 }
70 
71 
72 }
73 
74 
75 namespace yaSSL {
76 
77 
78 Socket::Socket(socket_t s)
79  : socket_(s), wouldBlock_(false), nonBlocking_(false),
80  ptr_(&socket_), send_func_(system_send), recv_func_(system_recv)
81 {}
82 
83 
84 void Socket::set_fd(socket_t s)
85 {
86  socket_ = s;
87 }
88 
89 
90 socket_t Socket::get_fd() const
91 {
92  return socket_;
93 }
94 
95 
96 Socket::~Socket()
97 {
98  // don't close automatically now
99 }
100 
101 
102 void Socket::closeSocket()
103 {
104  if (socket_ != INVALID_SOCKET) {
105 #ifdef _WIN32
106  closesocket(socket_);
107 #else
108  close(socket_);
109 #endif
110  socket_ = INVALID_SOCKET;
111  }
112 }
113 
114 
115 uint Socket::get_ready() const
116 {
117 #ifdef _WIN32
118  unsigned long ready = 0;
119  ioctlsocket(socket_, FIONREAD, &ready);
120 #else
121  /*
122  64-bit Solaris requires the variable passed to
123  FIONREAD be a 32-bit value.
124  */
125  unsigned int ready = 0;
126  ioctl(socket_, FIONREAD, &ready);
127 #endif
128 
129  return ready;
130 }
131 
132 
133 void Socket::set_transport_ptr(void *ptr)
134 {
135  ptr_ = ptr;
136 }
137 
138 
139 void Socket::set_transport_recv_function(yaSSL_recv_func_t recv_func)
140 {
141  recv_func_ = recv_func;
142 }
143 
144 
145 void Socket::set_transport_send_function(yaSSL_send_func_t send_func)
146 {
147  send_func_ = send_func;
148 }
149 
150 
151 uint Socket::send(const byte* buf, unsigned int sz, unsigned int& written)
152 {
153  const byte* pos = buf;
154  const byte* end = pos + sz;
155 
156  wouldBlock_ = false;
157 
158  /* Remove send()/recv() hooks once non-blocking send is implemented. */
159  while (pos != end) {
160  int sent = send_func_(ptr_, pos, static_cast<int>(end - pos));
161  if (sent == -1) {
162  if (get_lastError() == SOCKET_EWOULDBLOCK ||
163  get_lastError() == SOCKET_EAGAIN) {
164  wouldBlock_ = true; // would have blocked this time only
165  nonBlocking_ = true; // nonblocking, win32 only way to tell
166  return 0;
167  }
168  return static_cast<uint>(-1);
169  }
170  pos += sent;
171  written += sent;
172  }
173 
174  return sz;
175 }
176 
177 
178 uint Socket::receive(byte* buf, unsigned int sz)
179 {
180  wouldBlock_ = false;
181 
182  int recvd = recv_func_(ptr_, buf, sz);
183 
184  // idea to seperate error from would block by arnetheduck@gmail.com
185  if (recvd == -1) {
186  if (get_lastError() == SOCKET_EWOULDBLOCK ||
187  get_lastError() == SOCKET_EAGAIN) {
188  wouldBlock_ = true; // would have blocked this time only
189  nonBlocking_ = true; // socket nonblocking, win32 only way to tell
190  return 0;
191  }
192  }
193  else if (recvd == 0)
194  return static_cast<uint>(-1);
195 
196  return recvd;
197 }
198 
199 
200 void Socket::shutDown(int how)
201 {
202  shutdown(socket_, how);
203 }
204 
205 
206 int Socket::get_lastError()
207 {
208 #ifdef _WIN32
209  return WSAGetLastError();
210 #else
211  return errno;
212 #endif
213 }
214 
215 
216 bool Socket::WouldBlock() const
217 {
218  return wouldBlock_;
219 }
220 
221 
222 bool Socket::IsNonBlocking() const
223 {
224  return nonBlocking_;
225 }
226 
227 
228 void Socket::set_lastError(int errorCode)
229 {
230 #ifdef _WIN32
231  WSASetLastError(errorCode);
232 #else
233  errno = errorCode;
234 #endif
235 }
236 
237 
238 } // namespace