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 namespace plugin {
00037 
00038 static std::vector<plugin::Listen*> listen_list;
00039 std::vector<plugin::Listen*> listen_fd_list;
00040 std::vector<pollfd> fd_list;
00041 uint32_t fd_count= 0;
00042 int wakeup_pipe[2];
00043 
00044 ListenVector& Listen::getListenProtocols()
00045 {
00046   return listen_list;
00047 }
00048 
00049 bool Listen::addPlugin(plugin::Listen *listen_obj)
00050 {
00051   listen_list.push_back(listen_obj);
00052   return false;
00053 }
00054 
00055 void Listen::removePlugin(plugin::Listen *listen_obj)
00056 {
00057   listen_list.erase(std::remove(listen_list.begin(), listen_list.end(), listen_obj), listen_list.end());
00058 }
00059 
00060 bool Listen::setup()
00061 {
00062   BOOST_FOREACH(plugin::Listen* it, listen_list)
00063   {
00064     std::vector<int> fds;
00065     if (it->getFileDescriptors(fds))
00066     {
00067       errmsg_printf(error::ERROR, _("Error getting file descriptors"));
00068       return true;
00069     }
00070 
00071     fd_list.resize(fd_count + fds.size() + 1);
00072     
00073     BOOST_FOREACH(int fd, fds)
00074     {
00075       fd_list[fd_count].fd= fd;
00076       fd_list[fd_count].events= POLLIN | POLLERR;
00077       listen_fd_list.push_back(it);
00078       fd_count++;
00079     }
00080   }
00081 
00082   if (fd_count == 0)
00083   {
00084     errmsg_printf(error::ERROR, _("No sockets could be bound for listening"));
00085     return true;
00086   }
00087 
00088   /*
00089     We need a pipe to wakeup the listening thread since some operating systems
00090     are stupid. *cough* OSX *cough*
00091   */
00092   if (pipe(wakeup_pipe) == -1)
00093   {
00094     sql_perror("pipe()");
00095     return true;
00096   }
00097 
00098   fd_list.resize(fd_count + 1);
00099 
00100   fd_list[fd_count].fd= wakeup_pipe[0];
00101   fd_list[fd_count].events= POLLIN | POLLERR;
00102   fd_count++;
00103 
00104   return false;
00105 }
00106 
00107 Client *plugin::Listen::getClient()
00108 {
00109   while (1)
00110   {
00111     int ready= poll(&fd_list[0], fd_count, -1);
00112     if (ready == -1)
00113     {
00114       if (errno != EINTR)
00115       {
00116         sql_perror("poll()");
00117       }
00118       continue;
00119     }
00120     else if (ready == 0)
00121       continue;
00122 
00123     for (uint32_t x= 0; x < fd_count; x++)
00124     {
00125       if (fd_list[x].revents != POLLIN)
00126         continue;
00127 
00128       /* Check to see if the wakeup_pipe was written to. */
00129       if (x == fd_count - 1)
00130       {
00131         /* Close all file descriptors now. */
00132         for (x= 0; x < fd_count; x++)
00133         {
00134           (void) ::shutdown(fd_list[x].fd, SHUT_RDWR);
00135           (void) close(fd_list[x].fd);
00136           fd_list[x].fd= -1;
00137         }
00138 
00139         /* wakeup_pipe[0] was closed in the for loop above. */
00140         (void) close(wakeup_pipe[1]);
00141 
00142         return NULL;
00143       }
00144 
00145       if (plugin::Client* client= listen_fd_list[x]->getClient(fd_list[x].fd))
00146         return client;
00147     }
00148   }
00149 }
00150 
00151 Client *plugin::Listen::getNullClient()
00152 {
00153   return new plugin::NullClient();
00154 }
00155 
00156 void Listen::shutdown()
00157 {
00158   ssize_t ret= write(wakeup_pipe[1], "\0", 1);
00159   assert(ret == 1);
00160 }
00161 
00162 } /* namespace plugin */
00163 } /* namespace drizzled */