MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CpcClient.cpp
1 /*
2  Copyright (C) 2003-2008 MySQL AB, 2009, 2010 Sun Microsystems, Inc.
3 
4  All rights reserved. Use is subject to license terms.
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; version 2 of the License.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
20 #include <ndb_global.h>
21 
22 #include <NdbOut.hpp>
23 #include <NdbTCP.h>
24 #include "CpcClient.hpp"
25 
26 #define CPC_CMD(name, value, desc) \
27  { (name), \
28  0, \
29  ParserRow_t::Cmd, \
30  ParserRow_t::String, \
31  ParserRow_t::Optional, \
32  ParserRow_t::IgnoreMinMax, \
33  0, 0, \
34  0, \
35  (desc), \
36  (value) }
37 
38 #define CPC_ARG(name, type, opt, desc) \
39  { (name), \
40  0, \
41  ParserRow_t::Arg, \
42  ParserRow_t::type, \
43  ParserRow_t::opt, \
44  ParserRow_t::IgnoreMinMax, \
45  0, 0, \
46  0, \
47  (desc), 0 }
48 
49 #define CPC_END() \
50  { 0, \
51  0, \
52  ParserRow_t::Arg, \
53  ParserRow_t::Int, \
54  ParserRow_t::Optional, \
55  ParserRow_t::IgnoreMinMax, \
56  0, 0, \
57  0, \
58  0, 0 }
59 
60 #ifdef DEBUG_PRINT_PROPERTIES
61 static void printprop(const Properties &p) {
62  Properties::Iterator iter(&p);
63  const char *name;
64  while((name = iter.next()) != NULL) {
65  PropertiesType t;
66  Uint32 val_i;
67  BaseString val_s;
68 
69  p.getTypeOf(name, &t);
70  switch(t) {
71  case PropertiesType_Uint32:
72  p.get(name, &val_i);
73  ndbout << name << " (Uint32): " << val_i << endl;
74  break;
75  case PropertiesType_char:
76  p.get(name, val_s);
77  ndbout << name << " (string): " << val_s << endl;
78  break;
79  default:
80  ndbout << "Unknown type " << t << endl;
81  break;
82  }
83  }
84 }
85 #endif
86 
87 
88 int
89 SimpleCpcClient::stop_process(Uint32 id, Properties& reply){
90  const ParserRow_t stop_reply[] = {
91  CPC_CMD("stop process", NULL, ""),
92  CPC_ARG("status", Int, Mandatory, ""),
93  CPC_ARG("id", Int, Optional, ""),
94  CPC_ARG("errormessage", String, Optional, ""),
95 
96  CPC_END()
97  };
98 
99  Properties args;
100  args.put("id", id);
101 
102  const Properties* ret = cpc_call("stop process", args, stop_reply);
103  if(ret == 0){
104  reply.put("status", (Uint32)0);
105  reply.put("errormessage", "unknown error");
106  return -1;
107  }
108 
109  Uint32 status = 0;
110  ret->get("status", &status);
111  reply.put("status", status);
112  if(status != 0) {
113  BaseString msg;
114  ret->get("errormessage", msg);
115  reply.put("errormessage", msg.c_str());
116  }
117  delete ret;
118  return status;
119 }
120 
121 
122 int
123 SimpleCpcClient::start_process(Uint32 id, Properties& reply){
124  const ParserRow_t start_reply[] = {
125  CPC_CMD("start process", NULL, ""),
126  CPC_ARG("status", Int, Mandatory, ""),
127  CPC_ARG("id", Int, Optional, ""),
128  CPC_ARG("errormessage", String, Optional, ""),
129 
130  CPC_END()
131  };
132 
133  Properties args;
134  args.put("id", id);
135 
136  const Properties* ret = cpc_call("start process", args, start_reply);
137  if(ret == 0){
138  reply.put("status", (Uint32)0);
139  reply.put("errormessage", "unknown error");
140  return -1;
141  }
142 
143  Uint32 status = 0;
144  ret->get("status", &status);
145  reply.put("status", status);
146  if(status != 0) {
147  BaseString msg;
148  ret->get("errormessage", msg);
149  reply.put("errormessage", msg.c_str());
150  }
151 
152  delete ret;
153 
154  return status;
155 }
156 
157 int
158 SimpleCpcClient::undefine_process(Uint32 id, Properties& reply){
159  const ParserRow_t stop_reply[] = {
160  CPC_CMD("undefine process", NULL, ""),
161  CPC_ARG("status", Int, Mandatory, ""),
162  CPC_ARG("id", Int, Optional, ""),
163  CPC_ARG("errormessage", String, Optional, ""),
164 
165  CPC_END()
166  };
167 
168  Properties args;
169  args.put("id", id);
170 
171  const Properties* ret = cpc_call("undefine process", args, stop_reply);
172  if(ret == 0){
173  reply.put("status", (Uint32)0);
174  reply.put("errormessage", "unknown error");
175  return -1;
176  }
177 
178  Uint32 status = 0;
179  ret->get("status", &status);
180  reply.put("status", status);
181  if(status != 0) {
182  BaseString msg;
183  ret->get("errormessage", msg);
184  reply.put("errormessage", msg.c_str());
185  }
186 
187  delete ret;
188 
189  return status;
190 }
191 
192 #if 0
193 static void
194 printproc(SimpleCpcClient::Process & p) {
195  ndbout.println("Name: %s", p.m_name.c_str());
196  ndbout.println("Id: %d", p.m_id);
197  ndbout.println("Type: %s", p.m_type.c_str());
198  ndbout.println("Group: %s", p.m_group.c_str());
199  ndbout.println("Program path: %s", p.m_path.c_str());
200  ndbout.println("Arguments: %s", p.m_args.c_str());
201  ndbout.println("Environment: %s", p.m_env.c_str());
202  ndbout.println("Working directory: %s", p.m_cwd.c_str());
203  ndbout.println("Owner: %s", p.m_owner.c_str());
204  ndbout.println("Runas: %s", p.m_runas.c_str());
205  ndbout.println("Ulimit: %s", p.m_ulimit.c_str());
206  ndbout.println("%s", "");
207 }
208 #endif
209 
210 static int
211 convert(const Properties & src, SimpleCpcClient::Process & dst){
212  bool b = true;
213  b &= src.get("id", (Uint32*)&dst.m_id);
214  b &= src.get("name", dst.m_name);
215  b &= src.get("type", dst.m_type);
216  b &= src.get("status", dst.m_status);
217  b &= src.get("owner", dst.m_owner);
218  b &= src.get("group", dst.m_group);
219  b &= src.get("path", dst.m_path);
220  b &= src.get("args", dst.m_args);
221  b &= src.get("env", dst.m_env);
222  b &= src.get("cwd", dst.m_cwd);
223  b &= src.get("runas", dst.m_runas);
224 
225  b &= src.get("stdin", dst.m_stdin);
226  b &= src.get("stdout", dst.m_stdout);
227  b &= src.get("stderr", dst.m_stderr);
228  b &= src.get("ulimit", dst.m_ulimit);
229  b &= src.get("shutdown", dst.m_shutdown_options);
230 
231  return b;
232 }
233 
234 static int
235 convert(const SimpleCpcClient::Process & src, Properties & dst ){
236  bool b = true;
237  //b &= dst.put("id", (Uint32)src.m_id);
238  b &= dst.put("name", src.m_name.c_str());
239  b &= dst.put("type", src.m_type.c_str());
240  //b &= dst.put("status", src.m_status.c_str());
241  b &= dst.put("owner", src.m_owner.c_str());
242  b &= dst.put("group", src.m_group.c_str());
243  b &= dst.put("path", src.m_path.c_str());
244  b &= dst.put("args", src.m_args.c_str());
245  b &= dst.put("env", src.m_env.c_str());
246  b &= dst.put("cwd", src.m_cwd.c_str());
247  b &= dst.put("runas", src.m_runas.c_str());
248 
249  b &= dst.put("stdin", src.m_stdin.c_str());
250  b &= dst.put("stdout", src.m_stdout.c_str());
251  b &= dst.put("stderr", src.m_stderr.c_str());
252  b &= dst.put("ulimit", src.m_ulimit.c_str());
253  b &= dst.put("shutdown", src.m_shutdown_options.c_str());
254 
255  return b;
256 }
257 
258 int
259 SimpleCpcClient::define_process(Process & p, Properties& reply){
260  const ParserRow_t define_reply[] = {
261  CPC_CMD("define process", NULL, ""),
262  CPC_ARG("status", Int, Mandatory, ""),
263  CPC_ARG("id", Int, Optional, ""),
264  CPC_ARG("errormessage", String, Optional, ""),
265 
266  CPC_END()
267  };
268 
269  Properties args;
270  convert(p, args);
271 
272  const Properties* ret = cpc_call("define process", args, define_reply);
273  if(ret == 0){
274  reply.put("status", (Uint32)0);
275  reply.put("errormessage", "unknown error");
276  return -1;
277  }
278 
279  Uint32 status = 0;
280  ret->get("status", &status);
281  reply.put("status", status);
282  if(status != 0) {
283  BaseString msg;
284  ret->get("errormessage", msg);
285  reply.put("errormessage", msg.c_str());
286  }
287 
288  Uint32 id;
289  if(!ret->get("id", &id)){
290  return -1;
291  }
292 
293  p.m_id = id;
294  delete ret;
295  return status;
296 }
297 
298 int
299 SimpleCpcClient::list_processes(Vector<Process> &procs, Properties& reply) {
300  int start = 0, end = 0, entry;
301  const ParserRow_t list_reply[] = {
302  CPC_CMD("start processes", &start, ""),
303  CPC_CMD("end processes", &end, ""),
304 
305  CPC_CMD("process", &entry, ""),
306  CPC_ARG("id", Int, Mandatory, "Id of process."),
307  CPC_ARG("name", String, Mandatory, "Name of process"),
308  CPC_ARG("group", String, Mandatory, "Group of process"),
309  CPC_ARG("env", String, Mandatory, "Environment variables for process"),
310  CPC_ARG("path", String, Mandatory, "Path to binary"),
311  CPC_ARG("args", String, Mandatory, "Arguments to process"),
312  CPC_ARG("type", String, Mandatory, "Type of process"),
313  CPC_ARG("cwd", String, Mandatory, "Working directory of process"),
314  CPC_ARG("owner", String, Mandatory, "Owner of process"),
315  CPC_ARG("status",String, Mandatory, "Status of process"),
316  CPC_ARG("runas", String, Mandatory, "Run as user"),
317  CPC_ARG("stdin", String, Mandatory, "Redirect stdin"),
318  CPC_ARG("stdout",String, Mandatory, "Redirect stdout"),
319  CPC_ARG("stderr",String, Mandatory, "Redirect stderr"),
320  CPC_ARG("ulimit",String, Mandatory, "ulimit"),
321  CPC_ARG("shutdown",String, Mandatory, "shutdown"),
322 
323  CPC_END()
324  };
325 
326  reply.clear();
327 
328  const Properties args;
329 
330  cpc_send("list processes", args);
331 
332  bool done = false;
333  while(!done) {
334  const Properties *proc;
335  void *p;
336  cpc_recv(list_reply, &proc, &p);
337 
338  end++;
339  if(p == &start)
340  {
341  start = 1;
342  /* do nothing */
343  }
344  else if(p == &end)
345  {
346  done = true;
347  }
348  else if(p == &entry)
349  {
350  if(proc != NULL)
351  {
352  Process p;
353  convert(* proc, p);
354  procs.push_back(p);
355  }
356  else
357  {
358  ndbout_c("JONAS: start: %d loop: %d cnt: %u got p == &entry with proc == NULL",
359  start, end, procs.size());
360  }
361  }
362  else
363  {
364  ndbout_c("internal error: %d", __LINE__);
365  return -1;
366  }
367  if (proc)
368  {
369  delete proc;
370  }
371  }
372  return 0;
373 }
374 
375 
376 SimpleCpcClient::SimpleCpcClient(const char *_host, int _port) {
377  host = strdup(_host);
378  port = _port;
379  my_socket_invalidate(&cpc_sock);
380 }
381 
382 SimpleCpcClient::~SimpleCpcClient() {
383  if(host != NULL) {
384  free(host);
385  host = NULL;
386  }
387 
388  port = 0;
389 
390  if(my_socket_valid(cpc_sock)) {
391  my_socket_close(cpc_sock);
392  my_socket_invalidate(&cpc_sock);
393  }
394 }
395 
396 int
397 SimpleCpcClient::connect() {
398  struct sockaddr_in sa;
399  struct hostent *hp;
400 
401  /* Create socket */
402  cpc_sock = my_socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP);
403  if(!my_socket_valid(cpc_sock))
404  return -1;
405 
406  /* Connect socket */
407  sa.sin_family = AF_INET;
408  hp = gethostbyname(host);
409  if(hp == NULL) {
410  errno = ENOENT;
411  return -1;
412  }
413 
414  memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
415  sa.sin_port = htons(port);
416  if (my_connect_inet(cpc_sock, &sa) < 0)
417  return -1;
418 
419  return 0;
420 }
421 
422 int
423 SimpleCpcClient::cpc_send(const char *cmd,
424  const Properties &args) {
425  SocketOutputStream cpc_out(cpc_sock);
426 
427  cpc_out.println(cmd);
428 
429  Properties::Iterator iter(&args);
430  const char *name;
431  while((name = iter.next()) != NULL) {
432  PropertiesType t;
433  Uint32 val_i;
434  BaseString val_s;
435 
436  args.getTypeOf(name, &t);
437  switch(t) {
438  case PropertiesType_Uint32:
439  args.get(name, &val_i);
440  cpc_out.println("%s: %d", name, val_i);
441  break;
442  case PropertiesType_char:
443  args.get(name, val_s);
444  if (strlen(val_s.c_str()) > Parser_t::Context::MaxParseBytes)
445  {
446  ndbout << "Argument " << name << " at "
447  << strlen(val_s.c_str())
448  << " longer than max of "
449  << Parser_t::Context::MaxParseBytes
450  << endl;
451  abort();
452  }
453  cpc_out.println("%s: %s", name, val_s.c_str());
454  break;
455  default:
456  /* Silently ignore */
457  break;
458  }
459  }
460  cpc_out.println("%s", "");
461 
462  return 0;
463 }
464 
471 SimpleCpcClient::cpc_recv(const ParserRow_t *syntax,
472  const Properties **reply,
473  void **user_value) {
474  SocketInputStream cpc_in(cpc_sock);
475 
476  Parser_t::Context ctx;
477  ParserDummy session(cpc_sock);
478  Parser_t parser(syntax, cpc_in, true, true, true);
479  *reply = parser.parse(ctx, session);
480  if(user_value != NULL)
481  *user_value = ctx.m_currentCmd->user_value;
482  return ctx.m_status;
483 }
484 
485 const Properties *
486 SimpleCpcClient::cpc_call(const char *cmd,
487  const Properties &args,
488  const ParserRow_t *reply_syntax) {
489  cpc_send(cmd, args);
490 
491  const Properties *ret;
492  cpc_recv(reply_syntax, &ret);
493  return ret;
494 }
495 
496 
497 SimpleCpcClient::ParserDummy::ParserDummy(NDB_SOCKET_TYPE sock)
498  : SocketServer::Session(sock) {
499 }
500 
501 template class Vector<SimpleCpcClient::Process>;