1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
#include <drizzled/server_includes.h>
21
#include <drizzled/listen.h>
22
#include "drizzled/plugin_registry.h"
23
#include <drizzled/gettext.h>
24
#include <drizzled/error.h>
27
#include <netinet/tcp.h>
32
/* This is needed for the plugin registry interface. */
33
static ListenHandler *_default_listen_handler= NULL;
35
ListenHandler::ListenHandler(): fd_list(NULL), fd_count(0)
37
/* Don't allow more than one ListenHandler to be created for now. */
38
assert(_default_listen_handler == NULL);
39
_default_listen_handler= this;
42
ListenHandler::~ListenHandler()
47
assert(_default_listen_handler == this);
48
_default_listen_handler= NULL;
51
void ListenHandler::addListen(const Listen &listen_obj)
53
listen_list.push_back(&listen_obj);
56
void ListenHandler::removeListen(const Listen &listen_obj)
58
listen_list.erase(remove(listen_list.begin(),
64
bool ListenHandler::bindAll(const char *host, uint32_t bind_timeout)
66
vector<const Listen *>::iterator it;
68
char host_buf[NI_MAXHOST];
69
char port_buf[NI_MAXSERV];
70
struct addrinfo hints;
72
struct addrinfo *ai_list;
77
struct linger ling= {0, 0};
79
struct pollfd *tmp_fd_list;
81
for (it= listen_list.begin(); it < listen_list.end(); ++it)
83
memset(&hints, 0, sizeof(struct addrinfo));
84
hints.ai_flags= AI_PASSIVE;
85
hints.ai_socktype= SOCK_STREAM;
87
snprintf(port_buf, NI_MAXSERV, "%d", (*it)->getPort());
88
ret= getaddrinfo(host, port_buf, &hints, &ai_list);
91
errmsg_printf(ERRMSG_LVL_ERROR, _("getaddrinfo() failed with error %s"),
96
for (ai= ai_list; ai != NULL; ai= ai->ai_next)
98
ret= getnameinfo(ai->ai_addr, ai->ai_addrlen, host_buf, NI_MAXHOST,
99
port_buf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
102
strcpy(host_buf, "-");
103
strcpy(port_buf, "-");
106
fd= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
110
Call to socket() can fail for some getaddrinfo results, try another.
116
if (ai->ai_family == AF_INET6)
119
ret= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flags, sizeof(flags));
122
errmsg_printf(ERRMSG_LVL_ERROR,
123
_("setsockopt(IPV6_V6ONLY) failed with errno %d"),
130
ret= setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
133
errmsg_printf(ERRMSG_LVL_ERROR,
134
_("setsockopt(SO_REUSEADDR) failed with errno %d"),
139
ret= setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
142
errmsg_printf(ERRMSG_LVL_ERROR,
143
_("setsockopt(SO_KEEPALIVE) failed with errno %d"),
148
ret= setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
151
errmsg_printf(ERRMSG_LVL_ERROR,
152
_("setsockopt(SO_LINGER) failed with errno %d"),
157
ret= setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags));
160
errmsg_printf(ERRMSG_LVL_ERROR,
161
_("setsockopt(TCP_NODELAY) failed with errno %d"),
167
Sometimes the port is not released fast enough when stopping and
168
restarting the server. This happens quite often with the test suite
169
on busy Linux systems. Retry to bind the address at these intervals:
170
Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
171
Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
172
Limit the sequence by bind_timeout.
174
for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
176
if (((ret= ::bind(fd, ai->ai_addr, ai->ai_addrlen)) == 0) ||
177
(errno != EADDRINUSE) || (waited >= bind_timeout))
182
errmsg_printf(ERRMSG_LVL_INFO, _("Retrying bind() on %u"),
184
this_wait= retry * retry / 3 + 1;
190
errmsg_printf(ERRMSG_LVL_ERROR, _("bind() failed with errno: %d"),
192
errmsg_printf(ERRMSG_LVL_ERROR,
193
_("Do you already have another drizzled running?"));
197
if (listen(fd, (int) back_log) < 0)
199
errmsg_printf(ERRMSG_LVL_ERROR,
200
_("listen() failed with errno %d"), errno);
204
tmp_fd_list= (struct pollfd *)realloc(fd_list,
205
sizeof(struct pollfd) * (fd_count + 1));
206
if (tmp_fd_list == NULL)
208
errmsg_printf(ERRMSG_LVL_ERROR, _("realloc() failed with errno %d"),
213
fd_list= tmp_fd_list;
214
fd_list[fd_count].fd= fd;
215
fd_list[fd_count].events= POLLIN | POLLERR;
216
listen_fd_list.push_back(*it);
219
errmsg_printf(ERRMSG_LVL_INFO, _("Listening on %s:%s\n"), host_buf,
226
errmsg_printf(ERRMSG_LVL_ERROR,
227
_("No sockets could be bound for listening"));
231
freeaddrinfo(ai_list);
234
We need a pipe to wakeup the listening thread since some operating systems
235
are stupid. *cough* OSX *cough*
237
if (pipe(wakeup_pipe) == -1)
239
errmsg_printf(ERRMSG_LVL_ERROR, _("pipe() failed with errno %d"), errno);
243
tmp_fd_list= (struct pollfd *)realloc(fd_list,
244
sizeof(struct pollfd) * (fd_count + 1));
245
if (tmp_fd_list == NULL)
247
errmsg_printf(ERRMSG_LVL_ERROR, _("realloc() failed with errno %d"), errno);
251
fd_list= tmp_fd_list;
252
fd_list[fd_count].fd= wakeup_pipe[0];
253
fd_list[fd_count].events= POLLIN | POLLERR;
259
Protocol *ListenHandler::getProtocol(void) const
266
uint32_t error_count= 0;
270
ready= poll(fd_list, fd_count, -1);
275
errmsg_printf(ERRMSG_LVL_ERROR, _("poll() failed with errno %d"),
284
for (x= 0; x < fd_count; x++)
286
if (fd_list[x].revents != POLLIN)
289
/* Check to see if the wakeup_pipe was written to. */
290
if (x == fd_count - 1)
292
/* Close all file descriptors now. */
293
for (x= 0; x < fd_count; x++)
295
(void) shutdown(fd_list[x].fd, SHUT_RDWR);
296
(void) close(fd_list[x].fd);
300
/* wakeup_pipe[0] was closed in the for loop above. */
301
(void) close(wakeup_pipe[1]);
306
for (retry= 0; retry < MAX_ACCEPT_RETRY; retry++)
308
fd= accept(fd_list[x].fd, NULL, 0);
309
if (fd != -1 || (errno != EINTR && errno != EAGAIN))
315
if ((error_count++ & 255) == 0)
317
errmsg_printf(ERRMSG_LVL_ERROR, _("accept() failed with errno %d"),
321
if (errno == ENFILE || errno == EMFILE)
327
if (!(protocol= listen_fd_list[x]->protocolFactory()))
329
(void) shutdown(fd, SHUT_RDWR);
334
if (protocol->setFileDescriptor(fd))
336
(void) shutdown(fd, SHUT_RDWR);
347
Protocol *ListenHandler::getTmpProtocol(void) const
349
assert(listen_list.size() > 0);
350
return listen_list[0]->protocolFactory();
353
void ListenHandler::wakeup(void)
355
ssize_t ret= write(wakeup_pipe[1], "\0", 1);
359
void add_listen(const Listen &listen_obj)
361
assert(_default_listen_handler != NULL);
362
_default_listen_handler->addListen(listen_obj);
365
void remove_listen(const Listen &listen_obj)
367
assert(_default_listen_handler != NULL);
368
_default_listen_handler->removeListen(listen_obj);
371
void listen_abort(void)
373
assert(_default_listen_handler != NULL);
374
_default_listen_handler->wakeup();