Drizzled Public API Documentation

listen.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <drizzled/errmsg_print.h>
00023 #include <drizzled/error.h>
00024 #include <drizzled/gettext.h>
00025 #include <drizzled/plugin/listen.h>
00026 #include <drizzled/plugin/listen.h>
00027 #include <drizzled/plugin/null_client.h>
00028 
00029 #ifdef HAVE_SYS_SOCKET_H
00030 #include <sys/socket.h>
00031 #endif
00032 
00033 #include <poll.h>
00034 
00035 namespace drizzled
00036 {
00037 namespace plugin
00038 {
00039 
00040 static std::vector<plugin::Listen *> listen_list;
00041 std::vector<plugin::Listen *> listen_fd_list;
00042 std::vector<pollfd> fd_list;
00043 uint32_t fd_count= 0;
00044 int wakeup_pipe[2];
00045 
00046 ListenVector &Listen::getListenProtocols()
00047 {
00048   return listen_list;
00049 }
00050 
00051 bool Listen::addPlugin(plugin::Listen *listen_obj)
00052 {
00053   listen_list.push_back(listen_obj);
00054   return false;
00055 }
00056 
00057 void Listen::removePlugin(plugin::Listen *listen_obj)
00058 {
00059   listen_list.erase(std::remove(listen_list.begin(),
00060                                 listen_list.end(),
00061                                 listen_obj),
00062                     listen_list.end());
00063 }
00064 
00065 bool Listen::setup(void)
00066 {
00067   std::vector<plugin::Listen *>::iterator it;
00068 
00069   for (it= listen_list.begin(); it < listen_list.end(); ++it)
00070   {
00071     std::vector<int> fds;
00072     std::vector<int>::iterator fd;
00073 
00074     if ((*it)->getFileDescriptors(fds))
00075     {
00076       errmsg_printf(error::ERROR, _("Error getting file descriptors"));
00077       return true;
00078     }
00079 
00080     fd_list.resize(fd_count + fds.size() + 1);
00081 
00082     for (fd= fds.begin(); fd < fds.end(); ++fd)
00083     {
00084       fd_list[fd_count].fd= *fd;
00085       fd_list[fd_count].events= POLLIN | POLLERR;
00086       listen_fd_list.push_back(*it);
00087       fd_count++;
00088     }
00089   }
00090 
00091   if (fd_count == 0)
00092   {
00093     errmsg_printf(error::ERROR,
00094                   _("No sockets could be bound for listening"));
00095     return true;
00096   }
00097 
00098   /*
00099     We need a pipe to wakeup the listening thread since some operating systems
00100     are stupid. *cough* OSX *cough*
00101   */
00102   if (pipe(wakeup_pipe) == -1)
00103   {
00104     sql_perror("pipe()");
00105     return true;
00106   }
00107 
00108   fd_list.resize(fd_count + 1);
00109 
00110   fd_list[fd_count].fd= wakeup_pipe[0];
00111   fd_list[fd_count].events= POLLIN | POLLERR;
00112   fd_count++;
00113 
00114   return false;
00115 }
00116 
00117 Client *plugin::Listen::getClient(void)
00118 {
00119   int ready;
00120   plugin::Client *client;
00121 
00122   while (1)
00123   {
00124     ready= poll(&fd_list[0], fd_count, -1);
00125     if (ready == -1)
00126     {
00127       if (errno != EINTR)
00128       {
00129         sql_perror("poll()");
00130       }
00131 
00132       continue;
00133     }
00134     else if (ready == 0)
00135       continue;
00136 
00137     for (uint32_t x= 0; x < fd_count; x++)
00138     {
00139       if (fd_list[x].revents != POLLIN)
00140         continue;
00141 
00142       /* Check to see if the wakeup_pipe was written to. */
00143       if (x == fd_count - 1)
00144       {
00145         /* Close all file descriptors now. */
00146         for (x= 0; x < fd_count; x++)
00147         {
00148           (void) ::shutdown(fd_list[x].fd, SHUT_RDWR);
00149           (void) close(fd_list[x].fd);
00150           fd_list[x].fd= -1;
00151         }
00152 
00153         /* wakeup_pipe[0] was closed in the for loop above. */
00154         (void) close(wakeup_pipe[1]);
00155 
00156         return NULL;
00157       }
00158 
00159       if (!(client= listen_fd_list[x]->getClient(fd_list[x].fd)))
00160         continue;
00161 
00162       return client;
00163     }
00164   }
00165 }
00166 
00167 Client *plugin::Listen::getNullClient(void)
00168 {
00169   return new plugin::NullClient();
00170 }
00171 
00172 void Listen::shutdown(void)
00173 {
00174   ssize_t ret= write(wakeup_pipe[1], "\0", 1);
00175   assert(ret == 1);
00176 }
00177 
00178 
00179 } /* namespace plugin */
00180 } /* namespace drizzled */