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
21
#include <drizzled/gettext.h>
22
#include <drizzled/error.h>
23
#include <drizzled/plugin/listen_tcp.h>
24
#include <drizzled/errmsg_print.h>
27
#include <sys/socket.h>
30
#include <netinet/tcp.h>
35
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
39
extern uint32_t back_log;
40
extern uint32_t drizzled_bind_timeout;
43
int plugin::ListenTcp::acceptTcp(int fd)
48
for (retry= 0; retry < MAX_ACCEPT_RETRY; retry++)
50
new_fd= accept(fd, NULL, 0);
51
if (new_fd != -1 || (errno != EINTR && errno != EAGAIN))
57
if ((accept_error_count++ & 255) == 0)
59
errmsg_printf(ERRMSG_LVL_ERROR, _("accept() failed with errno %d"),
63
if (errno == ENFILE || errno == EMFILE)
72
bool plugin::ListenTcp::getFileDescriptors(std::vector<int> &fds)
75
char host_buf[NI_MAXHOST];
76
char port_buf[NI_MAXSERV];
77
struct addrinfo hints;
79
struct addrinfo *ai_list;
84
struct linger ling= {0, 0};
87
memset(&hints, 0, sizeof(struct addrinfo));
88
hints.ai_flags= AI_PASSIVE;
89
hints.ai_socktype= SOCK_STREAM;
91
snprintf(port_buf, NI_MAXSERV, "%d", getPort());
92
ret= getaddrinfo(getHost(), port_buf, &hints, &ai_list);
95
errmsg_printf(ERRMSG_LVL_ERROR, _("getaddrinfo() failed with error %s"),
100
for (ai= ai_list; ai != NULL; ai= ai->ai_next)
102
ret= getnameinfo(ai->ai_addr, ai->ai_addrlen, host_buf, NI_MAXHOST,
103
port_buf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
106
strcpy(host_buf, "-");
107
strcpy(port_buf, "-");
110
fd= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
114
Call to socket() can fail for some getaddrinfo results, try another.
120
if (ai->ai_family == AF_INET6)
123
ret= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flags, sizeof(flags));
126
errmsg_printf(ERRMSG_LVL_ERROR,
127
_("setsockopt(IPV6_V6ONLY) failed with errno %d"),
134
ret= fcntl(fd, F_SETFD, FD_CLOEXEC);
135
if (ret != 0 || !(fcntl(fd, F_GETFD, 0) & FD_CLOEXEC))
137
errmsg_printf(ERRMSG_LVL_ERROR,
138
_("fcntl(FD_CLOEXEC) failed with errno %d"),
143
ret= setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
146
errmsg_printf(ERRMSG_LVL_ERROR,
147
_("setsockopt(SO_REUSEADDR) failed with errno %d"),
152
ret= setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
155
errmsg_printf(ERRMSG_LVL_ERROR,
156
_("setsockopt(SO_KEEPALIVE) failed with errno %d"),
161
ret= setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
164
errmsg_printf(ERRMSG_LVL_ERROR,
165
_("setsockopt(SO_LINGER) failed with errno %d"),
170
ret= setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags));
173
errmsg_printf(ERRMSG_LVL_ERROR,
174
_("setsockopt(TCP_NODELAY) failed with errno %d"),
180
Sometimes the port is not released fast enough when stopping and
181
restarting the server. This happens quite often with the test suite
182
on busy Linux systems. Retry to bind the address at these intervals:
183
Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
184
Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
185
Limit the sequence by drizzled_bind_timeout.
187
for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
189
if (((ret= ::bind(fd, ai->ai_addr, ai->ai_addrlen)) == 0) ||
190
(errno != EADDRINUSE) || (waited >= drizzled_bind_timeout))
195
errmsg_printf(ERRMSG_LVL_INFO, _("Retrying bind() on %u"), getPort());
196
this_wait= retry * retry / 3 + 1;
202
errmsg_printf(ERRMSG_LVL_ERROR, _("bind() failed with errno: %d"),
204
errmsg_printf(ERRMSG_LVL_ERROR,
205
_("Do you already have another drizzled running?"));
209
if (listen(fd, (int) back_log) < 0)
211
errmsg_printf(ERRMSG_LVL_ERROR,
212
_("listen() failed with errno %d"), errno);
218
errmsg_printf(ERRMSG_LVL_INFO, _("Listening on %s:%s\n"), host_buf,
222
freeaddrinfo(ai_list);
227
const char* plugin::ListenTcp::getHost(void) const
232
} /* namespace drizzled */