MCS  0.3.3-alpha7
All Classes Namespaces Files Functions Variables Enumerations Enumerator Macros Pages
UserThread.cc
1 // ----------------------------------------------------------------------^
2 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
3 // (mailto: <gcalderone@ifc.inaf.it>)
4 //
5 // This file is part of MCS.
6 //
7 // MCS is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // MCS is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with MCS; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // ----------------------------------------------------------------------$
22 
23 #include "mcs.hh"
24 using namespace mcs;
25 
26 // LN
27 #include <iomanip>
28 //#include "malloc.h"
29 #if HAVE_MALLOC_H
30 #include <malloc.h>
31 #endif
32 
33 //LN-darwin
34 #ifdef __APPLE__
35 #include <sys/stat.h>
36 //# define THD_MKDIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
37 //# define SCANDIR_WANTS_CONST
38 #endif
39 
40 
41 void printMallinfo(int pos = 0) {
42 #if HAVE_MALLOC_H
43  struct mallinfo mi;
44  mi = mallinfo();
45 
46  cout << "\n\nDynamic memory (" << pos << "): " << mi.arena << endl << endl;
47 
48  cout << setw(10)<< mi.arena <<" int arena; /* non-mmapped space allocated from system */\n"
49  << setw(10)<< mi.ordblks <<" int ordblks; /* number of free chunks */\n"
50  << setw(10)<< mi.smblks <<" int smblks; /* number of fastbin blocks */\n"
51  << setw(10)<< mi.hblks <<" int hblks; /* number of mmapped regions */\n"
52  << setw(10)<< mi.hblkhd <<" int hblkhd; /* space in mmapped regions */\n"
53  << setw(10)<< mi.usmblks <<" int usmblks; /* maximum total allocated space */\n"
54  << setw(10)<< mi.fsmblks <<" int fsmblks; /* space available in freed fastbin blocks */\n"
55  << setw(10)<< mi.uordblks <<" int uordblks; /* total allocated space */\n"
56  << setw(10)<< mi.fordblks <<" int fordblks; /* total free space */\n"
57  << setw(10)<< mi.keepcost <<" int keepcost; /* top-most, releasable (via malloc_trim) space */\n\n";
58 #else
59  cout << "\n\nNo dynamic memory info for this system.\n";
60 #endif
61 }
62 
63 
64 
65 string mcs::UserThread::wpath(string fn)
66 {
67  string s;
68 
69  fn = subst(fn, " " , ""); // blanks
70  fn = subst(fn, "\\.\\." , ""); // ..
71  fn = subst(fn, "\\\\" , ""); // backslash
72  fn = subst(fn, "\\\"" , ""); // double quotes
73  fn = subst(fn, "\\\'" , ""); // single quotes
74 
75  //s = env->path;
76  s = ".";
77  if (env->cl_work) {
78  if (env->cl_work_cid)
79  s += string("/U") + string(tid());
80  else
81  s += string("/") + user;
82 
83  s += "/";
84  }
85 
86  return s + fn;
87 }
88 
89 
90 
92 {
93  sock->print(e.codemsg());
94  e.lmsg = " >" + e.lmsg; //Friendness of UserThread to Event class
95  if (log) Log(e);
96  return e.type();
97 }
98 
99 
100 
102 {
103 // void* buf = NULL;
104 // unsigned int size = data.prepareBuffer((void**) &buf);
105 // Serializable sss(buf, size);
106 //
107 // Send(MCS_OK( MSG_SENDDATA_START, 1 )); //1 is for a Data object
108 // sock->sendData(&sss);
109 // Send(MCS_OK( MSG_DATA_STOP ));
110 // free(buf);
111 // return OK;
112 
113  Send(MCS_OK( MSG_SENDDATA_START, 1 )); //1 is for a Data object
114  sock->sendData(&data);
115  Send(MCS_OK( MSG_DATA_STOP ));
116  return OK;
117 }
118 
119 
121 {
122 // void* buf = NULL;
123 // unsigned int size = vec.prepareBuffer((void**) &buf);
124 // Serializable sss(buf, size);
125 //
126 // Send(MCS_OK( MSG_SENDDATA_START, 2 )); //2 is for a Record object
127 // sock->sendData(&sss);
128 // Send(MCS_OK( MSG_DATA_STOP ));
129 // free(buf);
130 // return OK;
131 
132  Send(MCS_OK( MSG_SENDDATA_START, 2 )); //2 is for a Record object
133  sock->sendData(&vec);
134  Send(MCS_OK( MSG_DATA_STOP ));
135  return OK;
136 }
137 
138 
139 RetValue mcs::UserThread::Send(string filename, string path)
140 {
141  Send(MCS_OK( MSG_SENDFILE_START, filename.csz ));
142  Serializable sss(path, env->cl_chunksize);
143  sock->sendData(&sss);
144  Send(MCS_OK( MSG_FILE_STOP ));
145  return OK;
146 }
147 
148 
149 RetValue mcs::UserThread::Send(vector<string> vec)
150 {
151  for (unsigned int ui=0; ui<vec.size(); ui++)
152  Send(MCS_OK( MSG_OUT, vec[ui].c_str() ), false);
153 
154  return OK;
155 }
156 
157 
158 
159 #if ENABLE_MYSQL
161 {
162  RetValue ret = OK;
163 
164  if (query->gotRecordSet()) {
165  try {
166  //printMallinfo(1);
167  Send(MCS_OK( MSG_SENDFILE_START, "query.out" ));
168  //printMallinfo(2);
169  query->Result2Ascii(wpath("query.out"));
170  //printMallinfo(3);
171  Serializable file(wpath("query.out"), env->cl_chunksize);
172  //printMallinfo(4);
173  sock->sendData(&file);
174  //printMallinfo(5);
175  }
176  catch (Event& e) {
177  if (e.type() == FATAL) throw;
178  ret = Send(e);
179  }
180  //printMallinfo();
181  return Send(MCS_( ret, MSG_DATA_STOP )) ;
182  }
183  else return Send(MCS_WARN( MSG_NO_RESULT ));
184 }
185 #endif
186 
187 
188 
189 
191 {
192  switch (ret) {
193  case OK:
194  sock->print(MCS_PROMPT_OK); break;
195  case WARN:
196  sock->print(MCS_PROMPT_WARN); break;
197  case ERROR:
198  sock->print(MCS_PROMPT_ERROR); break;
199  default:
200  throw MCS_FATAL(MSG_UNEXPECTED);
201  }
202 }
203 
204 
206 {
207  string cmd;
208  bool first = true;
209  RetValue ret = OK;
210 
211  set_cancel_state(false);
212 
213  for (;;) {
214  try {
215  if (first) {
216  //A message to the user must be sent inside hk_connect
217  ret=hk_connect();
218  if (ret != OK) return;
219 
220  sock = new Socket(csocket, env->timeout, 1000, env->ssl_ctx);
221 
222  linfo.ipaddress() = sock->ipaddress();
223  linfo.hostname() = sock->hostname();
224 
225  Send(MCS_OK( MSG_WELCOME, env->localhost.csz,
226  env->appname.csz, env->appvers.csz));
227  first = false;
228  }
229  else {
230  set_cancel_state(true);
231  cmd = sock->getline();
232  set_cancel_state(false);
233 
234  //Synchronize with wakeUpClient()
235  syn.enter();
236  ret = exec(cmd);
237  syn.leave();
238 
239  //printMallinfo();
240  }
241  prompt(ret);
242  }
243  catch(Event e) {
244  //Unlock the mutex
245  while (syn.count())
246  syn.leave();
247 
248  ret = e.type();
249 
250  if (e.type() == FATAL) {
251  //If the client gives a "bye" command a FATAL exception with
252  //code BYE will be thrown.
253  if (e.code() == MSG_BYE) {
254 
255  hk_disconnect();
256 
257  //Wait until the client closes the connection, this is
258  //necessary to prevent "Address already in use" errors. The
259  //try..catch block is necessary because getline() will throw
260  //an error when the socket close.
261  try {cmd = sock->getline(); } catch(...) {}
262  }
263  else {
264  Log(e);
265  }
266 
267  Log( MCS_OK(MSG_USERTHREAD_TERMINATING) );
268  return;
269  }
270  }
271  }
272 }
273 
274 
275 
277 {
278  return Send(split(str, "\n"));
279 }
280 
281 
283 {
284  //syn.enter();
285  if (state() == MCS_STATE_RUNNING) {
286  if (e)
287  Send(*e);
288  else
289  Send(MCS_OK( MSG_WAKE_UP) );
290  }
291  //syn.leave();
292 }
293 
294 
295 
296 #define BEGIN_CMD(A) \
297 if ((!cmd_executed) && (cmd.cmpCmd(A))){ \
298  cmd_executed=true; \
299 
300 
301 #define BEGIN_CMD_LOGIN(A) \
302  BEGIN_CMD(A) \
303  if (! loginok) throw MCS_ERROR(MSG_NOT_LOGIN);
304 
305 
306 #define CMD_HELP(A) \
307  if (cmd.givenOpt(MCS_OPT_HELP)) { \
308  sendStrings(A); \
309  goto lbl_cmdexecuted; \
310  }
311 
312 
313 #define END_CMD goto lbl_cmdexecuted; }
314 
315 
316 RetValue mcs::UserThread::exec(string scmd, string _pars)
317 {
318  int i;
319  unsigned int ui;
320  string fn, s, tmp;
321  bool cmd_executed=false;
322  unsigned int size=0;
323 
324  bool opt_sqascii;
325  bool opt_sqfits ;
326  bool opt_force ;
327  bool opt_werr ;
328  static string bl = " ";
329 
330  CommandParser cmd;
331  RetValue ret=OK;
332  RetValue sub=OK;
333 
334  batchlevel++;
335 
336  try {
337 
338  scmd += " " + _pars;
339  cmd.parseCmd(scmd);
340  if (cmd.cmd().empty()) return OK;
341 
342  opt_sqascii = cmd.givenOpt(MCS_OPT_SAVEQUERYASCII);
343  opt_sqfits = cmd.givenOpt(MCS_OPT_SAVEQUERYFITS);
344  opt_force = cmd.givenOpt(MCS_OPT_FORCE);
345  opt_werr = cmd.givenOpt(MCS_OPT_ALL_ERRORS);
346 
347  if (batchlevel > 0)
348  Send(MCS_OK( MSG_BATCH_START, batchlevel, cmd.cline().csz ));
349 
350  if (cmd.cmpCmd(MCS_CMD_PASSWORD)) {
351  Log(MCS_OK( MSG_LOG_COMMAND, "*** PASSWORD ***" ));
352  }
353  else if (cmd.cmpCmd(MCS_CMD_NOP)) //Don't log NOP commands.
354  ;
355  else if (cmd.cmpCmd(MCS_CMD_CLIENT_INFO))
356  Log(MCS_OK( MSG_LOG_COMMAND, cmd.cline().csz ));
357  else {
358  Log(MCS_OK( MSG_LOG_COMMAND, cmd.cline().csz ));
359  linfo.lastCommand() = cmd.cline().substr(0, linfo.lastCommand().maxLength());
360  linfo.timeLastCommand().settimenow();
361  linfo.commandExecuted() = linfo.commandExecuted().ival() + 1;
362  }
363 
364 
365 
366 #if ! ENABLE_CFITSIO
367  if (opt_sqfits) {
368  ret=Send(MCS_WARN( MSG_FITS_NOT_COMPILED ));
369  opt_sqfits = false;
370  }
371 #endif
372 
373 #if ! ENABLE_MYSQL
374  if ((opt_sqfits) || (opt_sqascii)) {
375  cmd_executed = true;
376  throw MCS_ERROR(MSG_MYSQL_DISABLED);
377  }
378 #endif
379 
380  //Custom user routine
381  if (! cmd_executed)
382  sub = hk_exec(&cmd, cmd_executed);
383  if (sub > ret) ret = sub;
384 
385 
386  //................................................................
387  BEGIN_CMD(MCS_CMD_NOP);
388  END_CMD;
389 
390 
391  //................................................................
392  BEGIN_CMD(MCS_CMD_CID);
393  CMD_HELP(MCS_CMD_CID_HELP);
394  Send(MCS_OK( MSG_CLIENT_ID, id(), env->cl_chunksize));
395  END_CMD;
396 
397  //................................................................
398  BEGIN_CMD(MCS_CMD_CLIENT_INFO);
399  CMD_HELP(MCS_CMD_CLIENT_INFO_HELP);
400  setActiveRS(env->server->getAll_ClientInfo(), true);
401  END_CMD;
402 
403 
404  //................................................................
405  BEGIN_CMD(MCS_CMD_CLOSECLIENT);
406  CMD_HELP(MCS_CMD_CLOSECLIENT_HELP);
407  Send(MCS_OK( MSG_BYE ));
408  throw MCS_FATAL(MSG_BYE);
409  END_CMD;
410 
411 
412  //................................................................
413  BEGIN_CMD(MCS_CMD_USERNAME);
414  CMD_HELP(MCS_CMD_USERNAME_HELP);
415  if (cmd.argc() >= 1) {
416  user=cmd.arg(0).sval();
417  linfo.username() = user;
418  }
419  Send(MCS_OK( MSG_WELCOMEUSER, user.csz ));
420  END_CMD;
421 
422 
423  //................................................................
424  BEGIN_CMD(MCS_CMD_PASSWORD);
425  CMD_HELP(MCS_CMD_PASSWORD_HELP);
426  if (cmd.argc() >= 1) pass=cmd.arg(0).sval();
427  Send(MCS_OK( MSG_PASSWORD ));
428  END_CMD;
429 
430 
431  //................................................................
432  BEGIN_CMD(MCS_CMD_DBNAME);
433  CMD_HELP(MCS_CMD_DBNAME_HELP);
434  if (cmd.argc() >= 1) dbname=cmd.arg(0).sval();
435  Send(MCS_OK( MSG_DBNAME, dbname.csz ));
436  END_CMD;
437 
438 
439  //................................................................
440 #ifdef MCS_HAVE_DBH_CMD
441  BEGIN_CMD(MCS_CMD_DBHOST);
442  CMD_HELP(MCS_CMD_DBHOST_HELP);
443  if (cmd.argc() >= 1) dbhost=cmd.arg(0).sval();
444  Send(MCS_OK( MSG_DBHOST, dbhost.csz ));
445  END_CMD;
446 #endif
447 
448 
449  //................................................................
450  BEGIN_CMD(MCS_CMD_DBCONNECT);
451  CMD_HELP(MCS_CMD_DBCONNECT_HELP);
452  if (loginok) throw MCS_WARN(MSG_ALREADY_CONNECTED);
453 
454  if (env->cl_custom_auth) {
455  ret = hk_auth(grants, loginok);
456  if (ret == OK)
457  Send(MCS_OK( MSG_CONNECTED, " " ));
458  }
459  else {
460 #if ENABLE_MYSQL
461  //Check for the presence of values
462  if (user.empty() ) throw MCS_ERROR(MSG_MISSING_FIELD, "username");
463  else if (pass.empty() ) throw MCS_ERROR(MSG_MISSING_FIELD, "password");
464  else if (dbname.empty()) throw MCS_ERROR(MSG_MISSING_FIELD, "db name" );
465  else if (dbhost.empty()) throw MCS_ERROR(MSG_MISSING_FIELD, "db host" );
466  else {
467  db.connect(user, pass, dbname, dbhost);
468  query = new Query(&db, false);
469  if (env->cl_read_grants) {
470  query->query("select grants from users where username='"
471  + user + "'", true);
472  if (query->gotRecordSet() && query->nRows() == 1 ) {
473  grants = query->rec()[0].ival();
474  Log(MCS_OK( MSG_USER_HAS_GRANTS, user.csz, grants ));
475  }
476  else
477  throw MCS_FATAL(MSG_GRANTS_CANTGET_GRANTS);
478  }
479  else
480  grants=MCS_GRANT_ALL;
481  }
482 #else
483  grants = MCS_GRANT_ALL;
484 #endif
485 
486  if (! (grants & MCS_GRANT_LOGIN))
487  throw MCS_ERROR(MSG_GRANTS_LOGIN);
488  else {
489  loginok=true;
490  Send(MCS_OK( MSG_CONNECTED, dbname.csz ));
491  }
492  }
493 
494  linfo.logged() = loginok;
495 
496  if (env->cl_work) {
497  unsigned int size;
498  if (! File_Dir_Exist(wpath(), size))
499  mkDir(wpath(), MCS_MKDIR_PROTECT);
500  }
501 
502  if (env->cl_autoexec)
503  sub=exec(MCS_CMD_EXEC, "auto");
504  END_CMD;
505 
506 
507  //................................................................
508 // BEGIN_CMD_LOGIN(MCS_CMD_CLOSE_DB_CONN);
509 //#if ENABLE_MYSQL
510 // db.close();
511 //#endif
512 // Send(MCS_OK( MSG_CLOSE_DB_CONN ));
513 // loginok=false;
514 // END_CMD;
515 
516 
517 #if ENABLE_MYSQL
518  //................................................................
519  BEGIN_CMD_LOGIN(MCS_CMD_QUERY);
520  CMD_HELP(MCS_CMD_QUERY_HELP);
521  if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
522  if (! (grants & MCS_GRANT_QUERY)) throw MCS_ERROR(MSG_GRANTS_QUERY);
523 
524  s=cmd.allargs();
525  query->query(s, true);
526 
527  if (query->gotRecordSet()) {
528  Send(MCS_OK( MSG_DB_QRY_OK ));
529  setActiveRS(query, false);
530 
531  if (opt_sqfits) {
532 #if ENABLE_CFITSIO
533  //query->Result2Fits(wpath(fnout));
534 #endif
535  opt_sqfits=false;
536  }
537  else if (opt_sqascii) {
538  query->Result2Ascii(wpath(fnout));
539  opt_sqascii=false;
540  }
541  }
542  else
543  Send(MCS_OK( MSG_DB_ROWSAFF, query->nAffectedRows() ));
544  END_CMD;
545 
546 
548  //BEGIN_CMD_LOGIN(MCS_CMD_ROWS);
549  //CMD_HELP(MCS_CMD_ROWS_HELP);
550  //if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
551  //if (! query->gotRecordSet()) throw MCS_WARN(MSG_NO_RESULT);
552  //
553  //if (query->gotRecordSet())
554  // Send(MCS_OK( MSG_DB_ROWSAFF, query->nRows() ));
555  //END_CMD;
556 
557 
559  //BEGIN_CMD_LOGIN(MCS_CMD_FIELDS);
560  //CMD_HELP(MCS_CMD_FIELDS_HELP);
561  //if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
562  //if (! query->gotRecordSet()) throw MCS_WARN(MSG_NO_RESULT);
563  //
564  //Send( query->ExecutionDetails() );
565  //END_CMD;
566 
567 
568  //................................................................
569  BEGIN_CMD_LOGIN(MCS_CMD_SENDQUERYRES);
570  CMD_HELP(MCS_CMD_SENDQUERYRES_HELP);
571  if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
572  if (! (grants & MCS_GRANT_GET)) throw MCS_ERROR(MSG_GRANTS_GET);
573  if (! query->gotRecordSet()) throw MCS_WARN(MSG_NO_RESULT);
574 
575  sub=sendQueryRes();
576  END_CMD;
577 
578 
579  //................................................................
580  BEGIN_CMD_LOGIN(MCS_CMD_RECORD);
581  CMD_HELP(MCS_CMD_RECORD_HELP);
582  if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
583  if (! (grants & MCS_GRANT_GET)) throw MCS_ERROR(MSG_GRANTS_GET);
584  if (! rs) throw MCS_WARN(MSG_NO_RESULT);
585 
586  unsigned int pos = cmd.arg(0).ival();
587  if (pos == rs->pos())
588  Send(rs->rec());
589  else if (pos == rs->pos()+1) {
590  if (rs->setNext())
591  Send(rs->rec());
592  else
593  Send( MCS_OK(MSG_FETCH_EOF) );
594  }
595  else {
596  rs->setPos(pos);
597  Send(rs->rec());
598  }
599  END_CMD;
600 
601 
602  //................................................................
603  BEGIN_CMD_LOGIN(MCS_CMD_TABLELIST);
604  CMD_HELP(MCS_CMD_TABLELIST_HELP);
605  if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
606 
607  s = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '"
608  + dbname + "' AND TABLE_TYPE = 'BASE TABLE'";
609  exec(MCS_CMD_QUERY + bl + s);
610  //query->readTableList();
611  //Send( query->tableList );
612  END_CMD;
613 
614 
615  //................................................................
616  BEGIN_CMD_LOGIN(MCS_CMD_TABLEINFO);
617  CMD_HELP(MCS_CMD_TABLEINFO_HELP);
618  if (! env->cl_have_db) throw MCS_ERROR(MSG_DB_ERR_NOTACTIVATED);
619  if ((cmd.argc() < 1) || (cmd.arg(0).sval().empty()))
620  throw MCS_WARN(MSG_MISSING_FIELD, "table name");
621 
622  s = "SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '"
623  + dbname + "' AND TABLE_NAME = '" + cmd.arg(0).sval() + "'";
624 
625  exec(MCS_CMD_QUERY + bl + s);
626  //exec(MCS_CMD_QUERY + bl + "DESCRIBE " + cmd.arg(0).sval());
627  //Send( query->tableInfo(cmd.arg(0).sval()) );
628  END_CMD;
629 
630 #endif //ENABLE_MYSQL
631 
632 
633 
634  //................................................................
635  BEGIN_CMD_LOGIN(MCS_CMD_EXEC);
636  CMD_HELP(MCS_CMD_EXEC_HELP);
637  if (! (grants & MCS_GRANT_SCRIPTS)) throw MCS_ERROR(MSG_GRANTS_SCRIPT);
638 
639  s = fn = cmd.arg(0).sval();
640  i = chkExt(fn);
641 
642  if ((i == MCS_FT_BIN) || (i == MCS_FT_SCRIPT)) {
643 #if ENABLE_DEBUG
644  tmp = fn + " " + cmd.line_afterToken(1);
645  Log(MCS_OK( MSG_SCRIPT_START, tmp.csz ));
646 #endif
647  Send(MCS_OK( MSG_SCRIPT_START, s.csz ));
648 
649  i = spawn(fn, cmd.line_afterToken(1),
650  wpath(), itos(id()),
651  user, pass, dbname,
652  wpath(fnout), wpath(fnerr));
653  if (i != 0)
654  throw MCS_WARN(MSG_SCRIPT_ERROR, i);
655 
656  Send(MCS_OK( MSG_SCRIPT_STOP, s.csz ));
657  }
658  else {
659  string c="";
660  bool had_warn = false;
661  bool had_err = false;
662  bool stop = false;
663  vector<string> vec = cmd.replPars_onFile(fn);
664  if (i == MCS_FT_BATCH)
665  Send(MCS_OK( MSG_BATCH_START, batchlevel, s.csz ));
666  if (i == MCS_FT_SQL) {
667 #if ENABLE_MYSQL
668  Send(MCS_OK( MSG_SQL_START, s.csz )); c = MCS_CMD_QUERY;
669 #else
670  throw MCS_ERROR(MSG_DB_NOT_COMPILED);
671 #endif
672  }
673 
674  for (ui=0; ui<vec.size(); ui++) {
675 
676  sub=exec(c.csz, vec[ui]);
677 
678  switch(sub) {
679  case OK:
680  break;
681  case WARN:
682  had_warn = true;
683  if (opt_werr) stop = true;
684  break;
685  case ERROR:
686  had_err = true;
687  if (! opt_force) stop = true;
688  break;
689  case FATAL:
690  throw MCS_FATAL(MSG_UNEXPECTED);
691  break; //Is unexpected because an exception should be thrown
692  }
693 
694  if (stop) break;
695  }
696 
697  if (had_err) ret = ERROR;
698  else if (had_warn) ret = WARN;
699  else ret = OK;
700 
701  if (i == MCS_FT_BATCH) Send(MCS_OK( MSG_BATCH_STOP, batchlevel ));
702  if (i == MCS_FT_SQL) {
703  Send(MCS_OK( MSG_SQL_STOP ));
704 
705  if ((ret == OK) && query->gotRecordSet()) {
706  if (opt_sqfits) {
707 #if ENABLE_CFITSIO
708  //query->Result2Fits(wpath(fnout));
709 #endif
710  opt_sqfits=false;
711  }
712  else if (opt_sqascii) {
713  query->Result2Ascii(wpath(fnout));
714  opt_sqascii=false;
715  }
716  }
717  }
718  }
719  END_CMD;
720 
721 
722  //................................................................
723  BEGIN_CMD_LOGIN(MCS_CMD_GET);
724  CMD_HELP(MCS_CMD_GET_HELP);
725  if (! (grants & MCS_GRANT_GET)) throw MCS_ERROR(MSG_GRANTS_GET);
726 
727  fn = wpath(fnout);
728  s = fnout;
729  if (cmd.argc() == 1) {
730  fn = wpath(cmd.arg(0).sval());
731  s = cmd.arg(0).sval();
732  }
733 
734  ret = Send(s, fn);
735  END_CMD;
736 
737 
738 
739 //This has been commented because data in the "send" vector are automatically
740 //sent after each command.
741 // //................................................................
742 // BEGIN_CMD_LOGIN(MCS_CMD_GETDATA);
743 // CMD_HELP(MCS_CMD_GETDATA_HELP);
744 // if (! (grants & MCS_GRANT_GET)) throw MCS_ERROR(MSG_GRANTS_GET);
745 // if (cmd.argc() < 1) throw MCS_ERROR(MSG_MISSING_FIELD, "object index");
746 //
747 // ui = cmd.arg(0).ival();
748 // if (ui < send.count()) {
749 // tbuf = NULL;
750 // size = send.pop(ui).prepareBuffer((void**) &tbuf);
751 // Serializable sss(tbuf, size);
752 //
753 // Send(MCS_OK( MSG_SENDDATA_START, 1 )); //1 is for a Data object
754 // sock->sendData(&sss);
755 // Send(MCS_OK( MSG_DATA_STOP ));
756 // free(tbuf);
757 // }
758 // else
759 // throw MCS_ERROR(MSG_INDEX_OUT_RANGE, ui, send.count());
760 // END_CMD;
761 
762 
763  //................................................................
764  BEGIN_CMD_LOGIN(MCS_CMD_PUT);
765  CMD_HELP(MCS_CMD_PUT_HELP);
766  if (! (grants & MCS_GRANT_PUT)) throw MCS_ERROR(MSG_GRANTS_PUT);
767  if (cmd.argc() < 1) throw MCS_ERROR(MSG_MISSING_FIELD, "file name, size");
768 
769  s = cmd.arg(0).sval();
770  if (strchr(s.c_str(), '/')) { //A path is specified
771  if (s[0] == '/')
772  throw MCS_ERROR( MSG_NO_ABSOLUTE_PATH, s );
773 
774  if (strstr(s.c_str(), ".."))
775  throw MCS_ERROR( MSG_NO_DOUBLEDOT_PATH, s );
776 
777  string subdir = wpath(s);
778  unsigned int ui = subdir.rfind('/');
779  subdir.resize(ui);
780  if (! File_Dir_Exist(subdir, ui))
781  mkDir(subdir, MCS_MKDIR_PROTECT);
782  }
783  fn = wpath(s);
784  size = cmd.arg(1).ulval();
785 
786  Send(MCS_OK( MSG_RECVFILE_START, s.csz ));
787  sock->recvData(fn);
788  ret = Send(MCS_OK( MSG_FILE_STOP, s.csz ));
789  END_CMD;
790 
791 
792  //................................................................
793  BEGIN_CMD_LOGIN(MCS_CMD_PUTDATA);
794  CMD_HELP(MCS_CMD_PUTDATA_HELP);
795  if (! (grants & MCS_GRANT_PUT)) throw MCS_ERROR(MSG_GRANTS_PUT);
796  if (cmd.argc() < 1) throw MCS_ERROR(MSG_MISSING_FIELD, "size");
797 
798  size = cmd.arg(0).ulval();
799  Send(MCS_OK( MSG_RECVDATA_START ));
800  char* tbuf = NULL;
801  size = sock->recvData(&tbuf, 0);
802 
803  Data d(tbuf);
804  d.setSourceID(MCS_ID_CLIENT);
805  d.setDestID(userID());
806  recv.addField(d);
807 
808  Send(MCS_OK( MSG_DATA_STOP ));
809 
810  if (cmd.givenOpt(MCS_OPT_LOOP)) {
811  Send(MCS_OK( MSG_COPYING_DATA_OBJECTS, "send Record" ));
812  send.addField(d);
813  }
814 
815  free(tbuf);
816  END_CMD;
817 
818 
819  //................................................................
820  if (! cmd_executed)
821  throw MCS_ERROR(MSG_SYNTAX, cmd.cline().csz);
822 
823 
824  lbl_cmdexecuted:
825  ; //Continue from here if the command has been excuted
826 
827 
828 //Eventually send objects in the send Record
829  if (ret == OK)
830  while (send.count()) {
831  Data d = send.pop();
832  Send(d);
833  }
834 
835  hk_postexec(&cmd, ret);
836 
837  if (batchlevel > 0)
838  Send(MCS_OK( MSG_BATCH_STOP, batchlevel ));
839 
840 
841  } // try
842  catch(Event e) {
843  if (e.type() != FATAL)
844  ret = Send(e);
845  else
846  throw e;
847  }
848 
849  batchlevel--;
850  return ret;
851 }
852 
853 
854 
855 mcs::UserThread::UserThread(Thread* parent, int lID, int newsock) :
856  BaseThread(parent, lID),
857  syn(),
858  recv(true)
859 {
860  Log(MCS_OK( MSG_THREAD_CREATE, "UserThread" ));
861  //printMallinfo();
862 
863  sock = NULL;
864 
865  syn.synchronize(true);
866 
867  csocket = 0;
868  if (newsock) {
869  csocket = newsock;
870  }
871 
872  loginok=false;
873  grants=0;
874  batchlevel=-1;
875 
876  fnout="out";
877  fnerr="err";
878 
879  dbhost="localhost";
880  dbname=env->appname;
881 
882  linfo.id() = lID;
884 
885  luserid = MCS_ID_UNKNOWN;
886 
887 #if ENABLE_MYSQL
888  if (env->cl_have_db)
889  query = NULL;
890 #endif
891 
892  rs = NULL;
893 }
894 
895 
896 void mcs::UserThread::setActiveRS(RecordSet* rs, bool delWhenFinished)
897 {
898  if ( (this->rs) && (deleters) )
899  delete this->rs;
900 
901  this->rs = rs;
902  deleters = delWhenFinished;
903 
904  Record* tmp = rs->prepRecToSend();
905 
906  Send(*tmp);
907  delete tmp;
908  Send( MCS_OK( MSG_NEW_RECORDSET ) );
909 }
910 
911 
913 {
914  if ( (this->rs) && (deleters) )
915  delete rs;
916 
917  if (env->cl_work && env->cl_clean_logout)
918  rmDir(wpath());
919 
920  if (sock) {
921  delete sock;
922  sock = NULL;
923  }
924 
925 #if ENABLE_MYSQL
926  if (env->cl_have_db)
927  try { if (query) delete query; }
928  catch (Event &e) {}
929 #endif
930 
931  //printMallinfo();
932 
933  Log(MCS_OK( MSG_THREAD_DESTROY, "UserThread" ));
934 }
935 
936 
937 
939 {
940  return linfo;
941 }
942 
943 
944 
946 {
947  RetValue ret = OK;
948  cmd_executed = false;
949 
950  if (env->server->cb_exec)
951  ret = (*(env->server->cb_exec))(cmd, cmd_executed);
952 
953  if (env->server->cbwa_exec)
954  (*(env->server->cbwa_exec))();
955 
956  return ret;
957 }
958 
960 {
961  if (env->server->cb_postexec)
962  (*(env->server->cb_postexec))(cmd, ret);
963 
964  if (env->server->cbwa_postexec)
965  (*(env->server->cbwa_postexec))();
966 }
967 
969 {
970  RetValue ret = OK;
971 
972  if (env->server->cb_connect)
973  ret = (*(env->server->cb_connect))();
974 
975  if (env->server->cbwa_connect)
976  (*(env->server->cbwa_connect))();
977 
978  return ret;
979 }
980 
982 {
983  if (env->server->cb_disconnect)
984  (*(env->server->cb_disconnect))();
985 }
986 
987 
989 {
990  RetValue ret = OK;
991  grants = MCS_GRANT_ALL;
992  loginok = true;
993 
994  if (env->server->cb_auth)
995  ret = (*(env->server->cb_auth))(grants, loginok);
996 
997  if (env->server->cbwa_auth)
998  (*(env->server->cbwa_auth))();
999 
1000  return ret;
1001 }
1002 
1003 
1005 {
1006  return env->server;
1007 }
1008 
1009 
1011 {
1012  string ret;
1013  ret = user;
1014  return ret;
1015 }
1016 
1017 
1018 
1019 int mcs::UserThread::userID()
1020 {
1021  return luserid;
1022 }
1023 
1024 
1026 {
1027  d.setSourceID(userID());
1028  d.setDestID(dest);
1029  env->server->dispatch.addField(d);
1030 }
1031 
#define MCS_CMD_CLIENT_INFO
Command: Return server status information.
Definition: mcs.hh:296
string wpath(string fn="")
Return the path of the work directory followed by the path given in parameter.
Definition: UserThread.cc:65
void run()
The body of the thread.
Definition: UserThread.cc:205
#define MCS_FT_SQL
Return value for BaseThread.fileType(), SQL file.
Definition: mcs.hh:6257
#define MCS_CMD_RECORD
Definition: mcs.hh:337
RetValue Log(Event e)
Logging facility.
Definition: BaseThread.cc:29
string itos(int i)
Convert an integer to a string.
Definition: Utils.cc:77
Definition: mcs.hh:472
void settimenow()
Convert current time value to base type and store in internal buffer.
Definition: Data.cc:1846
string cline()
Returns the entire command line.
unsigned long long int ulval() const
Convert internal data to an unsigned long long integer value.
Definition: Data.cc:1397
int luserid
The userid of current user.
Definition: mcs.hh:6386
Serialize memory buffers or files into chunks.
Definition: mcs.hh:1290
Base class for MCS threaded objects.
Definition: mcs.hh:6098
string allargs()
Returns all arguments (not tokens!) as a string.
void(* cbwa_postexec)()
Pointer to a void callback function without arguments, called by hk_postexec().
Definition: mcs.hh:7316
string fnout
Default output file.
Definition: mcs.hh:6398
Execute queries on the database.
Definition: mcs.hh:5544
void parseCmd(string c)
Parse a command line into tokens, arguments and options.
bool File_Dir_Exist(string fn, unsigned int &size)
Check if a file or directory exists.
Definition: Utils.cc:39
vector< string > replPars_onFile(string fn)
Parse a MCS script.
void(* cbwa_exec)()
Pointer to a void callback function without arguments, called by hk_exec().
Definition: mcs.hh:7313
string sval(bool addWhiteSpaces=false) const
Convert internal data to a string object.
Definition: Data.cc:1555
#define MCS_CMD_GET
Command: Download a file from the work directory.
Definition: mcs.hh:416
int batchlevel
Nested batch level.
Definition: mcs.hh:6389
Class holding information about a client connection.
Definition: mcs.hh:6273
Main server class for a MCS-based application.
Definition: mcs.hh:7166
void synchronize(bool setactive)
Enable or disable the synchronization feature.
Definition: Thread.cc:89
#define MCS_OPT_SAVEQUERYASCII
Option: Save query result in ASCII format.
Definition: mcs.hh:383
Record dispatch
Record of Data objects to be sent to various threads.
Definition: mcs.hh:7322
Hold informations about an event.
Definition: mcs.hh:814
static Env * env
Pointer to the actual Env object, this can be seen in all threaded object.
Definition: mcs.hh:6116
A dynamic array of Data objects.
Definition: mcs.hh:4170
#define MCS_CMD_SENDQUERYRES
Command: Retrieve a file with an ASCII dump of the entire set of records returned by the last query...
Definition: mcs.hh:353
bool loginok
Tells if client has logged in correctly.
Definition: mcs.hh:6392
RetValue sendStrings(string str)
Send strings to client.
Definition: UserThread.cc:276
virtual RetValue hk_connect()
Virtual method called when a new user connects to the server.
Definition: UserThread.cc:968
#define MCS_OPT_LOOP
Option: Put a copy of thr recevied Data object in the "send" vector.
Definition: mcs.hh:401
string user
User name.
Definition: mcs.hh:6404
string fnerr
Default error file.
Definition: mcs.hh:6401
string dbhost
Host running database server.
Definition: mcs.hh:6413
#define MCS_(TYPE, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:970
int csocket
C socket descriptor, used to initialize the Socket object.
Definition: mcs.hh:6370
void send2OtherThread(Data &d, int destid)
Used to send data object to other threads.
Definition: UserThread.cc:1025
string line_afterToken(int i)
Return the "rest" relative to token at i-th position.
The base class that implement the data abstraction layer.
Definition: mcs.hh:4510
#define MCS_ERROR(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:964
string codemsg()
Return the code and the message, formatted as MCS_PRE CODE MESSAGE.
Definition: Event.cc:136
Server * parent()
Return the address of the Server object which generates this Thread.
Definition: UserThread.cc:1004
#define MCS_CMD_PUTDATA
Command: Upload Data objects.
Definition: mcs.hh:431
#define MCS_FT_BATCH
Return value for BaseThread.fileType(), batch file.
Definition: mcs.hh:6254
void wakeUpClient(Event *e=NULL)
Send a message to the client.
Definition: UserThread.cc:282
Data & timeConnetcted()
Time at which the client connected.
Definition: Server.cc:320
string appname
Application name.
Definition: mcs.hh:6923
void prompt(RetValue ret)
Send a prompt to client.
Definition: UserThread.cc:190
virtual void hk_postexec(CommandParser *cmd, RetValue ret)
Virtual method called after a command has been executed.
Definition: UserThread.cc:959
#define MCS_CMD_PUT
Command: Upload a file to the work directory.
Definition: mcs.hh:421
~UserThread()
Destructor.
Definition: UserThread.cc:912
int argc()
Return number of arguments.
RetValue
Return value for MCS routines.
Definition: mcs.hh:471
RetValue type()
Return the event type.
Definition: Event.cc:99
RetValue exec(string cmd, string pars="")
Execution method for user&#39;s command.
Definition: UserThread.cc:316
int grants
User grants.
Definition: mcs.hh:6395
#define MCS_CMD_CID
Command: Retrieve the Client identifier.
Definition: mcs.hh:327
bool givenOpt(string opt)
Check if a certain option has been given.
#define MCS_FT_SCRIPT
Return value for BaseThread.fileType(), script file.
Definition: mcs.hh:6260
Parse command lines.
Definition: mcs.hh:5185
#define MCS_CMD_EXEC
Command: Execute an external program, script, SQL or batch file.
Definition: mcs.hh:411
string dbname
Database name, usually the same as Env.appname.
Definition: mcs.hh:6410
RetValue(* cb_auth)(int &, bool &)
Pointer to a callback function, called by hk_auth().
Definition: mcs.hh:7292
bool cl_have_db
Activate DB facilities.
Definition: mcs.hh:6955
vector< string > split(string s, string sep=" ")
Split a string into tokens.
Definition: Utils.cc:192
#define MCS_PROMPT_ERROR
Prompt sent after a command raised one error.
Definition: mcs.hh:282
RetValue sendQueryRes()
Send query results as it was a file created with the Query.Result2Ascii() method. ...
Definition: UserThread.cc:160
#define MCS_CMD_TABLELIST
Command: Retrieve the list of tables actually present in the database.
Definition: mcs.hh:360
Main include file for all MCS based applications.
bool cl_clean_logout
Clean work dir on user logout.
Definition: mcs.hh:6979
UserThread(const UserThread &)
Declared to avoid using of default copy constructor.
void addField(Data *d)
Wrapper around Dynamic_Array.push.
Definition: Record.cc:364
bool cmpCmd(string cmd)
Check if the string in the parameter is the same as the command (case insensitive).
#define MCS_STATE_RUNNING
Thread state: the separate thread is executing the run() method.
Definition: mcs.hh:2409
#define MCS_WARN(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:961
int code()
Returns the event code.
Definition: Event.cc:92
A general purpose data type.
Definition: mcs.hh:3092
#define MCS_CMD_DBNAME
Command: Provide the application (database) name.
Definition: mcs.hh:311
#define MCS_CMD_USERNAME
Command: Provide user name.
Definition: mcs.hh:301
RetValue(* cb_connect)()
Pointer to a callback function, called by hk_connect().
Definition: mcs.hh:7289
string subst(string s, string what, string with, int op=0)
Perform substitutions on a string.
Definition: Utils.cc:135
bool rmDir(string path, enum ThrowExceptions throwexc=THROW)
Removes a directory.
Definition: Utils.cc:274
#define MCS_CMD_TABLEINFO
Command: Retrieve information about a table.
Definition: mcs.hh:366
#define MCS_FT_BIN
Return value for BaseThread.fileType(), binary file.
Definition: mcs.hh:6263
#define MCS_OK(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:958
Socket * sock
Socket to client.
Definition: mcs.hh:6383
#define MCS_PROMPT_OK
Prompt sent after a command has been executed correctly.
Definition: mcs.hh:276
Query * query
Query object.
Definition: mcs.hh:6420
ClientInfo & info()
Return internal ClientInfo structure.
Definition: UserThread.cc:938
#define MCS_CMD_QUERY
Command: Execute queries on the database.
Definition: mcs.hh:348
Data & id()
Client ID, the same as the one returned with the MCS_CMD_CID command.
Definition: Server.cc:317
#define MCS_OPT_SAVEQUERYFITS
Option: Save query result in FITS format.
Definition: mcs.hh:378
A class to create separate threads.
Definition: mcs.hh:2487
#define MCS_PROMPT_WARN
Prompt sent after a command raised one or more warnings.
Definition: mcs.hh:279
virtual RetValue hk_auth(int &grants, bool &loginok)
Virtual method called when the user issue the MCS_CMD_DBCONNECT command.
Definition: UserThread.cc:988
string cmd()
Returns the first token, that is the command.
#define MCS_CMD_NOP
Command: No operation (dummy) command.
Definition: mcs.hh:291
int ival() const
Convert internal data to a integer value.
Definition: Data.cc:1209
#define MCS_FATAL(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:967
RetValue(* cb_exec)(CommandParser *, bool &_executed)
Pointer to a callback function, called by hk_exec().
Definition: mcs.hh:7295
void(* cbwa_auth)()
Pointer to a void callback function without arguments, called by hk_auth().
Definition: mcs.hh:7310
Data & arg(int i)
Return argument at i-th position.
#define MCS_CMD_CLOSECLIENT
Command: Close the session.
Definition: mcs.hh:322
Manage TCP sockets.
Definition: mcs.hh:1662
string lmsg
Message.
Definition: mcs.hh:827
#define MCS_CMD_DBCONNECT
Command: Finalize the authentication process and log in.
Definition: mcs.hh:317
#define MCS_OPT_FORCE
Option: Continue execution of commands even if an error occur.
Definition: mcs.hh:389
ClientInfo linfo
Structure containing client informations.
Definition: mcs.hh:6373
virtual void hk_disconnect()
Virtual method called when the user disconnect.
Definition: UserThread.cc:981
string userName()
Return the user name used to authenticate the client.
Definition: UserThread.cc:1010
void(* cb_disconnect)()
Pointer to a callback function, called by hk_disconnect().
Definition: mcs.hh:7301
#define MCS_CMD_PASSWORD
Command: Provide password.
Definition: mcs.hh:306
void(* cb_postexec)(CommandParser *, RetValue)
Pointer to a callback function, called by hk_postexec().
Definition: mcs.hh:7298
bool mkDir(string path, mode_t perm=0, enum ThrowExceptions throwexc=THROW)
Create a directory.
Definition: Utils.cc:259
bool cl_work
Use private (per user) working dir, otherwise use path.
Definition: mcs.hh:6964
RetValue Send(Event e, bool log=true)
Send a message to client.
Definition: UserThread.cc:91
#define MCS_OPT_ALL_ERRORS
Option: Turns all warning into errors, so that a warning can stop the execution.
Definition: mcs.hh:395
Namespace for MCS library.
virtual RetValue hk_exec(CommandParser *cmd, bool &cmd_executed)
Virtual method called before executing a command.
Definition: UserThread.cc:945
void(* cbwa_connect)()
Pointer to a void callback function without arguments, called by hk_connect().
Definition: mcs.hh:7307

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha7
Documentation generated on Mon May 28 07:39:41 UTC 2018