00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021 #include <drizzled/gettext.h>
00022 #include <drizzled/error.h>
00023 #include <drizzled/plugin/listen_tcp.h>
00024 #include <drizzled/errmsg_print.h>
00025 #include <drizzled/constrained_value.h>
00026
00027 #include <cstdio>
00028 #include <unistd.h>
00029 #include <sys/socket.h>
00030 #include <fcntl.h>
00031 #include <netdb.h>
00032 #include <netinet/tcp.h>
00033 #include <cerrno>
00034
00035 #define MAX_ACCEPT_RETRY 10 // Test accept this many times
00036
00037 namespace drizzled
00038 {
00039 extern back_log_constraints back_log;
00040 extern uint32_t drizzled_bind_timeout;
00041
00042
00043 int plugin::ListenTcp::acceptTcp(int fd)
00044 {
00045 int new_fd;
00046 uint32_t retry;
00047
00048 for (retry= 0; retry < MAX_ACCEPT_RETRY; retry++)
00049 {
00050 new_fd= accept(fd, NULL, 0);
00051 if (new_fd != -1 || (errno != EINTR && errno != EAGAIN))
00052 break;
00053 }
00054
00055 if (new_fd == -1)
00056 {
00057 if ((accept_error_count++ & 255) == 0)
00058 {
00059 sql_perror(_("accept() failed with errno %d"));
00060 }
00061
00062 if (errno == ENFILE || errno == EMFILE)
00063 sleep(1);
00064
00065 return -1;
00066 }
00067
00068 return new_fd;
00069 }
00070
00071 bool plugin::ListenTcp::getFileDescriptors(std::vector<int> &fds)
00072 {
00073 int ret;
00074 char host_buf[NI_MAXHOST];
00075 char port_buf[NI_MAXSERV];
00076 struct addrinfo hints;
00077 struct addrinfo *ai;
00078 struct addrinfo *ai_list;
00079 int fd= -1;
00080 uint32_t waited;
00081 uint32_t this_wait;
00082 uint32_t retry;
00083 struct linger ling= {0, 0};
00084 int flags= 1;
00085
00086 memset(&hints, 0, sizeof(struct addrinfo));
00087 hints.ai_flags= AI_PASSIVE;
00088 hints.ai_socktype= SOCK_STREAM;
00089
00090 snprintf(port_buf, NI_MAXSERV, "%d", getPort());
00091 ret= getaddrinfo(getHost().empty() ? NULL : getHost().c_str(), port_buf, &hints, &ai_list);
00092 if (ret != 0)
00093 {
00094 errmsg_printf(error::ERROR, _("getaddrinfo() failed with error %s"),
00095 gai_strerror(ret));
00096 return true;
00097 }
00098
00099 for (ai= ai_list; ai != NULL; ai= ai->ai_next)
00100 {
00101 ret= getnameinfo(ai->ai_addr, ai->ai_addrlen, host_buf, NI_MAXHOST,
00102 port_buf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
00103 if (ret != 0)
00104 {
00105 strcpy(host_buf, "-");
00106 strcpy(port_buf, "-");
00107 }
00108
00109 fd= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00110 if (fd == -1)
00111 {
00112
00113
00114
00115 continue;
00116 }
00117
00118 #ifdef IPV6_V6ONLY
00119 if (ai->ai_family == AF_INET6)
00120 {
00121 flags= 1;
00122 ret= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flags, sizeof(flags));
00123 if (ret != 0)
00124 {
00125 sql_perror(_("setsockopt(IPV6_V6ONLY)"));
00126 return true;
00127 }
00128 }
00129 #endif
00130
00131 ret= fcntl(fd, F_SETFD, FD_CLOEXEC);
00132 if (ret != 0 || !(fcntl(fd, F_GETFD, 0) & FD_CLOEXEC))
00133 {
00134 sql_perror(_("fcntl(FD_CLOEXEC)"));
00135 return true;
00136 }
00137
00138 ret= setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
00139 if (ret != 0)
00140 {
00141 sql_perror(_("setsockopt(SO_REUSEADDR)"));
00142 return true;
00143 }
00144
00145 ret= setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
00146 if (ret != 0)
00147 {
00148 sql_perror(_("setsockopt(SO_KEEPALIVE)"));
00149 return true;
00150 }
00151
00152 ret= setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
00153 if (ret != 0)
00154 {
00155 sql_perror(_("setsockopt(SO_LINGER)"));
00156 return true;
00157 }
00158
00159 ret= setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags));
00160 if (ret != 0)
00161 {
00162 sql_perror(_("setsockopt(TCP_NODELAY)"));
00163 return true;
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
00175 {
00176 if (((ret= ::bind(fd, ai->ai_addr, ai->ai_addrlen)) == 0) ||
00177 (errno != EADDRINUSE) || (waited >= drizzled_bind_timeout))
00178 {
00179 break;
00180 }
00181
00182 errmsg_printf(error::INFO, _("Retrying bind() on %u"), getPort());
00183 this_wait= retry * retry / 3 + 1;
00184 sleep(this_wait);
00185 }
00186
00187 if (ret < 0)
00188 {
00189 std::string error_message;
00190
00191 error_message+= host_buf;
00192 error_message+= ":";
00193 error_message+= port_buf;
00194 error_message+= _(" failed to bind");
00195 sql_perror(error_message);
00196
00197 return true;
00198 }
00199
00200 if (listen(fd, (int) back_log) < 0)
00201 {
00202 sql_perror("listen()");
00203 return true;
00204 }
00205
00206 fds.push_back(fd);
00207
00208 errmsg_printf(error::INFO, _("Listening on %s:%s"), host_buf, port_buf);
00209 }
00210
00211 freeaddrinfo(ai_list);
00212
00213 return false;
00214 }
00215
00216 const std::string plugin::ListenTcp::getHost(void) const
00217 {
00218 return "";
00219 }
00220
00221 }