MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SocketClient.cpp
1 /*
2  Copyright (c) 2004, 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 
19 #include <ndb_global.h>
20 
21 #include <SocketClient.hpp>
22 #include <SocketAuthenticator.hpp>
23 
24 SocketClient::SocketClient(const char *server_name, unsigned short port, SocketAuthenticator *sa) :
25  m_connect_timeout_millisec(0) // Blocking connect by default
26 {
27  m_auth= sa;
28  m_port= port;
29  m_server_name= server_name ? strdup(server_name) : 0;
30  my_socket_invalidate(&m_sockfd);
31 }
32 
33 SocketClient::~SocketClient()
34 {
35  if (m_server_name)
36  free(m_server_name);
37  if (my_socket_valid(m_sockfd))
38  NDB_CLOSE_SOCKET(m_sockfd);
39  if (m_auth)
40  delete m_auth;
41 }
42 
43 bool
44 SocketClient::init()
45 {
46  if (my_socket_valid(m_sockfd))
47  NDB_CLOSE_SOCKET(m_sockfd);
48 
49  if (m_server_name)
50  {
51  memset(&m_servaddr, 0, sizeof(m_servaddr));
52  m_servaddr.sin_family = AF_INET;
53  m_servaddr.sin_port = htons(m_port);
54  // Convert ip address presentation format to numeric format
55  if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name))
56  return false;
57  }
58 
59  m_sockfd= my_socket_create(AF_INET, SOCK_STREAM, 0);
60  if (!my_socket_valid(m_sockfd)) {
61  return false;
62  }
63 
64  DBUG_PRINT("info",("NDB_SOCKET: " MY_SOCKET_FORMAT, MY_SOCKET_FORMAT_VALUE(m_sockfd)));
65 
66  return true;
67 }
68 
69 int
70 SocketClient::bind(const char* bindaddress, unsigned short localport)
71 {
72  if (!my_socket_valid(m_sockfd))
73  return -1;
74 
75  struct sockaddr_in local;
76  memset(&local, 0, sizeof(local));
77  local.sin_family = AF_INET;
78  local.sin_port = htons(localport);
79  // Convert ip address presentation format to numeric format
80  if (Ndb_getInAddr(&local.sin_addr, bindaddress))
81  {
82  return errno ? errno : EINVAL;
83  }
84 
85  if (my_socket_reuseaddr(m_sockfd, true) == -1)
86  {
87  int ret = my_socket_errno();
88  my_socket_close(m_sockfd);
89  my_socket_invalidate(&m_sockfd);
90  return ret;
91  }
92 
93  if (my_bind_inet(m_sockfd, &local) == -1)
94  {
95  int ret = my_socket_errno();
96  my_socket_close(m_sockfd);
97  my_socket_invalidate(&m_sockfd);
98  return ret;
99  }
100 
101  return 0;
102 }
103 
104 #ifdef _WIN32
105 #define NONBLOCKERR(E) (E!=SOCKET_EAGAIN && E!=SOCKET_EWOULDBLOCK)
106 #else
107 #define NONBLOCKERR(E) (E!=EINPROGRESS)
108 #endif
109 
110 NDB_SOCKET_TYPE
111 SocketClient::connect(const char *toaddress, unsigned short toport)
112 {
113  if (!my_socket_valid(m_sockfd))
114  {
115  if (!init())
116  {
117  return m_sockfd;
118  }
119  }
120 
121  if (toaddress)
122  {
123  if (m_server_name)
124  free(m_server_name);
125  m_server_name = strdup(toaddress);
126  m_port = toport;
127  memset(&m_servaddr, 0, sizeof(m_servaddr));
128  m_servaddr.sin_family = AF_INET;
129  m_servaddr.sin_port = htons(toport);
130  // Convert ip address presentation format to numeric format
131  if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name))
132  {
133  my_socket_close(m_sockfd);
134  my_socket_invalidate(&m_sockfd);
135  return m_sockfd;
136  }
137  }
138 
139  // Set socket non blocking
140  if (my_socket_nonblock(m_sockfd, true) < 0)
141  {
142  my_socket_close(m_sockfd);
143  my_socket_invalidate(&m_sockfd);
144  return m_sockfd;
145  }
146 
147  // Start non blocking connect
148  int r = my_connect_inet(m_sockfd, &m_servaddr);
149  if (r == 0)
150  goto done; // connected immediately.
151 
152  if (r < 0 && NONBLOCKERR(my_socket_errno())) {
153  // Start of non blocking connect failed
154  my_socket_close(m_sockfd);
155  my_socket_invalidate(&m_sockfd);
156  return m_sockfd;
157  }
158 
159  if (ndb_poll(m_sockfd, true, true, true,
160  m_connect_timeout_millisec > 0 ?
161  m_connect_timeout_millisec : -1) <= 0)
162  {
163  // Nothing has happened on the socket after timeout
164  // or an error occured
165  my_socket_close(m_sockfd);
166  my_socket_invalidate(&m_sockfd);
167  return m_sockfd;
168  }
169 
170  // Activity detected on the socket
171 
172  {
173  // Check socket level error code
174  int so_error = 0;
175  SOCKET_SIZE_TYPE len= sizeof(so_error);
176  if (my_getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0)
177  {
178  my_socket_close(m_sockfd);
179  my_socket_invalidate(&m_sockfd);
180  return m_sockfd;
181  }
182 
183  if (so_error)
184  {
185  my_socket_close(m_sockfd);
186  my_socket_invalidate(&m_sockfd);
187  return m_sockfd;
188  }
189  }
190 
191 done:
192  if (my_socket_nonblock(m_sockfd, true) < 0)
193  {
194  my_socket_close(m_sockfd);
195  my_socket_invalidate(&m_sockfd);
196  return m_sockfd;
197  }
198 
199  if (m_auth) {
200  if (!m_auth->client_authenticate(m_sockfd))
201  {
202  my_socket_close(m_sockfd);
203  my_socket_invalidate(&m_sockfd);
204  return m_sockfd;
205  }
206  }
207  NDB_SOCKET_TYPE sockfd = m_sockfd;
208 
209  my_socket_invalidate(&m_sockfd);
210 
211  return sockfd;
212 }