1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 
27 #include <uucode.h>
28 #include <socket_io.h>
29 #include <util/version.h>
30 #include <mgmapi.h>
31 #include <EventLogger.hpp>
32 #include <signaldata/SetLogLevelOrd.hpp>
33 #include <LogLevel.hpp>
34 #include <BaseString.hpp>
35 
36 #include <ConfigValues.hpp>
37 #include <mgmapi_configuration.hpp>
38 #include <Vector.hpp>
39 #include "Services.hpp"
40 #include "../mgmapi/ndb_logevent.hpp"
41 
42 #include "ndb_mgmd_error.h"
43 
44 #include <ndb_base64.h>
45 #include <ndberror.h>
46 
47 extern bool g_StopServer;
48 extern bool g_RestartServer;
49 extern EventLogger * g_eventLogger;
50 
51 /**
52    const char * name;
53    const char * realName;
54    const Type type;
55    const ArgType argType;
56    const ArgRequired argRequired;
57    const ArgMinMax argMinMax;
58    const int minVal;
59    const int maxVal;
60    void (T::* function)(const class Properties & args);
61    const char * description;
62 */
63 
64 #define MGM_CMD(name, fun, desc) \
65  { name, \
66    0, \
67    ParserRow<MgmApiSession>::Cmd, \
68    ParserRow<MgmApiSession>::String, \
69    ParserRow<MgmApiSession>::Optional, \
70    ParserRow<MgmApiSession>::IgnoreMinMax, \
71    0, 0, \
72    fun, \
73    desc, 0 }
74 
75 #define MGM_ARG(name, type, opt, desc) \
76  { name, \
77    0, \
78    ParserRow<MgmApiSession>::Arg, \
79    ParserRow<MgmApiSession>::type, \
80    ParserRow<MgmApiSession>::opt, \
81    ParserRow<MgmApiSession>::IgnoreMinMax, \
82    0, 0, \
83    0, \
84   desc, 0 }
85 
86 #define MGM_ARG2(name, type, opt, min, max, desc) \
87  { name, \
88    0, \
89    ParserRow<MgmApiSession>::Arg, \
90    ParserRow<MgmApiSession>::type, \
91    ParserRow<MgmApiSession>::opt, \
92    ParserRow<MgmApiSession>::IgnoreMinMax, \
93    min, max, \
94    0, \
95   desc, 0 }
96 
97 #define MGM_END() \
98  { 0, \
99    0, \
100    ParserRow<MgmApiSession>::Arg, \
101    ParserRow<MgmApiSession>::Int, \
102    ParserRow<MgmApiSession>::Optional, \
103    ParserRow<MgmApiSession>::IgnoreMinMax, \
104    0, 0, \
105    0, \
106    0, 0 }
107 
108 #define MGM_CMD_ALIAS(name, realName, fun) \
109  { name, \
110    realName, \
111    ParserRow<MgmApiSession>::CmdAlias, \
112    ParserRow<MgmApiSession>::Int, \
113    ParserRow<MgmApiSession>::Optional, \
114    ParserRow<MgmApiSession>::IgnoreMinMax, \
115    0, 0, \
116    0, \
117    0, 0 }
118 
119 #define MGM_ARG_ALIAS(name, realName, fun) \
120  { name, \
121    realName, \
122    ParserRow<MgmApiSession>::ArgAlias, \
123    ParserRow<MgmApiSession>::Int, \
124    ParserRow<MgmApiSession>::Optional, \
125    ParserRow<MgmApiSession>::IgnoreMinMax, \
126    0, 0, \
127    0, \
128    0, 0 }
129 
130 const
131 ParserRow<MgmApiSession> commands[] = {
132   MGM_CMD("get config", &MgmApiSession::getConfig, ""),
133     MGM_ARG("version", Int, Mandatory, "Configuration version number"),
134     MGM_ARG("node", Int, Optional, "Node ID"),
135     MGM_ARG("nodetype", Int, Optional, "Type of requesting node"),
136     MGM_ARG("from_node", Int, Optional, "Node to get config from"),
137 
138   MGM_CMD("get nodeid", &MgmApiSession::get_nodeid, ""),
139     MGM_ARG("version", Int, Mandatory, "Configuration version number"),
140     MGM_ARG("nodetype", Int, Mandatory, "Node type"),
141     MGM_ARG("transporter", String, Optional, "Transporter type"),
142     MGM_ARG("nodeid", Int, Optional, "Node ID"),
143     MGM_ARG("user", String, Mandatory, "Password"),
144     MGM_ARG("password", String, Mandatory, "Password"),
145     MGM_ARG("public key", String, Mandatory, "Public key"),
146     MGM_ARG("endian", String, Optional, "Endianness"),
147     MGM_ARG("name", String, Optional, "Name of connection"),
148     MGM_ARG("timeout", Int, Optional, "Timeout in seconds"),
149     MGM_ARG("log_event", Int, Optional, "Log failure in cluster log"),
150 
151   MGM_CMD("get version", &MgmApiSession::getVersion, ""),
152 
153   MGM_CMD("get status", &MgmApiSession::getStatus, ""),
154     MGM_ARG("types", String, Optional, "Types"),
155 
156   MGM_CMD("get info clusterlog", &MgmApiSession::getInfoClusterLog, ""),
157   MGM_CMD("get cluster loglevel", &MgmApiSession::getClusterLogLevel, ""),
158 
159   MGM_CMD("restart node", &MgmApiSession::restart_v1, ""),
160     MGM_ARG("node", String, Mandatory, "Nodes to restart"),
161     MGM_ARG("initialstart", Int, Optional, "Initial start"),
162     MGM_ARG("nostart", Int, Optional, "No start"),
163     MGM_ARG("abort", Int, Optional, "Abort"),
164 
165   MGM_CMD("restart node v2", &MgmApiSession::restart_v2, ""),
166     MGM_ARG("node", String, Mandatory, "Nodes to restart"),
167     MGM_ARG("initialstart", Int, Optional, "Initial start"),
168     MGM_ARG("nostart", Int, Optional, "No start"),
169     MGM_ARG("abort", Int, Optional, "Abort"),
170     MGM_ARG("force", Int, Optional, "Force"),
171 
172   MGM_CMD("restart all", &MgmApiSession::restartAll, ""),
173     MGM_ARG("initialstart", Int, Optional, "Initial start"),
174     MGM_ARG("nostart", Int, Optional, "No start"),
175     MGM_ARG("abort", Int, Optional, "Abort"),
176 
177   MGM_CMD("insert error", &MgmApiSession::insertError, ""),
178     MGM_ARG("node", Int, Mandatory, "Node to receive error"),
179     MGM_ARG("error", Int, Mandatory, "Errorcode to insert"),
180 
181   MGM_CMD("set trace", &MgmApiSession::setTrace, ""),
182     MGM_ARG("node", Int, Mandatory, "Node"),
183     MGM_ARG("trace", Int, Mandatory, "Trace number"),
184 
185   MGM_CMD("log signals", &MgmApiSession::logSignals, ""),
186     MGM_ARG("node", Int, Mandatory, "Node"),
187     MGM_ARG("blocks", String, Mandatory, "Blocks (space separated)"),
188     MGM_ARG("in", Int, Mandatory, "Log input signals"),
189     MGM_ARG("out", Int, Mandatory, "Log output signals"),
190 
191   MGM_CMD("start signallog", &MgmApiSession::startSignalLog, ""),
192     MGM_ARG("node", Int, Mandatory, "Node"),
193 
194   MGM_CMD("stop signallog", &MgmApiSession::stopSignalLog, ""),
195     MGM_ARG("node", Int, Mandatory, "Node"),
196 
197   MGM_CMD("dump state", &MgmApiSession::dumpState, ""),
198     MGM_ARG("node", Int, Mandatory ,"Node"),
199     MGM_ARG("args", String, Mandatory, "Args(space separated int's)"),
200 
201   MGM_CMD("start backup", &MgmApiSession::startBackup, ""),
202     MGM_ARG("completed", Int, Optional ,"Wait until completed"),
203     MGM_ARG("backupid", Int, Optional ,"User input backup id"),
204     MGM_ARG("backuppoint", Int, Optional ,"backup snapshot at start time or complete time"),
205 
206   MGM_CMD("abort backup", &MgmApiSession::abortBackup, ""),
207     MGM_ARG("id", Int, Mandatory, "Backup id"),
208 
209   MGM_CMD("stop", &MgmApiSession::stop_v1, ""),
210     MGM_ARG("node", String, Mandatory, "Node"),
211     MGM_ARG("abort", Int, Mandatory, "Node"),
212 
213   MGM_CMD("stop v2", &MgmApiSession::stop_v2, ""),
214     MGM_ARG("node", String, Mandatory, "Node"),
215     MGM_ARG("abort", Int, Mandatory, "Node"),
216     MGM_ARG("force", Int, Optional, "Force"),
217 
218   MGM_CMD("stop all", &MgmApiSession::stopAll, ""),
219     MGM_ARG("abort", Int, Mandatory, "Node"),
220     MGM_ARG("stop", String, Optional, "MGM/DB or both"),
221 
222   MGM_CMD("enter single user", &MgmApiSession::enterSingleUser, ""),
223     MGM_ARG("nodeId", Int, Mandatory, "Node"),
224 
225   MGM_CMD("exit single user", &MgmApiSession::exitSingleUser, ""),
226 
227 
228   MGM_CMD("start", &MgmApiSession::start, ""),
229     MGM_ARG("node", Int, Mandatory, "Node"),
230 
231   MGM_CMD("start all", &MgmApiSession::startAll, ""),
232 
233   MGM_CMD("bye", &MgmApiSession::bye, ""),
234 
235   MGM_CMD("end session", &MgmApiSession::endSession, ""),
236 
237   MGM_CMD("set loglevel", &MgmApiSession::setLogLevel, ""),
238     MGM_ARG("node", Int, Mandatory, "Node"),
239     MGM_ARG("category", Int, Mandatory, "Event category"),
240     MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
241 
242   MGM_CMD("set cluster loglevel", &MgmApiSession::setClusterLogLevel, ""),
243     MGM_ARG("node", Int, Mandatory, "Node"),
244     MGM_ARG("category", Int, Mandatory, "Event category"),
245     MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
246 
247   MGM_CMD("set logfilter", &MgmApiSession::setLogFilter, ""),
248     MGM_ARG("level", Int, Mandatory, "Severety level"),
249     MGM_ARG("enable", Int, Mandatory, "1=disable, 0=enable, -1=toggle"),
250 
251   MGM_CMD("set parameter", &MgmApiSession::setParameter, ""),
252     MGM_ARG("node", Int, Mandatory, "Node"),
253     MGM_ARG("parameter", Int, Mandatory, "Parameter"),
254     MGM_ARG("value", String, Mandatory, "Value"),
255 
256   MGM_CMD("set connection parameter",
257 	  &MgmApiSession::setConnectionParameter, ""),
258     MGM_ARG("node1", Int, Mandatory, "Node1 ID"),
259     MGM_ARG("node2", Int, Mandatory, "Node2 ID"),
260     MGM_ARG("param", Int, Mandatory, "Parameter"),
261     MGM_ARG("value", Int, Mandatory, "Value"),
262 
263   MGM_CMD("get connection parameter",
264 	  &MgmApiSession::getConnectionParameter, ""),
265     MGM_ARG("node1", Int, Mandatory, "Node1 ID"),
266     MGM_ARG("node2", Int, Mandatory, "Node2 ID"),
267     MGM_ARG("param", Int, Mandatory, "Parameter"),
268 
269   MGM_CMD("listen event", &MgmApiSession::listen_event, ""),
270     MGM_ARG("node", Int, Optional, "Node"),
271     MGM_ARG("parsable", Int, Optional, "Parsable"),
272     MGM_ARG("filter", String, Mandatory, "Event category"),
273 
274   MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""),
275 
276   MGM_CMD("check connection", &MgmApiSession::check_connection, ""),
277 
278   MGM_CMD("transporter connect", &MgmApiSession::transporter_connect, ""),
279 
280   MGM_CMD("get mgmd nodeid", &MgmApiSession::get_mgmd_nodeid, ""),
281 
282   MGM_CMD("report event", &MgmApiSession::report_event, ""),
283     MGM_ARG("length", Int, Mandatory, "Length"),
284     MGM_ARG("data", String, Mandatory, "Data"),
285 
286   MGM_CMD("list sessions", &MgmApiSession::listSessions, ""),
287 
288   MGM_CMD("get session id", &MgmApiSession::getSessionId, ""),
289 
290   MGM_CMD("get session", &MgmApiSession::getSession, ""),
291     MGM_ARG("id", Int, Mandatory, "SessionID"),
292 
293   MGM_CMD("set config", &MgmApiSession::setConfig, ""),
294     MGM_ARG("Content-Length", Int, Mandatory, "Length of config"),
295     MGM_ARG("Content-Type", String, Mandatory, "Type of config"),
296     MGM_ARG("Content-Transfer-Encoding", String, Mandatory, "encoding"),
297 
298   MGM_CMD("create nodegroup", &MgmApiSession::create_nodegroup, ""),
299     MGM_ARG("nodes", String, Mandatory, "Nodes"),
300 
301   MGM_CMD("drop nodegroup", &MgmApiSession::drop_nodegroup, ""),
302     MGM_ARG("ng", Int, Mandatory, "Nodegroup"),
303 
304   MGM_CMD("show config", &MgmApiSession::showConfig, ""),
305     MGM_ARG("Section", String, Optional, "Section name"),
306     MGM_ARG("NodeId", Int, Optional, "Nodeid"),
307     MGM_ARG("Name", String, Optional, "Parameter name"),
308 
309   MGM_CMD("reload config", &MgmApiSession::reloadConfig, ""),
310     MGM_ARG("config_filename", String, Optional, "Reload from path"),
311     MGM_ARG("mycnf", Int, Optional, "Reload from my.cnf"),
312     MGM_ARG("force", Int, Optional, "Force reload"),
313 
314   MGM_CMD("show variables", &MgmApiSession::show_variables, ""),
315 
316   MGM_CMD("dump events", &MgmApiSession::dump_events, ""),
317     MGM_ARG("type", Int, Mandatory, "Type of event"),
318     MGM_ARG("nodes", String, Optional, "Nodes to include"),
319 
320   MGM_END()
321 };
322 
323 struct PurgeStruct
324 {
325   NodeBitmask free_nodes;/* free nodes as reported
326 			  * by ndbd in apiRegReqConf
327 			  */
328   BaseString *str;
329   NDB_TICKS tick;
330 };
331 
332 extern int g_errorInsert;
333 #define ERROR_INSERTED(x) (g_errorInsert == x || m_errorInsert == x)
334 
335 #define SLEEP_ERROR_INSERTED(x) if(ERROR_INSERTED(x)){NdbSleep_SecSleep(10);}
336 
MgmApiSession(class MgmtSrvr & mgm,NDB_SOCKET_TYPE sock,Uint64 session_id)337 MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock, Uint64 session_id)
338   : SocketServer::Session(sock), m_mgmsrv(mgm), m_name("unknown:0")
339 {
340   DBUG_ENTER("MgmApiSession::MgmApiSession");
341   m_input = new SocketInputStream(sock, SOCKET_TIMEOUT);
342   m_output = new BufferedSockOutputStream(sock, SOCKET_TIMEOUT);
343   m_parser = new Parser_t(commands, *m_input, true, true, true);
344   m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv);
345   m_stopSelf= 0;
346   m_ctx= NULL;
347   m_session_id= session_id;
348   m_mutex= NdbMutex_Create();
349   m_errorInsert= 0;
350 
351   struct sockaddr_in addr;
352   SOCKET_SIZE_TYPE addrlen= sizeof(addr);
353   if (my_getpeername(sock, (struct sockaddr*)&addr, &addrlen) == 0)
354     m_name.assfmt("%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
355   DBUG_PRINT("info", ("new connection from: %s", m_name.c_str()));
356 
357   DBUG_VOID_RETURN;
358 }
359 
~MgmApiSession()360 MgmApiSession::~MgmApiSession()
361 {
362   DBUG_ENTER("MgmApiSession::~MgmApiSession");
363   if (m_input)
364     delete m_input;
365   if (m_output)
366     delete m_output;
367   if (m_parser)
368     delete m_parser;
369   if (m_allocated_resources)
370     delete m_allocated_resources;
371   if(my_socket_valid(m_socket))
372   {
373     NDB_CLOSE_SOCKET(m_socket);
374     my_socket_invalidate(&m_socket);
375   }
376   if(m_stopSelf < 0)
377     g_RestartServer= true;
378   if(m_stopSelf)
379     g_StopServer= true;
380   NdbMutex_Destroy(m_mutex);
381   DBUG_VOID_RETURN;
382 }
383 
384 void
runSession()385 MgmApiSession::runSession()
386 {
387   DBUG_ENTER("MgmApiSession::runSession");
388 
389   g_eventLogger->debug("%s: Connected!", name());
390 
391   Parser_t::Context ctx;
392   ctx.m_mutex= m_mutex;
393   m_ctx= &ctx;
394   bool stop= false;
395   while(!stop) {
396     NdbMutex_Lock(m_mutex);
397 
398     m_input->reset_timeout();
399     m_output->reset_timeout();
400 
401     if (m_parser->run(ctx, *this))
402     {
403       stop= m_stop; // Has session been stopped
404       assert(ctx.m_status == Parser_t::Ok);
405     }
406     else
407     {
408       stop= m_stop; // Has session been stopped
409       const char* msg= NULL;
410       switch(ctx.m_status) {
411       case Parser_t::Eof:    // Client disconnected
412         stop= true;
413         g_eventLogger->debug("%s: Eof!", name());
414         break;
415 
416       case Parser_t::ExternalStop: // Stopped by other thread
417         stop= true;
418         g_eventLogger->debug("%s: ExternalStop!", name());
419         break;
420 
421       case Parser_t::NoLine: // Normal read timeout
422       case Parser_t::EmptyLine:
423         break;
424 
425       case Parser_t::UnknownCommand: msg= "Unknown command"; break;
426       case Parser_t::UnknownArgument: msg= "Unknown argument"; break;
427       case Parser_t::TypeMismatch: msg= "Type mismatch"; break;
428       case Parser_t::InvalidArgumentFormat: msg= "Invalid arg. format"; break;
429       case Parser_t::UnknownArgumentType: msg= "Unknown argument type"; break;
430       case Parser_t::ArgumentGivenTwice: msg= "Argument given twice"; break;
431       case Parser_t::MissingMandatoryArgument: msg= "Missing arg."; break;
432 
433       case Parser_t::Ok: // Should never happen here
434       case Parser_t::CommandWithoutFunction:
435         abort();
436         break;
437       }
438 
439       if (msg){
440         g_eventLogger->debug("%s: %s, '%s'",
441                              name(),
442                              msg,
443                              ctx.m_currentToken != 0 ?
444                              ctx.m_currentToken : "<NULL>");
445 
446         // Send result to client
447         m_output->println("result: %s, '%s'",
448                           msg,
449                           ctx.m_currentToken != 0 ?
450                           ctx.m_currentToken : "<NULL>");
451         m_output->print("\n");
452       }
453     }
454 
455     NdbMutex_Unlock(m_mutex);
456 
457     // Send output from command to the client
458     m_output->flush();
459 
460   }
461 
462   g_eventLogger->debug("%s: Stopped!", name());
463 
464   NdbMutex_Lock(m_mutex);
465   m_ctx= NULL;
466   if(my_socket_valid(m_socket))
467   {
468     my_socket_close(m_socket);
469     my_socket_invalidate(&m_socket);
470   }
471   NdbMutex_Unlock(m_mutex);
472 
473   g_eventLogger->debug("%s: Disconnected!", name());
474 
475   DBUG_VOID_RETURN;
476 }
477 
478 void
get_nodeid(Parser_t::Context &,const class Properties & args)479 MgmApiSession::get_nodeid(Parser_t::Context &,
480 			  const class Properties &args)
481 {
482   Uint32 version, nodeid= 0, nodetype= 0xff;
483   Uint32 timeout= 20;  // default seconds timeout
484   const char * transporter;
485   const char * user;
486   const char * password;
487   const char * public_key;
488   const char * endian= NULL;
489   const char * name= NULL;
490   Uint32 log_event= 1;
491   bool log_event_version;
492   union { long l; char c[sizeof(long)]; } endian_check;
493 
494   args.get("version", &version);
495   args.get("nodetype", &nodetype);
496   args.get("transporter", &transporter);
497   args.get("nodeid", &nodeid);
498   args.get("user", &user);
499   args.get("password", &password);
500   args.get("public key", &public_key);
501   args.get("endian", &endian);
502   args.get("name", &name);
503   args.get("timeout", &timeout);
504   /* for backwards compatability keep track if client uses new protocol */
505   log_event_version= args.get("log_event", &log_event);
506 
507   m_output->println("get nodeid reply");
508 
509   endian_check.l = 1;
510   if(endian
511      && strcmp(endian,(endian_check.c[sizeof(long)-1])?"big":"little")!=0) {
512     m_output->println("result: Node does not have the same endianness as the management server.");
513     m_output->println("%s", "");
514     return;
515   }
516 
517   bool compatible;
518   switch (nodetype) {
519   case NODE_TYPE_MGM:
520   case NODE_TYPE_API:
521     compatible = ndbCompatible_mgmt_api(NDB_VERSION, version);
522     break;
523   case NODE_TYPE_DB:
524     compatible = ndbCompatible_mgmt_ndb(NDB_VERSION, version);
525     break;
526   default:
527     m_output->println("result: unknown nodetype %d", nodetype);
528     m_output->println("%s", "");
529     return;
530   }
531 
532   struct sockaddr_in addr;
533   SOCKET_SIZE_TYPE addrlen= sizeof(addr);
534   int r = my_getpeername(m_socket, (struct sockaddr*)&addr, &addrlen);
535   if (r != 0 ) {
536     m_output->println("result: getpeername(" MY_SOCKET_FORMAT   \
537                       ") failed, err= %d",
538                       MY_SOCKET_FORMAT_VALUE(m_socket), r);
539     m_output->println("%s", "");
540     return;
541   }
542 
543   /* Check nodeid parameter */
544   if (nodeid > MAX_NODES_ID)
545   {
546     m_output->println("result: illegal nodeid %u", nodeid);
547     m_output->println("%s", "");
548     return;
549   }
550 
551   NodeId tmp= nodeid;
552   if(tmp == 0 || !m_allocated_resources->is_reserved(tmp)){
553     BaseString error_string;
554     int error_code;
555     NDB_TICKS tick= 0;
556     /* only report error on second attempt as not to clog the cluster log */
557     while (!m_mgmsrv.alloc_node_id(&tmp, (enum ndb_mgm_node_type)nodetype,
558                                    (struct sockaddr*)&addr, &addrlen,
559                                    error_code, error_string,
560                                    tick == 0 ? 0 : log_event,
561                                    timeout))
562     {
563       /* NDB_MGM_ALLOCID_CONFIG_MISMATCH is a non retriable error */
564       if (tick == 0 && error_code != NDB_MGM_ALLOCID_CONFIG_MISMATCH)
565       {
566         // attempt to free any timed out reservations
567         tick= NdbTick_CurrentMillisecond();
568         struct PurgeStruct ps;
569         m_mgmsrv.get_connected_nodes(ps.free_nodes);
570         // invert connected_nodes to get free nodes
571         ps.free_nodes.bitXORC(NodeBitmask());
572         ps.str= 0;
573         ps.tick= tick;
574         m_mgmsrv.get_socket_server()->
575           foreachSession(stop_session_if_timed_out,&ps);
576 	m_mgmsrv.get_socket_server()->checkSessions();
577         error_string = "";
578         continue;
579       }
580       const char *alias;
581       const char *str;
582       alias= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)
583 						nodetype, &str);
584       m_output->println("result: %s", error_string.c_str());
585       /* only use error_code protocol if client knows about it */
586       if (log_event_version)
587         m_output->println("error_code: %d", error_code);
588       m_output->println("%s", "");
589       return;
590     }
591   }
592 
593 #if 0
594   if (!compatible){
595     m_output->println(cmd);
596     m_output->println("result: incompatible version mgmt 0x%x and node 0x%x",
597 		      NDB_VERSION, version);
598     m_output->println("%s", "");
599     return;
600   }
601 #endif
602 
603   m_output->println("nodeid: %u", tmp);
604   m_output->println("result: Ok");
605   m_output->println("%s", "");
606   m_allocated_resources->reserve_node(tmp, timeout*1000);
607 
608   if (name)
609     g_eventLogger->info("Node %d: %s", tmp, name);
610 
611   return;
612 }
613 
614 void
getConfig(Parser_t::Context &,const class Properties & args)615 MgmApiSession::getConfig(Parser_t::Context &,
616                          const class Properties &args)
617 {
618   Uint32 nodetype = NDB_MGM_NODE_TYPE_UNKNOWN;
619   Uint32 from_node = 0;
620 
621   // Ignoring mandatory parameter "version"
622   // Ignoring optional parameter "node"
623   args.get("nodetype", &nodetype);
624   args.get("from_node", &from_node);
625 
626   SLEEP_ERROR_INSERTED(1);
627   m_output->println("get config reply");
628 
629   BaseString pack64, error;
630 
631   UtilBuffer packed;
632 
633   bool success = (from_node > 0) ?
634                  m_mgmsrv.get_packed_config_from_node(from_node,
635                                                       pack64, error) :
636                  m_mgmsrv.get_packed_config((ndb_mgm_node_type)nodetype,
637                                             pack64, error);
638 
639   if (!success)
640   {
641     m_output->println("result: %s", error.c_str());
642     m_output->print("\n");
643     return;
644   }
645 
646   m_output->println("result: Ok");
647   m_output->println("Content-Length: %u", pack64.length());
648   m_output->println("Content-Type: ndbconfig/octet-stream");
649   SLEEP_ERROR_INSERTED(2);
650   m_output->println("Content-Transfer-Encoding: base64");
651   m_output->print("\n");
652 
653   if(ERROR_INSERTED(3))
654   {
655     // Return only half the packed config
656     BaseString half64 = pack64.substr(0, pack64.length());
657     m_output->println(half64.c_str());
658     return;
659   }
660   m_output->println(pack64.c_str());
661   m_output->print("\n");
662   return;
663 }
664 
665 void
insertError(Parser<MgmApiSession>::Context &,Properties const & args)666 MgmApiSession::insertError(Parser<MgmApiSession>::Context &,
667 			   Properties const &args) {
668   Uint32 node = 0, error = 0;
669   int result= 0;
670 
671   args.get("node", &node);
672   args.get("error", &error);
673 
674   if(node==m_mgmsrv.getOwnNodeId()
675      && error < MGM_ERROR_MAX_INJECT_SESSION_ONLY)
676   {
677     m_errorInsert= error;
678     if(error==0)
679       g_errorInsert= error;
680   }
681   else
682   {
683     result= m_mgmsrv.insertError(node, error);
684   }
685 
686   m_output->println("insert error reply");
687   if(result != 0)
688     m_output->println("result: %s", get_error_text(result));
689   else
690     m_output->println("result: Ok");
691   m_output->println("%s", "");
692 }
693 
694 void
setTrace(Parser<MgmApiSession>::Context &,Properties const & args)695 MgmApiSession::setTrace(Parser<MgmApiSession>::Context &,
696 			Properties const &args) {
697   Uint32 node = 0, trace = 0;
698 
699   args.get("node", &node);
700   args.get("trace", &trace);
701 
702   int result = m_mgmsrv.setTraceNo(node, trace);
703 
704   m_output->println("set trace reply");
705   if(result != 0)
706     m_output->println("result: %s", get_error_text(result));
707   else
708     m_output->println("result: Ok");
709   m_output->println("%s", "");
710 }
711 
712 void
getVersion(Parser<MgmApiSession>::Context &,Properties const &)713 MgmApiSession::getVersion(Parser<MgmApiSession>::Context &,
714 			  Properties const &) {
715   m_output->println("version");
716   m_output->println("id: %d", NDB_VERSION_D);
717   m_output->println("major: %d", NDB_VERSION_MAJOR);
718   m_output->println("minor: %d", NDB_VERSION_MINOR);
719   m_output->println("build: %d", NDB_VERSION_BUILD);
720   m_output->println("string: %s", m_mgmsrv.get_version_string());
721   m_output->println("mysql_major: %d", NDB_MYSQL_VERSION_MAJOR);
722   m_output->println("mysql_minor: %d", NDB_MYSQL_VERSION_MINOR);
723   m_output->println("mysql_build: %d", NDB_MYSQL_VERSION_BUILD);
724   m_output->println("%s", "");
725 }
726 
727 void
startBackup(Parser<MgmApiSession>::Context &,Properties const & args)728 MgmApiSession::startBackup(Parser<MgmApiSession>::Context &,
729 			   Properties const &args) {
730   DBUG_ENTER("MgmApiSession::startBackup");
731   unsigned backupId;
732   unsigned input_backupId= 0;
733   unsigned backuppoint= 0;
734   Uint32 completed= 2;
735   int result;
736 
737   args.get("completed", &completed);
738 
739   if(args.contains("backupid"))
740     args.get("backupid", &input_backupId);
741   if(args.contains("backuppoint"))
742     args.get("backuppoint", &backuppoint);
743 
744   result = m_mgmsrv.startBackup(backupId, completed, input_backupId, backuppoint);
745 
746   m_output->println("start backup reply");
747   if(result != 0)
748   {
749     m_output->println("result: %s", get_error_text(result));
750   }
751   else{
752     m_output->println("result: Ok");
753     if (completed)
754       m_output->println("id: %d", backupId);
755   }
756   m_output->println("%s", "");
757   DBUG_VOID_RETURN;
758 }
759 
760 void
abortBackup(Parser<MgmApiSession>::Context &,Properties const & args)761 MgmApiSession::abortBackup(Parser<MgmApiSession>::Context &,
762 			   Properties const &args) {
763   Uint32 id = 0;
764 
765   args.get("id", &id);
766 
767   int result = m_mgmsrv.abortBackup(id);
768 
769   m_output->println("abort backup reply");
770   if(result != 0)
771     m_output->println("result: %s", get_error_text(result));
772   else
773     m_output->println("result: Ok");
774   m_output->println("%s", "");
775 }
776 
777 /*****************************************************************************/
778 
779 void
dumpState(Parser<MgmApiSession>::Context &,Properties const & args)780 MgmApiSession::dumpState(Parser<MgmApiSession>::Context &,
781 			 Properties const &args) {
782   Uint32 node;
783   BaseString args_str;
784 
785   args.get("node", &node);
786   args.get("args", args_str);
787 
788   int result = m_mgmsrv.dumpState(node, args_str.c_str());
789   m_output->println("dump state reply");
790   if(result != 0)
791     m_output->println("result: %s", get_error_text(result));
792   else
793     m_output->println("result: Ok");
794   m_output->println("%s", "");
795 }
796 
797 
798 void
bye(Parser<MgmApiSession>::Context &,Properties const &)799 MgmApiSession::bye(Parser<MgmApiSession>::Context &,
800                    Properties const &) {
801   m_stop = true;
802 }
803 
804 void
endSession(Parser<MgmApiSession>::Context &,Properties const &)805 MgmApiSession::endSession(Parser<MgmApiSession>::Context &,
806                           Properties const &) {
807   if(m_allocated_resources)
808     delete m_allocated_resources;
809 
810   m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv);
811 
812   SLEEP_ERROR_INSERTED(4);
813   m_output->println("end session reply");
814 }
815 
816 void
getClusterLogLevel(Parser<MgmApiSession>::Context &,Properties const &)817 MgmApiSession::getClusterLogLevel(Parser<MgmApiSession>::Context &			, Properties const &) {
818   const char* names[] = { "startup",
819 			  "shutdown",
820 			  "statistics",
821 			  "checkpoint",
822 			  "noderestart",
823 			  "connection",
824 			  "info",
825 			  "warning",
826 			  "error",
827 			  "congestion",
828 			  "debug",
829 			  "backup" };
830 
831   int loglevel_count = (CFG_MAX_LOGLEVEL - CFG_MIN_LOGLEVEL + 1) ;
832   LogLevel::EventCategory category;
833 
834   m_output->println("get cluster loglevel");
835   for(int i = 0; i < loglevel_count; i++) {
836     category = (LogLevel::EventCategory) i;
837     m_output->println("%s: %d", names[i], m_mgmsrv.m_event_listner[0].m_logLevel.getLogLevel(category));
838   }
839   m_output->println("%s", "");
840 }
841 
842 void
setClusterLogLevel(Parser<MgmApiSession>::Context &,Properties const & args)843 MgmApiSession::setClusterLogLevel(Parser<MgmApiSession>::Context &,
844 				  Properties const &args) {
845   Uint32 node, level, cat;
846   BaseString errorString;
847   DBUG_ENTER("MgmApiSession::setClusterLogLevel");
848   args.get("node", &node);
849   args.get("category", &cat);
850   args.get("level", &level);
851 
852   DBUG_PRINT("enter",("node=%d, category=%d, level=%d", node, cat, level));
853 
854   m_output->println("set cluster loglevel reply");
855 
856   if(level > NDB_MGM_MAX_LOGLEVEL) {
857     m_output->println("result: Invalid loglevel %d", level);
858     m_output->println("%s", "");
859     DBUG_VOID_RETURN;
860   }
861 
862   LogLevel::EventCategory category=
863     (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
864 
865   m_mgmsrv.m_event_listner.lock();
866   if (m_mgmsrv.m_event_listner[0].m_logLevel.setLogLevel(category,level))
867   {
868     m_output->println("result: Invalid category %d", category);
869     m_output->println("%s", "");
870     m_mgmsrv.m_event_listner.unlock();
871     DBUG_VOID_RETURN;
872   }
873   m_mgmsrv.m_event_listner.unlock();
874 
875   {
876     LogLevel tmp;
877     m_mgmsrv.m_event_listner.update_max_log_level(tmp);
878   }
879 
880   m_output->println("result: Ok");
881   m_output->println("%s", "");
882   DBUG_VOID_RETURN;
883 }
884 
885 void
setLogLevel(Parser<MgmApiSession>::Context &,Properties const & args)886 MgmApiSession::setLogLevel(Parser<MgmApiSession>::Context &,
887 			   Properties const &args) {
888   Uint32 node = 0, level = 0, cat;
889   BaseString errorString;
890   SetLogLevelOrd logLevel;
891   logLevel.clear();
892   args.get("node", &node);
893   args.get("category", &cat);
894   args.get("level", &level);
895 
896   if(level > NDB_MGM_MAX_LOGLEVEL) {
897     m_output->println("set loglevel reply");
898     m_output->println("result: Invalid loglevel: %s", errorString.c_str());
899     m_output->println("%s", "");
900     return;
901   }
902 
903   LogLevel::EventCategory category=
904     (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
905 
906   {
907     LogLevel ll;
908     ll.setLogLevel(category,level);
909     m_mgmsrv.m_event_listner.update_max_log_level(ll);
910   }
911 
912   m_output->println("set loglevel reply");
913   m_output->println("result: Ok");
914   m_output->println("%s", "");
915 }
916 
917 void
stopSignalLog(Parser<MgmApiSession>::Context &,Properties const & args)918 MgmApiSession::stopSignalLog(Parser<MgmApiSession>::Context &,
919 			     Properties const &args) {
920   Uint32 node;
921 
922   args.get("node", &node);
923 
924   int result = m_mgmsrv.stopSignalTracing(node);
925 
926   m_output->println("stop signallog");
927   if(result != 0)
928     m_output->println("result: %s", get_error_text(result));
929   else
930     m_output->println("result: Ok");
931   m_output->println("%s", "");
932 }
933 
934 void
restart_v1(Parser<MgmApiSession>::Context &,Properties const & args)935 MgmApiSession::restart_v1(Parser<MgmApiSession>::Context &,
936 		       Properties const &args) {
937   restart(args,1);
938 }
939 
940 void
restart_v2(Parser<MgmApiSession>::Context &,Properties const & args)941 MgmApiSession::restart_v2(Parser<MgmApiSession>::Context &,
942 		       Properties const &args) {
943   restart(args,2);
944 }
945 
946 void
restart(Properties const & args,int version)947 MgmApiSession::restart(Properties const &args, int version) {
948   Uint32
949     nostart = 0,
950     initialstart = 0,
951     abort = 0, force = 0;
952   char *nodes_str;
953   Vector<NodeId> nodes;
954 
955   args.get("initialstart", &initialstart);
956   args.get("nostart", &nostart);
957   args.get("abort", &abort);
958   args.get("node", (const char **)&nodes_str);
959   args.get("force", &force);
960 
961   char *p, *last;
962   for((p = strtok_r(nodes_str, " ", &last));
963       p;
964       (p = strtok_r(NULL, " ", &last))) {
965     nodes.push_back(atoi(p));
966   }
967 
968   int restarted = 0;
969   int result= m_mgmsrv.restartNodes(nodes,
970                                     &restarted,
971                                     nostart != 0,
972                                     initialstart != 0,
973                                     abort != 0,
974                                     force != 0,
975                                     &m_stopSelf);
976 
977   if (force &&
978       (result == NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH ||
979        result == UNSUPPORTED_NODE_SHUTDOWN))
980   {
981     // Force restart by restarting all nodes
982     result = m_mgmsrv.restartDB(nostart, initialstart, false, &restarted);
983   }
984 
985   m_output->println("restart reply");
986   if(result != 0){
987     m_output->println("result: %d-%s", result, get_error_text(result));
988   } else
989     m_output->println("result: Ok");
990   m_output->println("restarted: %d", restarted);
991   if(version>1)
992     m_output->println("disconnect: %d", (m_stopSelf)?1:0);
993   m_output->println("%s", "");
994 }
995 
996 void
restartAll(Parser<MgmApiSession>::Context &,Properties const & args)997 MgmApiSession::restartAll(Parser<MgmApiSession>::Context &,
998 			  Properties const &args)
999 {
1000   Uint32 nostart = 0;
1001   Uint32 initialstart = 0;
1002   Uint32 abort = 0;
1003 
1004   args.get("initialstart", &initialstart);
1005   args.get("abort", &abort);
1006   args.get("nostart", &nostart);
1007 
1008   int count = 0;
1009   int result = m_mgmsrv.restartDB(nostart, initialstart, abort, &count);
1010 
1011   m_output->println("restart reply");
1012   if(result != 0)
1013     m_output->println("result: %s", get_error_text(result));
1014   else
1015     m_output->println("result: Ok");
1016   m_output->println("restarted: %d", count);
1017   m_output->println("%s", "");
1018 }
1019 
1020 static void
printNodeStatus(OutputStream * output,MgmtSrvr & mgmsrv,enum ndb_mgm_node_type type)1021 printNodeStatus(OutputStream *output,
1022 		MgmtSrvr &mgmsrv,
1023 		enum ndb_mgm_node_type type) {
1024   NodeId nodeId = 0;
1025   while(mgmsrv.getNextNodeId(&nodeId, type)) {
1026     enum ndb_mgm_node_status status;
1027     Uint32 startPhase = 0,
1028       version = 0, mysql_version = 0,
1029       dynamicId = 0,
1030       nodeGroup = 0,
1031       connectCount = 0;
1032     bool system;
1033     const char *address= NULL;
1034     mgmsrv.status(nodeId, &status, &version, &mysql_version, &startPhase,
1035 		  &system, &dynamicId, &nodeGroup, &connectCount,
1036 		  &address);
1037     output->println("node.%d.type: %s",
1038 		      nodeId,
1039 		      ndb_mgm_get_node_type_string(type));
1040     output->println("node.%d.status: %s",
1041 		      nodeId,
1042 		    ndb_mgm_get_node_status_string(status));
1043     output->println("node.%d.version: %d", nodeId, version);
1044     output->println("node.%d.mysql_version: %d", nodeId, mysql_version);
1045     output->println("node.%d.startphase: %d", nodeId, startPhase);
1046     output->println("node.%d.dynamic_id: %d", nodeId, dynamicId);
1047     output->println("node.%d.node_group: %d", nodeId, nodeGroup);
1048     output->println("node.%d.connect_count: %d", nodeId, connectCount);
1049     output->println("node.%d.address: %s", nodeId, address ? address : "");
1050   }
1051 }
1052 
1053 void
getStatus(Parser<MgmApiSession>::Context &,Properties const & args)1054 MgmApiSession::getStatus(Parser<MgmApiSession>::Context &,
1055 			 Properties const & args) {
1056   Uint32 i;
1057   int noOfNodes = 0;
1058   BaseString typestring;
1059 
1060   enum ndb_mgm_node_type types[10];
1061   if (args.get("types", typestring))
1062   {
1063     Vector<BaseString> tmp;
1064     typestring.split(tmp, " ");
1065     for (i = 0; i < tmp.size(); i++)
1066     {
1067       types[i] = ndb_mgm_match_node_type(tmp[i].c_str());
1068     }
1069     types[i] = NDB_MGM_NODE_TYPE_UNKNOWN;
1070   }
1071   else
1072   {
1073     types[0] = NDB_MGM_NODE_TYPE_NDB;
1074     types[1] = NDB_MGM_NODE_TYPE_MGM;
1075     types[2] = NDB_MGM_NODE_TYPE_API;
1076     types[3] = NDB_MGM_NODE_TYPE_UNKNOWN;
1077   }
1078 
1079   for (i = 0; types[i] != NDB_MGM_NODE_TYPE_UNKNOWN; i++)
1080   {
1081     NodeId nodeId = 0;
1082     while(m_mgmsrv.getNextNodeId(&nodeId, types[i]))
1083       noOfNodes++;
1084   }
1085 
1086   SLEEP_ERROR_INSERTED(5);
1087   m_output->println("node status");
1088   SLEEP_ERROR_INSERTED(6);
1089   m_output->println("nodes: %d", noOfNodes);
1090   for (i = 0; types[i] != NDB_MGM_NODE_TYPE_UNKNOWN; i++)
1091   {
1092     SLEEP_ERROR_INSERTED(int(7+i));
1093     printNodeStatus(m_output, m_mgmsrv, types[i]);
1094   }
1095   m_output->println("%s", "");
1096 }
1097 
1098 
1099 static bool
isEventLogFilterEnabled(int severity)1100 isEventLogFilterEnabled(int severity)
1101 {
1102   return g_eventLogger->isEnable((Logger::LoggerLevel)severity);
1103 }
1104 
1105 void
getInfoClusterLog(Parser<MgmApiSession>::Context &,Properties const &)1106 MgmApiSession::getInfoClusterLog(Parser<MgmApiSession>::Context &,
1107 		    Properties const &) {
1108   const char* names[] = { "enabled",
1109 			  "debug",
1110 			  "info",
1111 			  "warning",
1112 			  "error",
1113 			  "critical",
1114 			  "alert" };
1115 
1116   m_output->println("clusterlog");
1117   for(int i = 0; i < 7; i++) {
1118     m_output->println("%s: %d",
1119                       names[i],
1120                       isEventLogFilterEnabled(i));
1121   }
1122   m_output->println("%s", "");
1123 }
1124 
1125 void
stop_v1(Parser<MgmApiSession>::Context &,Properties const & args)1126 MgmApiSession::stop_v1(Parser<MgmApiSession>::Context &,
1127                        Properties const &args) {
1128   stop(args,1);
1129 }
1130 
1131 void
stop_v2(Parser<MgmApiSession>::Context &,Properties const & args)1132 MgmApiSession::stop_v2(Parser<MgmApiSession>::Context &,
1133                        Properties const &args) {
1134   stop(args,2);
1135 }
1136 
1137 void
stop(Properties const & args,int version)1138 MgmApiSession::stop(Properties const &args, int version) {
1139   Uint32 abort, force = 0;
1140   char *nodes_str;
1141   Vector<NodeId> nodes;
1142 
1143   args.get("node", (const char **)&nodes_str);
1144   if(nodes_str == NULL)
1145   {
1146     m_output->println("stop reply");
1147     m_output->println("result: empty node list");
1148     m_output->println("%s", "");
1149     return;
1150   }
1151   args.get("abort", &abort);
1152   args.get("force", &force);
1153 
1154   char *p, *last;
1155   for((p = strtok_r(nodes_str, " ", &last));
1156       p;
1157       (p = strtok_r(NULL, " ", &last))) {
1158     nodes.push_back(atoi(p));
1159   }
1160 
1161   int stopped= 0;
1162   int result= 0;
1163   if (nodes.size())
1164   {
1165     result= m_mgmsrv.stopNodes(nodes, &stopped, abort != 0, force != 0,
1166                                &m_stopSelf);
1167 
1168     if (force &&
1169         (result == NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH ||
1170          result == UNSUPPORTED_NODE_SHUTDOWN))
1171     {
1172       // Force stop and shutdown all remaining nodes
1173       result = m_mgmsrv.shutdownDB(&stopped, false);
1174     }
1175   }
1176 
1177   m_output->println("stop reply");
1178   if(result != 0)
1179     m_output->println("result: %s", get_error_text(result));
1180   else
1181     m_output->println("result: Ok");
1182   m_output->println("stopped: %d", stopped);
1183   if(version>1)
1184     m_output->println("disconnect: %d", (m_stopSelf)?1:0);
1185   m_output->println("%s", "");
1186 }
1187 
1188 void
stopAll(Parser<MgmApiSession>::Context &,Properties const & args)1189 MgmApiSession::stopAll(Parser<MgmApiSession>::Context &,
1190                        Properties const &args) {
1191   int stopped[2] = {0,0};
1192   Uint32 abort;
1193   args.get("abort", &abort);
1194 
1195   BaseString stop;
1196   const char* tostop= "db";
1197   int ver=1;
1198   if (args.get("stop", stop))
1199   {
1200     tostop= stop.c_str();
1201     ver= 2;
1202   }
1203 
1204   int result= 0;
1205   if(strstr(tostop,"db"))
1206     result= m_mgmsrv.shutdownDB(&stopped[0], abort != 0);
1207   if(!result && strstr(tostop,"mgm"))
1208     result= m_mgmsrv.shutdownMGM(&stopped[1], abort!=0, &m_stopSelf);
1209 
1210   m_output->println("stop reply");
1211   if(result != 0)
1212     m_output->println("result: %s", get_error_text(result));
1213   else
1214     m_output->println("result: Ok");
1215   m_output->println("stopped: %d", stopped[0]+stopped[1]);
1216   if(ver >1)
1217     m_output->println("disconnect: %d", (m_stopSelf)?1:0);
1218   m_output->println("%s", "");
1219 }
1220 
1221 void
enterSingleUser(Parser<MgmApiSession>::Context &,Properties const & args)1222 MgmApiSession::enterSingleUser(Parser<MgmApiSession>::Context &,
1223 			  Properties const &args) {
1224   int stopped = 0;
1225   Uint32 nodeId = 0;
1226   int result= 0;
1227   args.get("nodeId", &nodeId);
1228 
1229   result = m_mgmsrv.enterSingleUser(&stopped, nodeId);
1230   m_output->println("enter single user reply");
1231   if(result != 0) {
1232     m_output->println("result: %s", get_error_text(result));
1233   }
1234   else {
1235     m_output->println("result: Ok");
1236   }
1237   m_output->println("%s", "");
1238 }
1239 
1240 void
exitSingleUser(Parser<MgmApiSession>::Context &,Properties const & args)1241 MgmApiSession::exitSingleUser(Parser<MgmApiSession>::Context &,
1242 			      Properties const &args) {
1243   int stopped = 0;
1244   int result = m_mgmsrv.exitSingleUser(&stopped, false);
1245   m_output->println("exit single user reply");
1246   if(result != 0)
1247     m_output->println("result: %s", get_error_text(result));
1248   else
1249     m_output->println("result: Ok");
1250   m_output->println("%s", "");
1251 }
1252 
1253 
1254 void
startSignalLog(Parser<MgmApiSession>::Context &,Properties const & args)1255 MgmApiSession::startSignalLog(Parser<MgmApiSession>::Context &,
1256 			      Properties const &args) {
1257   Uint32 node;
1258 
1259   args.get("node", &node);
1260 
1261   int result = m_mgmsrv.startSignalTracing(node);
1262 
1263   m_output->println("start signallog reply");
1264   if(result != 0)
1265     m_output->println("result: %s", get_error_text(result));
1266   else
1267     m_output->println("result: Ok");
1268   m_output->println("%s", "");
1269 }
1270 
1271 void
logSignals(Parser<MgmApiSession>::Context &,Properties const & args)1272 MgmApiSession::logSignals(Parser<MgmApiSession>::Context &,
1273 			   Properties const &args) {
1274   Uint32 node = 0, in = 0, out = 0;
1275   //  BaseString blocks;
1276   BaseString blockList;
1277   char * blockName;
1278   args.get("node", &node);
1279   args.get("in", &in);
1280   args.get("out", &out);
1281   args.get("blocks", blockList);
1282   // fast fix - pekka
1283   char buf[200];
1284   BaseString::snprintf(buf, 200, "%s", blockList.c_str());
1285   Vector<BaseString> blocks;
1286 
1287   blockName=strtok(buf,"|");
1288   while( blockName != NULL)
1289     {
1290       blocks.push_back(blockName);
1291       blockName=strtok(NULL,"|");
1292     }
1293 
1294 
1295   if(in > 1 || out > 1)
1296     return; /* Invalid arguments */
1297 
1298   const MgmtSrvr::LogMode modes[] = {
1299     MgmtSrvr::Off,
1300     MgmtSrvr::Out,
1301     MgmtSrvr::In,
1302     MgmtSrvr::InOut,
1303   };
1304   MgmtSrvr::LogMode mode = modes[in<<1 | out];
1305 
1306   int result = m_mgmsrv.setSignalLoggingMode(node, mode, blocks);
1307 
1308   m_output->println("log signals reply");
1309   if(result != 0)
1310     m_output->println("result: %s", get_error_text(result));
1311   else
1312     m_output->println("result: Ok");
1313   m_output->println("%s", "");
1314 }
1315 
1316 void
start(Parser<MgmApiSession>::Context &,Properties const & args)1317 MgmApiSession::start(Parser<MgmApiSession>::Context &,
1318 		     Properties const &args) {
1319   Uint32 node;
1320 
1321   args.get("node", &node);
1322 
1323   int result = m_mgmsrv.start(node);
1324 
1325   m_output->println("start reply");
1326   if(result != 0)
1327     m_output->println("result: %s", get_error_text(result));
1328   else
1329     m_output->println("result: Ok");
1330   m_output->println("%s", "");
1331 }
1332 
1333 void
startAll(Parser<MgmApiSession>::Context &,Properties const &)1334 MgmApiSession::startAll(Parser<MgmApiSession>::Context &,
1335 			Properties const &) {
1336   NodeId node = 0;
1337   int started = 0;
1338 
1339   while(m_mgmsrv.getNextNodeId(&node, NDB_MGM_NODE_TYPE_NDB))
1340     if(m_mgmsrv.start(node) == 0)
1341       started++;
1342 
1343   m_output->println("start reply");
1344   m_output->println("result: Ok");
1345   m_output->println("started: %d", started);
1346   m_output->println("%s", "");
1347 }
1348 
1349 
1350 static bool
setEventLogFilter(int severity,int enable)1351 setEventLogFilter(int severity, int enable)
1352 {
1353   Logger::LoggerLevel level = (Logger::LoggerLevel)severity;
1354   if (enable > 0) {
1355     g_eventLogger->enable(level);
1356   } else if (enable == 0) {
1357     g_eventLogger->disable(level);
1358   }
1359   else
1360   {
1361     /* enable is < 0 => toggle the filter value */
1362     if (g_eventLogger->isEnable(level))
1363       g_eventLogger->disable(level);
1364     else
1365       g_eventLogger->enable(level);
1366   }
1367   return g_eventLogger->isEnable(level);
1368 }
1369 
1370 
1371 void
setLogFilter(Parser_t::Context & ctx,const class Properties & args)1372 MgmApiSession::setLogFilter(Parser_t::Context &ctx,
1373 			    const class Properties &args) {
1374   Uint32 severity;
1375   Uint32 enable;
1376 
1377   args.get("level", &severity);
1378   args.get("enable", &enable);
1379 
1380   bool result = setEventLogFilter(severity, enable);
1381 
1382   m_output->println("set logfilter reply");
1383   m_output->println("result: %d", result);
1384   m_output->println("%s", "");
1385 }
1386 
1387 #ifdef NOT_USED
1388 
1389 static NdbOut&
operator <<(NdbOut & out,const LogLevel & ll)1390 operator<<(NdbOut& out, const LogLevel & ll)
1391 {
1392   out << "[LogLevel: ";
1393   for(size_t i = 0; i<LogLevel::LOGLEVEL_CATEGORIES; i++)
1394     out << ll.getLogLevel((LogLevel::EventCategory)i) << " ";
1395   out << "]";
1396   return out;
1397 }
1398 #endif
1399 
1400 
1401 static void
logevent2str(BaseString & str,int eventType,const Uint32 * theData,Uint32 len,NodeId nodeId,Uint32 timeval,char * pretty_text,size_t pretty_text_size)1402 logevent2str(BaseString& str, int eventType,
1403              const Uint32* theData,
1404              Uint32 len,
1405              NodeId nodeId, Uint32 timeval,
1406              char* pretty_text, size_t pretty_text_size)
1407 {
1408   str.assign("log event reply\n");
1409   str.appfmt("type=%d\n", eventType);
1410   str.appfmt("time=%d\n", timeval);
1411   str.appfmt("source_nodeid=%d\n", nodeId);
1412   unsigned i;
1413   for (i = 0; ndb_logevent_body[i].token; i++)
1414   {
1415     if ( ndb_logevent_body[i].type == eventType)
1416       break;
1417   }
1418 
1419   if (ndb_logevent_body[i].token)
1420   {
1421     do {
1422       int val= theData[ndb_logevent_body[i].index];
1423       if (ndb_logevent_body[i].index_fn)
1424         val= (*(ndb_logevent_body[i].index_fn))(val);
1425       str.appfmt("%s=%d\n",ndb_logevent_body[i].token, val);
1426       if(strcmp(ndb_logevent_body[i].token,"error") == 0)
1427       {
1428         int pretty_text_len= strlen(pretty_text);
1429         if(pretty_text_size-pretty_text_len-3 > 0)
1430         {
1431           BaseString::snprintf(pretty_text+pretty_text_len, 4 , " - ");
1432           ndb_error_string(val, pretty_text+(pretty_text_len+3),
1433                            pretty_text_size-pretty_text_len-3);
1434         }
1435       }
1436     } while (ndb_logevent_body[++i].type == eventType);
1437   }
1438   else
1439   {
1440     str.append("data=");
1441     for (i = 1; i<len; i++)
1442       str.appfmt("%u ", theData[i]);
1443     str.append("\n");
1444   }
1445 }
1446 
1447 
1448 void
log(int eventType,const Uint32 * theData,Uint32 len,NodeId nodeId)1449 Ndb_mgmd_event_service::log(int eventType, const Uint32* theData,
1450 			    Uint32 len, NodeId nodeId){
1451 
1452   Uint32 threshold;
1453   LogLevel::EventCategory cat;
1454   Logger::LoggerLevel severity;
1455   EventLoggerBase::EventTextFunction textF;
1456   int i, n;
1457   DBUG_ENTER("Ndb_mgmd_event_service::log");
1458   DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
1459 
1460   if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
1461     DBUG_VOID_RETURN;
1462 
1463   // Generate the message for pretty format clients
1464   char pretty_text[512];
1465   EventLogger::getText(pretty_text, sizeof(pretty_text),
1466 		       textF, theData, len, nodeId);
1467 
1468   // Generate the message for parseable format clients
1469   // and if there is a field named "error" append the ndb_error_string
1470   // for that error number to the end of the pretty format message
1471   BaseString str;
1472   logevent2str(str, eventType, theData, len, nodeId, 0,
1473                pretty_text, sizeof(pretty_text));
1474 
1475   Vector<NDB_SOCKET_TYPE> copy;
1476   m_clients.lock();
1477   for(i = m_clients.size() - 1; i >= 0; i--)
1478   {
1479     if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat))
1480     {
1481       if(!my_socket_valid(m_clients[i].m_socket))
1482         continue;
1483 
1484       SocketOutputStream out(m_clients[i].m_socket);
1485 
1486       int r;
1487       if (m_clients[i].m_parsable)
1488         r= out.println(str.c_str());
1489       else
1490         r= out.println(pretty_text);
1491 
1492       if (r<0)
1493       {
1494         copy.push_back(m_clients[i].m_socket);
1495         m_clients.erase(i, false);
1496       }
1497     }
1498   }
1499   m_clients.unlock();
1500 
1501   if ((n= (int)copy.size()))
1502   {
1503     for(i= 0; i < n; i++)
1504       NDB_CLOSE_SOCKET(copy[i]);
1505 
1506     LogLevel tmp; tmp.clear();
1507     m_clients.lock();
1508     for(i= m_clients.size() - 1; i >= 0; i--)
1509       tmp.set_max(m_clients[i].m_logLevel);
1510     m_clients.unlock();
1511     update_log_level(tmp);
1512   }
1513   DBUG_VOID_RETURN;
1514 }
1515 
1516 void
update_max_log_level(const LogLevel & log_level)1517 Ndb_mgmd_event_service::update_max_log_level(const LogLevel &log_level)
1518 {
1519   LogLevel tmp = log_level;
1520   m_clients.lock();
1521   for(int i = m_clients.size() - 1; i >= 0; i--)
1522     tmp.set_max(m_clients[i].m_logLevel);
1523   m_clients.unlock();
1524   update_log_level(tmp);
1525 }
1526 
1527 void
update_log_level(const LogLevel & tmp)1528 Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp)
1529 {
1530   m_logLevel = tmp;
1531   EventSubscribeReq req;
1532   req.assign(tmp);
1533   // send update to all nodes
1534   req.blockRef = 0;
1535   m_mgmsrv->m_log_level_requests.push_back(req);
1536 }
1537 
1538 void
check_listeners()1539 Ndb_mgmd_event_service::check_listeners()
1540 {
1541   int i, n= 0;
1542   DBUG_ENTER("Ndb_mgmd_event_service::check_listeners");
1543   m_clients.lock();
1544   for(i= m_clients.size() - 1; i >= 0; i--)
1545   {
1546     if(!my_socket_valid(m_clients[i].m_socket))
1547       continue;
1548 
1549     SocketOutputStream out(m_clients[i].m_socket);
1550 
1551     DBUG_PRINT("info",("%d " MY_SOCKET_FORMAT,
1552                        i,
1553                        MY_SOCKET_FORMAT_VALUE(m_clients[i].m_socket)));
1554 
1555     if(out.println("<PING>") < 0)
1556     {
1557       NDB_CLOSE_SOCKET(m_clients[i].m_socket);
1558       m_clients.erase(i, false);
1559       n=1;
1560     }
1561   }
1562   if (n)
1563   {
1564     LogLevel tmp; tmp.clear();
1565     for(i= m_clients.size() - 1; i >= 0; i--)
1566       tmp.set_max(m_clients[i].m_logLevel);
1567     update_log_level(tmp);
1568   }
1569   m_clients.unlock();
1570   DBUG_VOID_RETURN;
1571 }
1572 
1573 void
add_listener(const Event_listener & client)1574 Ndb_mgmd_event_service::add_listener(const Event_listener& client)
1575 {
1576   DBUG_ENTER("Ndb_mgmd_event_service::add_listener");
1577   DBUG_PRINT("enter",("client.m_socket: " MY_SOCKET_FORMAT,
1578                       MY_SOCKET_FORMAT_VALUE(client.m_socket)));
1579 
1580   check_listeners();
1581 
1582   m_clients.push_back(client);
1583   update_max_log_level(client.m_logLevel);
1584 
1585   DBUG_VOID_RETURN;
1586 }
1587 
1588 void
stop_sessions()1589 Ndb_mgmd_event_service::stop_sessions(){
1590   m_clients.lock();
1591   for(int i = m_clients.size() - 1; i >= 0; i--){
1592     if(my_socket_valid(m_clients[i].m_socket))
1593     {
1594       NDB_CLOSE_SOCKET(m_clients[i].m_socket);
1595       m_clients.erase(i);
1596     }
1597   }
1598   m_clients.unlock();
1599 }
1600 
1601 void
setParameter(Parser_t::Context &,Properties const & args)1602 MgmApiSession::setParameter(Parser_t::Context &,
1603 			    Properties const &args)
1604 {
1605   Uint32 node, param;
1606   BaseString value;
1607   args.get("node", &node);
1608   args.get("parameter", &param);
1609   args.get("value", value);
1610 
1611   BaseString result;
1612   int ret = m_mgmsrv.setDbParameter(node,
1613 				    param,
1614 				    value.c_str(),
1615 				    result);
1616 
1617   m_output->println("set parameter reply");
1618   m_output->println("message: %s", result.c_str());
1619   m_output->println("result: %d", ret);
1620   m_output->println("%s", "");
1621 }
1622 
1623 void
setConnectionParameter(Parser_t::Context & ctx,Properties const & args)1624 MgmApiSession::setConnectionParameter(Parser_t::Context &ctx,
1625 				      Properties const &args)
1626 {
1627   Uint32 node1, node2, param, value;
1628   args.get("node1", &node1);
1629   args.get("node2", &node2);
1630   args.get("param", &param);
1631   args.get("value", &value);
1632 
1633   BaseString result;
1634   int ret = m_mgmsrv.setConnectionDbParameter(node1,
1635 					      node2,
1636 					      param,
1637 					      value,
1638 					      result);
1639 
1640   m_output->println("set connection parameter reply");
1641   m_output->println("message: %s", result.c_str());
1642   m_output->println("result: %s", (ret>0)?"Ok":"Failed");
1643   m_output->println("%s", "");
1644 }
1645 
1646 void
getConnectionParameter(Parser_t::Context & ctx,Properties const & args)1647 MgmApiSession::getConnectionParameter(Parser_t::Context &ctx,
1648 				      Properties const &args)
1649 {
1650   Uint32 node1, node2, param;
1651   int value = 0;
1652 
1653   args.get("node1", &node1);
1654   args.get("node2", &node2);
1655   args.get("param", &param);
1656 
1657   BaseString result;
1658   int ret = m_mgmsrv.getConnectionDbParameter(node1,
1659 					      node2,
1660 					      param,
1661 					      &value,
1662 					      result);
1663 
1664   m_output->println("get connection parameter reply");
1665   m_output->println("value: %d", value);
1666   m_output->println("result: %s", (ret>0)?"Ok":result.c_str());
1667   m_output->println("%s", "");
1668 }
1669 
1670 void
listen_event(Parser<MgmApiSession>::Context & ctx,Properties const & args)1671 MgmApiSession::listen_event(Parser<MgmApiSession>::Context & ctx,
1672 			    Properties const & args) {
1673   Uint32 parsable= 0;
1674   BaseString node, param, value;
1675   args.get("node", node);
1676   args.get("filter", param);
1677   args.get("parsable", &parsable);
1678 
1679   int result = 0;
1680   BaseString msg;
1681 
1682   Ndb_mgmd_event_service::Event_listener le;
1683   le.m_parsable = parsable;
1684   le.m_socket = m_socket;
1685 
1686   Vector<BaseString> list;
1687   param.trim();
1688   param.split(list, " ,");
1689   for(size_t i = 0; i<list.size(); i++){
1690     Vector<BaseString> spec;
1691     list[i].trim();
1692     list[i].split(spec, "=:");
1693     if(spec.size() != 2){
1694       msg.appfmt("Invalid filter specification: >%s< >%s< %d",
1695 		 param.c_str(), list[i].c_str(), spec.size());
1696       result = -1;
1697       goto done;
1698     }
1699 
1700     spec[0].trim().ndb_toupper();
1701     int category = ndb_mgm_match_event_category(spec[0].c_str());
1702     if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
1703       category = atoi(spec[0].c_str());
1704       if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
1705 	 category > NDB_MGM_MAX_EVENT_CATEGORY){
1706 	msg.appfmt("Unknown category: >%s<", spec[0].c_str());
1707 	result = -1;
1708 	goto done;
1709       }
1710     }
1711 
1712     int level = atoi(spec[1].c_str());
1713     if(level < 0 || level > NDB_MGM_MAX_LOGLEVEL){
1714       msg.appfmt("Invalid level: >%s<", spec[1].c_str());
1715       result = -1;
1716       goto done;
1717     }
1718     category -= CFG_MIN_LOGLEVEL;
1719     le.m_logLevel.setLogLevel((LogLevel::EventCategory)category, level);
1720   }
1721 
1722   if(list.size() == 0){
1723     msg.appfmt("Empty filter specification");
1724     result = -1;
1725     goto done;
1726   }
1727 
1728 done:
1729   m_output->println("listen event");
1730   m_output->println("result: %d", result);
1731   if(result != 0)
1732     m_output->println("msg: %s", msg.c_str());
1733   m_output->println("%s", "");
1734 
1735   if(result==0)
1736   {
1737     m_mgmsrv.m_event_listner.add_listener(le);
1738     m_stop = true;
1739     my_socket_invalidate(&m_socket);
1740   }
1741 }
1742 
1743 void
stop_session_if_not_connected(SocketServer::Session * _s,void * data)1744 MgmApiSession::stop_session_if_not_connected(SocketServer::Session *_s, void *data)
1745 {
1746   MgmApiSession *s= (MgmApiSession *)_s;
1747   struct PurgeStruct &ps= *(struct PurgeStruct *)data;
1748   if (s->m_allocated_resources->is_reserved(ps.free_nodes))
1749   {
1750     if (ps.str)
1751       ps.str->appfmt(" %d", s->m_allocated_resources->get_nodeid());
1752     s->stopSession();
1753   }
1754 }
1755 
1756 void
stop_session_if_timed_out(SocketServer::Session * _s,void * data)1757 MgmApiSession::stop_session_if_timed_out(SocketServer::Session *_s, void *data)
1758 {
1759   MgmApiSession *s= (MgmApiSession *)_s;
1760   struct PurgeStruct &ps= *(struct PurgeStruct *)data;
1761   if (s->m_allocated_resources->is_reserved(ps.free_nodes) &&
1762       s->m_allocated_resources->is_timed_out(ps.tick))
1763   {
1764     s->stopSession();
1765   }
1766 }
1767 
1768 void
purge_stale_sessions(Parser_t::Context & ctx,const class Properties & args)1769 MgmApiSession::purge_stale_sessions(Parser_t::Context &ctx,
1770 				    const class Properties &args)
1771 {
1772   struct PurgeStruct ps;
1773   BaseString str;
1774   ps.str = &str;
1775 
1776   m_mgmsrv.get_connected_nodes(ps.free_nodes);
1777   ps.free_nodes.bitXORC(NodeBitmask()); // invert connected_nodes to get free nodes
1778 
1779   m_mgmsrv.get_socket_server()->foreachSession(stop_session_if_not_connected,&ps);
1780   m_mgmsrv.get_socket_server()->checkSessions();
1781 
1782   m_output->println("purge stale sessions reply");
1783   if (str.length() > 0)
1784     m_output->println("purged:%s",str.c_str());
1785   m_output->println("result: Ok");
1786   m_output->println("%s", "");
1787 }
1788 
1789 void
check_connection(Parser_t::Context & ctx,const class Properties & args)1790 MgmApiSession::check_connection(Parser_t::Context &ctx,
1791 				const class Properties &args)
1792 {
1793   SLEEP_ERROR_INSERTED(1);
1794   m_output->println("check connection reply");
1795   SLEEP_ERROR_INSERTED(2);
1796   m_output->println("result: Ok");
1797   SLEEP_ERROR_INSERTED(3);
1798   m_output->println("%s", "");
1799 }
1800 
1801 void
transporter_connect(Parser_t::Context & ctx,Properties const & args)1802 MgmApiSession::transporter_connect(Parser_t::Context &ctx,
1803 				   Properties const &args)
1804 {
1805   BaseString errormsg;
1806   if (!m_mgmsrv.transporter_connect(m_socket, errormsg))
1807   {
1808     // Connection not allowed or failed
1809     g_eventLogger->warning("Failed to convert connection "
1810                            "from '%s' to transporter: %s",
1811                            name(),
1812                            errormsg.c_str());
1813     // Close the socket to indicate failure to other side
1814   }
1815   else
1816   {
1817     /*
1818       Conversion to transporter suceeded
1819       Stop this session thread and release resources
1820       but don't close the socket, it's been taken over
1821       by the transporter
1822     */
1823     my_socket_invalidate(&m_socket);   // so nobody closes it
1824   }
1825 
1826   m_stop= true; // Stop the session
1827 }
1828 
1829 void
get_mgmd_nodeid(Parser_t::Context & ctx,Properties const & args)1830 MgmApiSession::get_mgmd_nodeid(Parser_t::Context &ctx,
1831 			       Properties const &args)
1832 {
1833   m_output->println("get mgmd nodeid reply");
1834   m_output->println("nodeid:%u",m_mgmsrv.getOwnNodeId());
1835   SLEEP_ERROR_INSERTED(1);
1836 
1837   m_output->println("%s", "");
1838 }
1839 
1840 void
report_event(Parser_t::Context & ctx,Properties const & args)1841 MgmApiSession::report_event(Parser_t::Context &ctx,
1842 			    Properties const &args)
1843 {
1844   Uint32 length;
1845   const char *data_string;
1846   Uint32 data[25];
1847 
1848   args.get("length", &length);
1849   args.get("data", &data_string);
1850 
1851   BaseString tmp(data_string);
1852   Vector<BaseString> item;
1853   tmp.split(item, " ");
1854   for (int i = 0; (Uint32) i < length ; i++)
1855   {
1856     sscanf(item[i].c_str(), "%u", data+i);
1857   }
1858 
1859   m_mgmsrv.eventReport(data, length);
1860   m_output->println("report event reply");
1861   m_output->println("result: ok");
1862   m_output->println("%s", "");
1863 }
1864 
1865 void
create_nodegroup(Parser_t::Context & ctx,Properties const & args)1866 MgmApiSession::create_nodegroup(Parser_t::Context &ctx,
1867                                 Properties const &args)
1868 {
1869   int res = 0;
1870   BaseString nodestr;
1871   BaseString retval;
1872   int ng = -1;
1873   Vector<int> nodes;
1874   BaseString result("Ok");
1875 
1876   args.get("nodes", nodestr);
1877   Vector<BaseString> list;
1878   nodestr.split(list, " ");
1879   for (Uint32 i = 0; i < list.size() ; i++)
1880   {
1881     int res;
1882     int node;
1883     if ((res = sscanf(list[i].c_str(), "%u", &node)) != 1)
1884     {
1885       nodes.clear();
1886       result = "FAIL: Invalid format for nodes";
1887       break;
1888     }
1889     nodes.push_back(node);
1890   }
1891 
1892   res = m_mgmsrv.createNodegroup(nodes.getBase(), nodes.size(), &ng);
1893 
1894   m_output->println("create nodegroup reply");
1895   m_output->println("ng: %d", ng);
1896   if (res)
1897   {
1898     m_output->println("error_code: %d", res);
1899     m_output->println("result: %d-%s", res, get_error_text(res));
1900   }
1901   else
1902   {
1903     m_output->println("result: Ok");
1904   }
1905   m_output->println("%s", "");
1906 }
1907 
1908 void
drop_nodegroup(Parser_t::Context & ctx,Properties const & args)1909 MgmApiSession::drop_nodegroup(Parser_t::Context &ctx,
1910                               Properties const &args)
1911 {
1912   BaseString result("Ok");
1913 
1914   unsigned ng;
1915   args.get("ng", &ng);
1916 
1917   int res;
1918   if((res = m_mgmsrv.dropNodegroup(ng)) != 0)
1919   {
1920     result.assfmt("error: %d", res);
1921   }
1922 
1923 //end:
1924   m_output->println("drop nodegroup reply");
1925   m_output->println("result: %s", result.c_str());
1926   m_output->println("%s", "");
1927 }
1928 
1929 void
list_session(SocketServer::Session * _s,void * data)1930 MgmApiSession::list_session(SocketServer::Session *_s, void *data)
1931 {
1932   MgmApiSession *s= (MgmApiSession *)_s;
1933   MgmApiSession *lister= (MgmApiSession*) data;
1934 
1935   if(s!=lister)
1936     NdbMutex_Lock(s->m_mutex);
1937 
1938   Uint64 id= s->m_session_id;
1939   lister->m_output->println("session: %llu",id);
1940   lister->m_output->println("session.%llu.m_stopSelf: %d",id,s->m_stopSelf);
1941   lister->m_output->println("session.%llu.m_stop: %d",id,s->m_stop);
1942   lister->m_output->println("session.%llu.allocated.nodeid: %d",id,s->m_allocated_resources->get_nodeid());
1943   if(s->m_ctx)
1944   {
1945     int l= strlen(s->m_ctx->m_tokenBuffer);
1946     char *buf= (char*) malloc(2*l+1);
1947     char *b= buf;
1948     for(int i=0; i<l;i++)
1949       if(s->m_ctx->m_tokenBuffer[i]=='\n')
1950       {
1951         *b++='\\';
1952         *b++='n';
1953       }
1954       else
1955       {
1956         *b++= s->m_ctx->m_tokenBuffer[i];
1957       }
1958     *b= '\0';
1959 
1960     lister->m_output->println("session.%llu.parser.buffer.len: %u",id,l);
1961     lister->m_output->println("session.%llu.parser.buffer: %s",id,buf);
1962     lister->m_output->println("session.%llu.parser.status: %d",id,s->m_ctx->m_status);
1963 
1964     free(buf);
1965   }
1966 
1967   if(s!=lister)
1968     NdbMutex_Unlock(s->m_mutex);
1969 }
1970 
1971 void
listSessions(Parser_t::Context & ctx,Properties const & args)1972 MgmApiSession::listSessions(Parser_t::Context &ctx,
1973                             Properties const &args) {
1974   m_mgmsrv.get_socket_server()->foreachSession(list_session,(void*)this);
1975 
1976   m_output->println("%s", "");
1977 }
1978 
1979 void
getSessionId(Parser_t::Context & ctx,Properties const & args)1980 MgmApiSession::getSessionId(Parser_t::Context &ctx,
1981                                  Properties const &args) {
1982   m_output->println("get session id reply");
1983   m_output->println("id: %llu",m_session_id);
1984   m_output->println("%s", "");
1985 }
1986 
1987 struct get_session_param {
1988   MgmApiSession *l;
1989   Uint64 id;
1990   int found;
1991 };
1992 
1993 void
get_session(SocketServer::Session * _s,void * data)1994 MgmApiSession::get_session(SocketServer::Session *_s, void *data)
1995 {
1996   struct get_session_param *p= (struct get_session_param*)data;
1997   MgmApiSession *s= (MgmApiSession *)_s;
1998 
1999   if(s!=p->l)
2000     NdbMutex_Lock(s->m_mutex);
2001 
2002   if(p->id != s->m_session_id)
2003   {
2004     if(s!=p->l)
2005       NdbMutex_Unlock(s->m_mutex);
2006     return;
2007   }
2008 
2009   p->found= true;
2010   p->l->m_output->println("id: %llu",s->m_session_id);
2011   p->l->m_output->println("m_stopSelf: %d",s->m_stopSelf);
2012   p->l->m_output->println("m_stop: %d",s->m_stop);
2013   p->l->m_output->println("nodeid: %d",s->m_allocated_resources->get_nodeid());
2014   if(s->m_ctx)
2015   {
2016     int l= strlen(s->m_ctx->m_tokenBuffer);
2017     p->l->m_output->println("parser_buffer_len: %u",l);
2018     p->l->m_output->println("parser_status: %d",s->m_ctx->m_status);
2019   }
2020 
2021   if(s!=p->l)
2022     NdbMutex_Unlock(s->m_mutex);
2023 }
2024 
2025 void
getSession(Parser_t::Context & ctx,Properties const & args)2026 MgmApiSession::getSession(Parser_t::Context &ctx,
2027                           Properties const &args) {
2028   Uint64 id;
2029   struct get_session_param p;
2030 
2031   args.get("id", &id);
2032 
2033   p.l= this;
2034   p.id= id;
2035   p.found= false;
2036 
2037   m_output->println("get session reply");
2038   m_mgmsrv.get_socket_server()->foreachSession(get_session,(void*)&p);
2039 
2040   if(p.found==false)
2041     m_output->println("id: 0");
2042 
2043   m_output->println("%s", "");
2044 }
2045 
2046 
2047 static bool
clear_dynamic_ports_from_config(Config * config)2048 clear_dynamic_ports_from_config(Config* config)
2049 {
2050   ConfigIter iter(config, CFG_SECTION_CONNECTION);
2051 
2052   for(;iter.valid();iter.next()) {
2053     Uint32 n1, n2;
2054     if (iter.get(CFG_CONNECTION_NODE_1, &n1) != 0 &&
2055         iter.get(CFG_CONNECTION_NODE_2, &n2) != 0)
2056       return false;
2057 
2058     Uint32 port_value;
2059     if (iter.get(CFG_CONNECTION_SERVER_PORT, &port_value) != 0)
2060       return false;
2061 
2062     int port = (int)port_value;
2063     if (port < 0)
2064     {
2065       // Found a dynamic port with value in config, clear it by updating
2066       // the already existing value
2067       Uint32 zero_port = 0;
2068       ConfigValues::Iterator i2(config->m_configValues->m_config,
2069                                 iter.m_config);
2070       if (!i2.set(CFG_CONNECTION_SERVER_PORT, zero_port))
2071         return false;
2072     }
2073   }
2074   return true;
2075 }
2076 
2077 
setConfig(Parser_t::Context & ctx,Properties const & args)2078 void MgmApiSession::setConfig(Parser_t::Context &ctx, Properties const &args)
2079 {
2080   BaseString result("Ok");
2081   Uint32 len64 = 0;
2082 
2083   {
2084     const char* buf;
2085     args.get("Content-Type", &buf);
2086     if(strcmp(buf, "ndbconfig/octet-stream")) {
2087       result.assfmt("Unhandled content type '%s'", buf);
2088       goto done;
2089     }
2090 
2091     args.get("Content-Transfer-Encoding", &buf);
2092     if(strcmp(buf, "base64")) {
2093       result.assfmt("Unhandled content encoding '%s'", buf);
2094       goto done;
2095     }
2096   }
2097 
2098   args.get("Content-Length", &len64);
2099   if(len64 ==0 || len64 > (1024*1024)) {
2100     result.assfmt("Illegal config length size %d", len64);
2101     goto done;
2102   }
2103   len64 += 1; // Trailing \n
2104 
2105   {
2106     char* buf64 = new char[len64];
2107     int r = 0;
2108     size_t start = 0;
2109     do {
2110       if((r= read_socket(m_socket,
2111                          SOCKET_TIMEOUT,
2112                          &buf64[start],
2113                          len64-start)) < 1)
2114       {
2115         delete[] buf64;
2116         result.assfmt("read_socket failed, errno: %d", errno);
2117         goto done;
2118       }
2119       start += r;
2120     } while(start < len64);
2121 
2122     char* decoded = new char[base64_needed_decoded_length((size_t)len64 - 1)];
2123     int decoded_len= ndb_base64_decode(buf64, len64-1, decoded, NULL);
2124     delete[] buf64;
2125 
2126     ConfigValuesFactory cvf;
2127     if(!cvf.unpack(decoded, decoded_len))
2128     {
2129       delete[] decoded;
2130       result.assfmt("Failed to unpack config");
2131       goto done;
2132     }
2133     delete[] decoded;
2134 
2135     Config new_config(cvf.getConfigValues());
2136 
2137     // Remove any dynamic ports from the new config
2138     if (!clear_dynamic_ports_from_config(&new_config))
2139     {
2140       result.assfmt("INTERNAL ERROR: Failed to clear dynamic "
2141                     "ports from config");
2142       goto done;
2143     }
2144 
2145     (void)m_mgmsrv.change_config(new_config, result);
2146   }
2147 
2148 done:
2149 
2150   m_output->println("set config reply");
2151   m_output->println("result: %s", result.c_str());
2152   m_output->println("%s", "");
2153 }
2154 
2155 
showConfig(Parser_t::Context & ctx,Properties const & args)2156 void MgmApiSession::showConfig(Parser_t::Context &ctx, Properties const &args)
2157 {
2158   const char* section = NULL;
2159   const char* name = NULL;
2160   Uint32 nodeid = 0;
2161 
2162   args.get("Section", &section);
2163   args.get("NodeId", &nodeid);
2164   args.get("Name", &name);
2165 
2166   NdbOut socket_out(*m_output, false /* turn off autoflush */);
2167   m_output->println("show config reply");
2168   m_mgmsrv.print_config(section, nodeid, name,
2169                         socket_out);
2170   m_output->println("%s", "");
2171 }
2172 
2173 
2174 void
reloadConfig(Parser_t::Context &,const class Properties & args)2175 MgmApiSession::reloadConfig(Parser_t::Context &,
2176                             const class Properties &args)
2177 {
2178   const char* config_filename= NULL;
2179   Uint32 mycnf = 0;
2180 
2181   args.get("config_filename", &config_filename);
2182   args.get("mycnf", &mycnf);
2183 
2184   g_eventLogger->debug("config_filename: %s, mycnf: %s",
2185                        str_null(config_filename),
2186                        yes_no(mycnf));
2187 
2188   m_output->println("reload config reply");
2189 
2190   BaseString msg;
2191   if (!m_mgmsrv.reload_config(config_filename, (mycnf != 0), msg))
2192     m_output->println("result: %s", msg.c_str());
2193   else
2194     m_output->println("result: Ok");
2195 
2196   m_output->println("%s", "");
2197 }
2198 
2199 
2200 void
show_variables(Parser_t::Context &,const class Properties & args)2201 MgmApiSession::show_variables(Parser_t::Context &,
2202                               const class Properties &args)
2203 {
2204   m_output->println("show variables reply");
2205   NdbOut socket_out(*m_output, false /* turn off autoflush */);
2206   m_mgmsrv.show_variables(socket_out);
2207   m_output->println("%s", "");
2208 }
2209 
2210 
2211 static bool
valid_nodes(const NdbNodeBitmask & nodes,unsigned max_nodeid)2212 valid_nodes(const NdbNodeBitmask& nodes, unsigned max_nodeid)
2213 {
2214   unsigned nodeid = 0;
2215   while((nodeid = nodes.find(nodeid)) != NdbNodeBitmask::NotFound)
2216   {
2217     if (nodeid == 0 || nodeid > max_nodeid)
2218       return false;
2219     nodeid++;
2220   }
2221   return true;
2222 }
2223 
2224 
2225 #include <signaldata/DumpStateOrd.hpp>
2226 #include "../common/util/parse_mask.hpp"
2227 
2228 static const
2229 struct dump_request {
2230   Ndb_logevent_type type;
2231   DumpStateOrd::DumpStateType dump_type;
2232   // Number of reports to wait for from each node
2233   Uint32 reports_per_node;
2234 } dump_requests [] =
2235 {
2236   { NDB_LE_BackupStatus,
2237     DumpStateOrd::BackupStatus,
2238     1 },
2239 
2240   { NDB_LE_MemoryUsage,
2241     DumpStateOrd::DumpPageMemory,
2242     2},
2243 
2244   { NDB_LE_SavedEvent,
2245     DumpStateOrd::DumpEventLog,
2246     0},
2247 
2248   { NDB_LE_ILLEGAL_TYPE, (DumpStateOrd::DumpStateType)0, 0 }
2249 };
2250 
2251 void
dump_events(Parser_t::Context &,const class Properties & args)2252 MgmApiSession::dump_events(Parser_t::Context &,
2253                            const class Properties &args)
2254 {
2255   m_output->println("dump events reply");
2256 
2257   // Check "type" argument
2258   Uint32 type;
2259   args.get("type", &type);
2260 
2261   const dump_request* request = dump_requests;
2262 
2263   for (; request->type != NDB_LE_ILLEGAL_TYPE; request++)
2264   {
2265     if (request->type == (Ndb_logevent_type)type)
2266       break;
2267   }
2268 
2269   if (request->type == NDB_LE_ILLEGAL_TYPE)
2270   {
2271     m_output->println("result: ndb_logevent_type %u not supported", type);
2272     m_output->println("%s", "");
2273     return;
2274   }
2275 
2276   // Check "nodes" argument
2277   NdbNodeBitmask nodes;
2278   const char* nodes_str = NULL;
2279   args.get("nodes", &nodes_str);
2280   if (nodes_str)
2281   {
2282     int res = parse_mask(nodes_str, nodes);
2283     if (res < 0 || !valid_nodes(nodes, MAX_NDB_NODES-1))
2284     {
2285       m_output->println("result: invalid nodes: '%s'", nodes_str);
2286       m_output->println("%s", "");
2287       return;
2288     }
2289   }
2290 
2291   // Request the events
2292   Vector<SimpleSignal> events;
2293   if (!m_mgmsrv.request_events(nodes,
2294                                request->reports_per_node,
2295                                request->dump_type,
2296                                events))
2297   {
2298     m_output->println("result: failed to dump events");
2299     m_output->println("%s", "");
2300     return;
2301   }
2302 
2303   // Return result
2304   m_output->println("result: Ok");
2305   m_output->println("events: %u", events.size());
2306   m_output->println("%s", ""); // Empty line between header and first event
2307   for (unsigned i = 0; i < events.size(); i++)
2308   {
2309     const EventReport * const event =
2310       (const EventReport*)events[i].getDataPtrSend();
2311     const NodeId nodeid = refToNode(events[i].header.theSendersBlockRef);
2312 
2313     // Check correct EVENT_REP type returned
2314     assert(event->getEventType() == request->type);
2315 
2316     BaseString str;
2317     char pretty_text[512];
2318     Uint32 tmpData[256];
2319     const Uint32 * dataPtr = events[i].getDataPtr();
2320     Uint32 dataLen = events[i].getLength();
2321     if (events[i].header.m_noOfSections == 1)
2322     {
2323       if (dataLen + events[i].ptr[0].sz > NDB_ARRAY_SIZE(tmpData))
2324       {
2325         events[i].ptr[0].sz = NDB_ARRAY_SIZE(tmpData) - dataLen;
2326       }
2327       memcpy(tmpData, dataPtr, 4 * dataLen);
2328       memcpy(tmpData + dataLen, events[i].ptr[0].p, 4*events[i].ptr[0].sz);
2329       dataPtr = tmpData;
2330       dataLen += events[i].ptr[0].sz;
2331     }
2332     logevent2str(str,
2333                  event->getEventType(),
2334                  dataPtr,
2335                  dataLen,
2336                  nodeid, 0,
2337                  pretty_text, sizeof(pretty_text));
2338 
2339     m_output->println("%s", str.c_str());
2340   }
2341 }
2342 
2343 
2344 template class MutexVector<int>;
2345 template class Vector<ParserRow<MgmApiSession> const*>;
2346 template class Vector<NDB_SOCKET_TYPE>;
2347 template class Vector<SimpleSignal>;
2348