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