MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
socket_io.cpp
1 /*
2  Copyright (c) 2003, 2010, 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; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <ndb_global.h>
19 
20 #include <portlib/NdbTCP.h>
21 #include <portlib/NdbTick.h>
22 #include <util/socket_io.h>
23 #include <util/BaseString.hpp>
24 
25 static inline
26 int
27 poll_socket(ndb_socket_t socket, bool read, bool write,
28  int timeout_millis, int* total_elapsed_millis)
29 {
30  const NDB_TICKS start = NdbTick_CurrentMillisecond();
31 
32  timeout_millis -= *total_elapsed_millis;
33 
34  if (timeout_millis <= 0)
35  return 0; // Timeout occured
36 
37  const int res =
38  ndb_poll(socket, read, write, false, timeout_millis);
39 
40  // Calculate elapsed time in this function
41  const int elapsed_millis = (int)(NdbTick_CurrentMillisecond() - start);
42  assert(elapsed_millis >= 0);
43 
44  // Update the total elapsed time
45  *total_elapsed_millis += elapsed_millis;
46 
47  return res;
48 }
49 
50 
51 extern "C"
52 int
53 read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
54  char * buf, int buflen){
55  if(buflen < 1)
56  return 0;
57 
58  int elapsed_millis = 0;
59  const int res = poll_socket(socket, true, false,
60  timeout_millis, &elapsed_millis);
61  if (res <= 0)
62  return res;
63 
64  return (int)my_recv(socket, &buf[0], buflen, 0);
65 }
66 
67 extern "C"
68 int
69 readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
70  char * buf, int buflen, NdbMutex *mutex){
71  if(buflen <= 1)
72  return 0;
73 
74  if(mutex)
75  NdbMutex_Unlock(mutex);
76 
77  const int res = poll_socket(socket, true, false,
78  timeout_millis, time);
79 
80  if(mutex)
81  NdbMutex_Lock(mutex);
82 
83  if (res <= 0)
84  return res;
85 
86  char* ptr = buf;
87  int len = buflen;
88  do
89  {
90  int t;
91  while((t = (int)my_recv(socket, ptr, len, MSG_PEEK)) == -1
92  && socket_errno == EINTR);
93 
94  if(t < 1)
95  {
96  return -1;
97  }
98 
99 
100  for(int i = 0; i<t; i++)
101  {
102  if(ptr[i] == '\n')
103  {
107  for (len = 1 + i; len; )
108  {
109  while ((t = (int)my_recv(socket, ptr, len, 0)) == -1
110  && socket_errno == EINTR);
111  if (t < 1)
112  return -1;
113  ptr += t;
114  len -= t;
115  }
116  if (t > 1 && ptr[-2] == '\r')
117  {
118  ptr[-2] = '\n';
119  ptr[-1] = '\0';
120  ptr--;
121  }
122 
123  *time = 0;
124 
125  ptr[0]= 0;
126  return ptr - buf;
127  }
128  }
129 
130  for (int tmp = t; tmp; )
131  {
132  while ((t = (int)my_recv(socket, ptr, tmp, 0)) == -1 && socket_errno == EINTR);
133  if (t < 1)
134  {
135  return -1;
136  }
137  ptr += t;
138  len -= t;
139  tmp -= t;
140  if (t > 0 && buf[t-1] == '\r')
141  {
142  buf[t-1] = '\n';
143  ptr--;
144  }
145  }
146 
147  if (poll_socket(socket, true, false, timeout_millis, time) != 1)
148  {
149  // Read some bytes but didn't find newline before all time was
150  // used up => return error
151  return -1;
152  }
153 
154  } while (len > 0);
155 
156  return -1;
157 }
158 
159 extern "C"
160 int
161 write_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
162  const char buf[], int len){
163 
164  if (poll_socket(socket, false, true, timeout_millis, time) != 1)
165  return -1;
166 
167  const char * tmp = &buf[0];
168  while(len > 0){
169  const int w = (int)my_send(socket, tmp, len, 0);
170  if(w == -1){
171  return -1;
172  }
173  len -= w;
174  tmp += w;
175 
176  if(len == 0)
177  break;
178 
179  if (poll_socket(socket, false, true, timeout_millis, time) != 1)
180  return -1;
181  }
182 
183  return 0;
184 }
185 
186 extern "C"
187 int
188 print_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
189  const char * fmt, ...){
190  va_list ap;
191  va_start(ap, fmt);
192  int ret = vprint_socket(socket, timeout_millis, time, fmt, ap);
193  va_end(ap);
194 
195  return ret;
196 }
197 
198 extern "C"
199 int
200 println_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
201  const char * fmt, ...){
202  va_list ap;
203  va_start(ap, fmt);
204  int ret = vprintln_socket(socket, timeout_millis, time, fmt, ap);
205  va_end(ap);
206  return ret;
207 }
208 
209 extern "C"
210 int
211 vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
212  const char * fmt, va_list ap){
213  char buf[1000];
214  char *buf2 = buf;
215  size_t size;
216 
217  if (fmt != 0 && fmt[0] != 0) {
218  size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap);
219  /* Check if the output was truncated */
220  if(size > sizeof(buf)) {
221  buf2 = (char *)malloc(size);
222  if(buf2 == NULL)
223  return -1;
224  BaseString::vsnprintf(buf2, size, fmt, ap);
225  }
226  } else
227  return 0;
228 
229  int ret = write_socket(socket, timeout_millis, time, buf2, size);
230  if(buf2 != buf)
231  free(buf2);
232  return ret;
233 }
234 
235 extern "C"
236 int
237 vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, int *time,
238  const char * fmt, va_list ap){
239  char buf[1000];
240  char *buf2 = buf;
241  size_t size;
242 
243  if (fmt != 0 && fmt[0] != 0) {
244  size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap)+1;// extra byte for '/n'
245  /* Check if the output was truncated */
246  if(size > sizeof(buf)) {
247  buf2 = (char *)malloc(size);
248  if(buf2 == NULL)
249  return -1;
250  BaseString::vsnprintf(buf2, size, fmt, ap);
251  }
252  } else {
253  size = 1;
254  }
255  buf2[size-1]='\n';
256 
257  int ret = write_socket(socket, timeout_millis, time, buf2, size);
258  if(buf2 != buf)
259  free(buf2);
260  return ret;
261 }
262 
263 #ifdef NDB_WIN32
264 
265 class INIT_WINSOCK2
266 {
267 public:
268  INIT_WINSOCK2(void);
269  ~INIT_WINSOCK2(void);
270 
271 private:
272  bool m_bAcceptable;
273 };
274 
275 INIT_WINSOCK2 g_init_winsock2;
276 
277 INIT_WINSOCK2::INIT_WINSOCK2(void)
278 : m_bAcceptable(false)
279 {
280  WORD wVersionRequested;
281  WSADATA wsaData;
282  int err;
283 
284  wVersionRequested = MAKEWORD( 2, 2 );
285 
286  err = WSAStartup( wVersionRequested, &wsaData );
287  if ( err != 0 ) {
288  /* Tell the user that we could not find a usable */
289  /* WinSock DLL. */
290  m_bAcceptable = false;
291  }
292 
293  /* Confirm that the WinSock DLL supports 2.2.*/
294  /* Note that if the DLL supports versions greater */
295  /* than 2.2 in addition to 2.2, it will still return */
296  /* 2.2 in wVersion since that is the version we */
297  /* requested. */
298 
299  if ( LOBYTE( wsaData.wVersion ) != 2 ||
300  HIBYTE( wsaData.wVersion ) != 2 ) {
301  /* Tell the user that we could not find a usable */
302  /* WinSock DLL. */
303  WSACleanup( );
304  m_bAcceptable = false;
305  }
306 
307  /* The WinSock DLL is acceptable. Proceed. */
308  m_bAcceptable = true;
309 }
310 
311 INIT_WINSOCK2::~INIT_WINSOCK2(void)
312 {
313  if(m_bAcceptable)
314  {
315  m_bAcceptable = false;
316  WSACleanup();
317  }
318 }
319 
320 #endif
321