MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbTCP.cpp
1 /*
2  Copyright (c) 2003, 2011, 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 #include <NdbTCP.h>
21 
22 
23 /* On some operating systems (e.g. Solaris) INADDR_NONE is not defined */
24 #ifndef INADDR_NONE
25 #define INADDR_NONE -1 /* Error value from inet_addr */
26 #endif
27 
28 
29 extern "C"
30 int
31 Ndb_getInAddr(struct in_addr * dst, const char *address)
32 {
33  struct addrinfo hints;
34  memset(&hints, 0, sizeof(hints));
35  hints.ai_family = AF_INET; // Only IPv4 address
36  hints.ai_socktype = SOCK_STREAM;
37  hints.ai_protocol = IPPROTO_TCP;
38 
39  struct addrinfo* ai_list;
40  if (getaddrinfo(address, NULL, &hints, &ai_list) != 0)
41  {
42  dst->s_addr = INADDR_NONE;
43  return -1;
44  }
45 
46  /* Return sin_addr for the first address returned */
47  struct sockaddr_in* sin = (struct sockaddr_in*)ai_list->ai_addr;
48  memcpy(dst, &sin->sin_addr, sizeof(struct in_addr));
49 
50  freeaddrinfo(ai_list);
51  return 0;
52 }
53 
54 #ifdef TEST_NDBGETINADDR
55 #include <NdbTap.hpp>
56 
57 static void
58 CHECK(const char* address, int expected_res, bool is_numeric= false)
59 {
60  struct in_addr addr;
61 
62  fprintf(stderr, "Testing '%s'\n", address);
63 
64  int res= Ndb_getInAddr(&addr, address);
65 
66  if (res != expected_res)
67  {
68  fprintf(stderr, "> unexpected result: %d, expected: %d\n",
69  res, expected_res);
70  abort();
71  }
72 
73  if (res != 0)
74  {
75  fprintf(stderr, "> returned -1, checking INADDR_NONE\n");
76 
77  // Should return INADDR_NONE when when lookup fails
78  struct in_addr none;
79  none.s_addr = INADDR_NONE;
80  if (memcmp(&addr, &none, sizeof(none)) != 0)
81  {
82  fprintf(stderr, "> didn't return INADDR_NONE after failure, "
83  "got: '%s', expected; '%s'\n",
84  inet_ntoa(addr), inet_ntoa(none));
85  abort();
86  }
87  fprintf(stderr, "> ok\n");
88  return;
89  }
90 
91  fprintf(stderr, "> '%s' -> '%s'\n", address, inet_ntoa(addr));
92 
93  if (is_numeric)
94  {
95  // Check that numeric address always map back to itself
96  // ie. compare to value returned by 'inet_aton'
97  fprintf(stderr, "> Checking numeric address against inet_addr\n");
98  struct in_addr addr2;
99  addr2.s_addr = inet_addr(address);
100  fprintf(stderr, "> inet_addr(%s) -> '%s'\n", address, inet_ntoa(addr2));
101 
102  if (memcmp(&addr, &addr2, sizeof(struct in_addr)) != 0)
103  {
104  fprintf(stderr, "> numeric address '%s' didn't map to same value as "
105  "inet_addr: '%s'", address, inet_ntoa(addr2));
106  abort();
107  }
108  fprintf(stderr, "> ok\n");
109  }
110 }
111 
112 
113 /*
114  socket_library_init
115  - Normally done by ndb_init(), but to avoid
116  having to link with "everything", implement it locally
117 */
118 
119 static void
120 socket_library_init(void)
121 {
122 #ifdef _WIN32
123  WORD requested_version = MAKEWORD( 2, 0 );
124  WSADATA wsa_data;
125  if (WSAStartup( requested_version, &wsa_data ))
126  {
127  fprintf(stderr, "failed to init Winsock\n");
128  abort();
129  }
130 
131  // Confirm that the requested version of the library was loaded
132  if (wsa_data.wVersion != requested_version)
133  {
134  (void)WSACleanup();
135  fprintf(stderr, "Wrong version of Winsock loaded\n");
136  abort();
137  }
138 #endif
139 }
140 
141 
142 static void
143 socket_library_end()
144 {
145 #ifdef _WIN32
146  (void)WSACleanup();
147 #endif
148 }
149 
150 static bool
151 can_resolve_hostname(const char* name)
152 {
153  fprintf(stderr, "Checking if '%s' can be used for testing\n", name);
154  struct addrinfo hints;
155  memset(&hints, 0, sizeof(hints));
156  hints.ai_family = AF_INET; // Only IPv4 address
157  hints.ai_socktype = SOCK_STREAM;
158  hints.ai_protocol = IPPROTO_TCP;
159 
160  struct addrinfo* ai_list;
161  int err = getaddrinfo(name, NULL, &hints, &ai_list);
162 
163  if (err)
164  {
165  fprintf(stderr, "> '%s' -> error: %d '%s'\n",
166  name, err, gai_strerror(err));
167 
168  if (err == EAI_NODATA ||
169  err == EAI_NONAME)
170  {
171  // An OK error
172  fprintf(stderr, "> skipping tests with this name...\n");
173  return false;
174  }
175 
176  // Another unhandled error
177  abort();
178  }
179 
180  freeaddrinfo(ai_list);
181 
182  return true;
183 }
184 
185 
186 TAPTEST(NdbGetInAddr)
187 {
188  socket_library_init();
189 
190  if (can_resolve_hostname("localhost"))
191  CHECK("localhost", 0);
192  CHECK("127.0.0.1", 0, true);
193 
194  char hostname_buf[256];
195  if (gethostname(hostname_buf, sizeof(hostname_buf)) == 0 &&
196  can_resolve_hostname(hostname_buf))
197  {
198  // Check this machines hostname
199  CHECK(hostname_buf, 0);
200 
201  struct in_addr addr;
202  Ndb_getInAddr(&addr, hostname_buf);
203  // Convert hostname to dotted decimal string ip and check
204  CHECK(inet_ntoa(addr), 0, true);
205  }
206  CHECK("unknown_?host", -1); // Does not exist
207  CHECK("3ffe:1900:4545:3:200:f8ff:fe21:67cf", -1); // No IPv6
208  CHECK("fe80:0:0:0:200:f8ff:fe21:67cf", -1);
209  CHECK("fe80::200:f8ff:fe21:67cf", -1);
210  CHECK("::1", -1); // the loopback, but still No IPv6
211 
212  socket_library_end();
213 
214  return 1; // OK
215 }
216 #endif
217 
218 
219 static inline
220 int my_socket_nfds(ndb_socket_t s, int nfds)
221 {
222 #ifdef _WIN32
223  (void)s;
224 #else
225  if(s.fd > nfds)
226  return s.fd;
227 #endif
228  return nfds;
229 }
230 
231 #define my_FD_SET(sock,set) FD_SET(ndb_socket_get_native(sock), set)
232 #define my_FD_ISSET(sock,set) FD_ISSET(ndb_socket_get_native(sock), set)
233 
234 
235 int Ndb_check_socket_hup(NDB_SOCKET_TYPE sock)
236 {
237 #ifdef HAVE_POLL
238  struct pollfd pfd[1];
239  int r;
240 
241  pfd[0].fd= sock.fd; // FIXME: THIS IS A BUG
242  pfd[0].events= POLLHUP | POLLIN | POLLOUT | POLLNVAL;
243  pfd[0].revents= 0;
244  r= poll(pfd,1,0);
245  if(pfd[0].revents & (POLLHUP|POLLERR))
246  return 1;
247 
248  return 0;
249 #else /* HAVE_POLL */
250  fd_set readfds, writefds, errorfds;
251  struct timeval tv= {0,0};
252  int s_err;
253  SOCKET_SIZE_TYPE s_err_size= sizeof(s_err);
254 
255  FD_ZERO(&readfds);
256  FD_ZERO(&writefds);
257  FD_ZERO(&errorfds);
258 
259  my_FD_SET(sock, &readfds);
260  my_FD_SET(sock, &writefds);
261  my_FD_SET(sock, &errorfds);
262 
263  if(select(my_socket_nfds(sock,0)+1, &readfds, &writefds, &errorfds, &tv)<0)
264  return 1;
265 
266  if(my_FD_ISSET(sock,&errorfds))
267  return 1;
268 
269  s_err=0;
270  if (my_getsockopt(sock, SOL_SOCKET, SO_ERROR, &s_err, &s_err_size) != 0)
271  return(1);
272 
273  if (s_err)
274  { /* getsockopt could succeed */
275  return(1); /* but return an error... */
276  }
277 
278  return 0;
279 #endif /* HAVE_POLL */
280 }