Drizzled Public API Documentation

protocol.cc
1 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2010 Brian Aker
5  *
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; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 
22 #include <config.h>
23 #include <drizzled/gettext.h>
24 #include <drizzled/error.h>
25 #include <drizzled/session.h>
26 #include <drizzled/internal/my_sys.h>
27 #include <drizzled/internal/m_string.h>
28 #include <algorithm>
29 #include <iostream>
30 #include <boost/program_options.hpp>
31 #include <boost/filesystem.hpp>
33 
34 #include <sys/stat.h>
35 
36 #include <sys/un.h>
37 
38 #include <plugin/mysql_unix_socket_protocol/protocol.h>
39 
40 #define DRIZZLE_UNIX_SOCKET_PATH "/var/run/drizzle/mysql.socket"
41 
42 namespace po= boost::program_options;
43 namespace fs= boost::filesystem;
44 using namespace drizzled;
45 using namespace std;
46 
47 namespace drizzle_plugin {
48 namespace mysql_unix_socket_protocol {
49 
50 static bool clobber= false;
51 
52 ProtocolCounters Protocol::mysql_unix_counters;
53 
54 Protocol::~Protocol()
55 {
56  fs::remove(_unix_socket_path);
57 }
58 
59 in_port_t Protocol::getPort() const
60 {
61  return 0;
62 }
63 
64 extern "C" {
65 
66  char at_exit_socket_file[1024 * 4]= { 0 };
67 
68  static void remove_socket_file(void)
69  {
70  if (at_exit_socket_file[0])
71  {
72  if (unlink(at_exit_socket_file) == -1)
73  {
74  std::cerr << "Could not remove socket: " << at_exit_socket_file << "(" << strerror(errno) << ")" << std::endl;
75  }
76 
77  at_exit_socket_file[0]= 0;
78  }
79  }
80 }
81 
82 static int init(drizzled::module::Context &context)
83 {
84  const module::option_map &vm= context.getOptions();
85 
86  fs::path uds_path(vm["path"].as<fs::path>());
87  if (not fs::exists(uds_path))
88  {
89  Protocol *listen_obj= new Protocol("mysql_unix_socket_protocol", uds_path);
90  listen_obj->addCountersToTable();
91  context.add(listen_obj);
92  context.registerVariable(new sys_var_const_string_val("path", fs::system_complete(uds_path).file_string()));
93  context.registerVariable(new sys_var_bool_ptr_readonly("clobber", &clobber));
94  context.registerVariable(new sys_var_uint32_t_ptr("max-connections", &Protocol::mysql_unix_counters.max_connections));
95  snprintf(at_exit_socket_file, sizeof(at_exit_socket_file), "%s", uds_path.file_string().c_str());
96  atexit(remove_socket_file);
97  }
98  else
99  {
100  cerr << uds_path << _(" exists already. Do you have another Drizzle or "
101  "MySQL running? Or perhaps the file is stale and "
102  "should be removed?") << std::endl;
103  return 0;
104  }
105 
106  return 0;
107 }
108 
109 bool Protocol::getFileDescriptors(std::vector<int> &fds)
110 {
111  int unix_sock= socket(AF_UNIX, SOCK_STREAM, 0);
112  if (unix_sock < 0)
113  {
114  std::cerr << "Can't start server : UNIX Socket";
115  return false;
116  }
117 
118  // In case we restart and find something in our way we move it aside and
119  // then attempt to remove it.
120  if (clobber)
121  {
122  fs::path move_file(_unix_socket_path.file_string() + ".old");
123  fs::rename(_unix_socket_path, move_file);
124  unlink(move_file.file_string().c_str());
125  }
126 
127 
128  int arg= 1;
129 
130  (void) setsockopt(unix_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));
131  unlink(_unix_socket_path.file_string().c_str());
132 
133  sockaddr_un servAddr;
134  memset(&servAddr, 0, sizeof(servAddr));
135 
136  servAddr.sun_family= AF_UNIX;
137  if (_unix_socket_path.file_string().size() > sizeof(servAddr.sun_path))
138  {
139  std::cerr << "Unix Socket Path length too long. Must be under "
140  << sizeof(servAddr.sun_path) << " bytes." << endl;
141  return false;
142  }
143  memcpy(servAddr.sun_path, _unix_socket_path.file_string().c_str(), min(sizeof(servAddr.sun_path)-1,_unix_socket_path.file_string().size()));
144 
145  socklen_t addrlen= sizeof(servAddr);
146  if (::bind(unix_sock, reinterpret_cast<sockaddr *>(&servAddr), addrlen) < 0)
147  {
148  std::cerr << "Can't start server : Bind on unix socket." << std::endl;
149  std::cerr << "Do you already have another of drizzled or mysqld running on socket: " << _unix_socket_path << "?" << std::endl;
150  std::cerr << "Can't start server : UNIX Socket" << std::endl;
151 
152  return false;
153  }
154 
155  if (listen(unix_sock, (int) 1000) < 0)
156  {
157  std::cerr << "listen() on Unix socket failed with error " << errno << "\n";
158  }
159  else
160  {
161  errmsg_printf(error::INFO, _("Listening on %s"), _unix_socket_path.file_string().c_str());
162  }
163 
164  fds.push_back(unix_sock);
165 
166  chmod(_unix_socket_path.file_string().c_str(),0777);
167 
168  return false;
169 }
170 
171 plugin::Client *Protocol::getClient(int fd)
172 {
173  int new_fd= acceptTcp(fd);
174  return new_fd == -1 ? NULL : new ClientMySQLProtocol(new_fd, getCounters());
175 }
176 
177 static void init_options(drizzled::module::option_context &context)
178 {
179  context("path",
180  po::value<fs::path>()->default_value(DRIZZLE_UNIX_SOCKET_PATH),
181  _("Path used for MySQL UNIX Socket Protocol."));
182  context("clobber",
183  _("Clobber socket file if one is there already."));
184  context("max-connections",
185  po::value<uint32_t>(&Protocol::mysql_unix_counters.max_connections)->default_value(1000),
186  _("Maximum simultaneous connections."));
187 }
188 
189 } /* namespace mysql_unix_socket_protocol */
190 } /* namespace drizzle_plugin */
191 
192 DRIZZLE_DECLARE_PLUGIN
193 {
194  DRIZZLE_VERSION_ID,
195  "mysql_unix_socket_protocol",
196  "0.3",
197  "Brian Aker",
198  N_("MySQL Unix socket protocol"),
199  PLUGIN_LICENSE_GPL,
200  drizzle_plugin::mysql_unix_socket_protocol::init,
201  NULL,
202  drizzle_plugin::mysql_unix_socket_protocol::init_options,
203 }
204 DRIZZLE_DECLARE_PLUGIN_END;