00001
00002
00003
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include <iostream>
00046
00047 #include "mastercont.h"
00048 #include "bidirconn.h"
00049 #include "udslistener.h"
00050 #include "history.h"
00051 #include "logfile.h"
00052 #include "incoming.h"
00053 #include "sockconn.h"
00058 #include "userttyconn.h"
00059 #include "ipsockaddr.h"
00060 #include "udssockaddr.h"
00061 #include "guard.h"
00062
00063
00064
00065
00066
00067 MasterController::MasterController(ConfigP &inConfig, bool inServer)
00068 : config(inConfig), server(inServer)
00069 {
00070 }
00071
00072 MasterController::~MasterController(void)
00073 {
00075
00076
00077
00078
00079 }
00080
00081
00082 MasterController* MasterController::single_instance = NULL;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 void
00095 MasterController::run(ConfigP &config, bool server)
00096 {
00097
00098 if (single_instance)
00099 throw(CMUnsupported("Unable to run a second MasterController"));
00100
00101
00102 single_instance = new MasterController(config, server);
00103
00104
00105 try {
00106 single_instance->block_signals();
00107 } catch (...) {
00108 std::cerr << "Failed to block signals before starting threads, bailing..."
00109 << std::endl;
00110 exit(4);
00111 }
00112
00113
00114 pthread_t tid_signals;
00115 int ret = pthread_create(&tid_signals, NULL,
00116 MasterController::signal_handler_thread, single_instance);
00117 PTHREAD_CHECK_AND_THROW(ret, "pthread_create(signal_handler_thread)");
00118
00119
00120
00121 single_instance->manage_connections();
00122
00123
00124 pthread_cancel(tid_signals);
00125
00126
00127 pthread_join(tid_signals, NULL);
00128
00129
00130
00131
00132
00133 delete single_instance;
00134 single_instance = NULL;
00135 }
00136
00137 MasterController *
00138 MasterController::get_instance()
00139 {
00140 if (!single_instance) {
00141
00142
00143 }
00144
00145 return single_instance;
00146 }
00147
00148 void
00149 MasterController::manage_connections()
00150 {
00151 clog << "MasterController thread starting, thread id " << pthread_self()
00152 << endl;
00153
00154
00155 try {
00156 start_connections();
00157 } catch (CMFailure &f) {
00158 cerr << f.what() << endl;
00159 return;
00160 }
00161
00162 do {
00163
00164 MessageP msg = get_message();
00165 Message::MsgType mtype = msg->type();
00166
00167
00168
00169 clog << "master thread got a message of type " << msg->name();
00170 if (mtype == Message::M_Command)
00171 clog << "(" << msg->code() << ")";
00172 clog << std::endl;
00173
00174 clog << "Looking for C_Exit" << endl;
00175 if (mtype == Message::M_Command) {
00176 if (msg->code() == Message::C_Exit)
00177 break;
00178 if (msg->code() == Message::C_Disconnected) {
00179 if (!server) {
00180
00181
00182
00183 break;
00184 }
00185 clog << "Eep! Got a disconnect message, but don't yet know how to remove whoever it was from other childrens' lists." << endl;
00186
00187
00188
00189 }
00190 }
00191
00192 clog << "Ignoring message, waiting again." << endl;
00193 } while (1);
00194
00195
00196
00197
00198
00199
00200 try {
00201 destroy_children();
00202 } catch (CMException &e) {
00203 cerr << e.what() << endl;
00204 } catch (...) {
00205 throw;
00206 }
00207 clog << "MasterController::master_thread() exiting..." << endl;
00208 return;
00209 }
00210
00211
00212 void
00213 MasterController::start_connections()
00214 {
00215 if (server) {
00216
00217
00218
00219
00220 BiDirConn *serv = NULL;
00221 Incoming *client = NULL;
00222
00223
00227
00228 try {
00229 struct sockaddr *sa = build_addr(*config);
00230 SocketAddressP tcp_addr(new IPSocketAddress(sa));
00231 ConnectorP conn(new SocketConnector(tcp_addr));
00232
00233 serv = new BiDirConn(conn);
00234 delete sa;
00235 } catch (std::exception &e) {
00236 cerr << "Exception trying to create a TCP BiDirConn: " << e.what()
00237 << std::endl;
00238 throw;
00239 }
00240 clog << "TCP connection started..." << endl;
00241
00242
00243 if (config->find("logfile") != config->end()) {
00244 try {
00245
00246
00247 clog << "Creating a LogFile" << endl;
00248 ConnectorP log(new LogFile((*config)["logfile"]));
00249 Outlet *log_out = new Outlet(log);
00250 clog << "LogFile created (file is '" << (*config)["logfile"] << "') at "
00251 << log_out << endl;
00252
00253 clog << "Adding to serv's recipients" << endl;
00254 serv->add_recipient(log_out);
00255 clog << "Added to serv's recipients" << endl;
00256 add_recipient(log_out);
00257 } catch (CMInvalidParameter &e) {
00258 cerr << "Cannot open logfile " << (*config)["logfile"]
00259 << ", continuing without logging." << endl;
00260 } catch (std::exception &e) {
00261 cerr << "Exception trying to open the logfile: " << e.what()
00262 << endl;
00263
00264 }
00265 }
00266
00267 #if defined(HISTORY) && (HISTORY > 0)
00268
00269
00270 try {
00271 clog << "Creating a History" << endl;
00272 ConnectorP hist(new History(50));
00273 Outlet *hist_out = new Outlet(hist);
00274 clog << "History created (" << HISTORY << " lines) at " << hist_out << endl;
00275
00276 clog << "Adding to serv's recipients" << endl;
00277 serv->add_recipient(hist_out);
00278 clog << "Added to serv's recipients" << endl;
00279 add_recipient(hist_out);
00280 } catch (CMInvalidParameter &e) {
00281 cerr << "Cannot construct history (" << HISTORY << " lines)"
00282 << ", continuing without history." << endl;
00283 } catch (std::exception &e) {
00284 cerr << "Exception trying to construct history: " << e.what()
00285 << endl;
00286
00287 }
00288 #endif
00289
00290
00294 if (config->find("local_socket") == config->end()) {
00295 cerr << "No 'local_socket' parameter defined in the configuration; "
00296 << "cannot proceed." << std::endl;
00297 throw(fireball(18,"Cannot start a server without a local_socket"));
00298 }
00299
00304 SocketAddressP socket_path(new UDSSocketAddress((*config)["local_socket"]));
00305 try {
00306 ListenerP base(new UDSListener(socket_path));
00307
00308
00309 client = new Incoming(base, CONNECT_TO_ONE(serv));
00310 } catch (CMFailure &f) {
00311
00312
00313
00314 throw;
00315 } catch (std::exception &e) {
00316 cerr << "Exception caught: " << e.what() << endl;
00317 throw;
00318 }
00319
00320
00321
00322 add_recipient(serv);
00323 clog << recipients.size() << " recipients in MasterControllers list" << endl;
00324 clog << "client is " << client << endl;
00325 if (client)
00326 clog << "(" << client->get_id() << ")" << endl;
00327 add_recipient(client);
00328 } else {
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 BiDirConn *serv = NULL;
00340 BiDirConn *tty = NULL;
00341
00342 try {
00343
00344 if (config->find("local_socket") != config->end()) {
00345 SocketAddressP usp(new UDSSocketAddress((*config)["local_socket"]));
00346 ConnectorP conn(new SocketConnector(usp));
00347
00348 serv = new BiDirConn(conn);
00349 } else if ((config->find("host") != config->end()) &&
00350 (config->find("port") != config->end())) {
00351 try {
00352
00353 struct sockaddr *sa = build_addr(*config);
00354 SocketAddressP addr(new IPSocketAddress(sa));
00355 ConnectorP conn(new SocketConnector(addr));
00356
00357 serv = new BiDirConn(conn);
00358 delete sa;
00359 } catch (CMException &e) {
00360 std::cerr << "CM exception: " << e.what() << std::endl;
00361
00362 throw;
00363 } catch (std::exception &e) {
00364 std::cerr << "Standard exception: " << e.what()
00365 << std::endl;
00366 throw;
00367 }
00368 } else {
00369 std::cerr << "Unable to find server to connect to in specified "
00370 << "configuration. Please check the config file(s)."
00371 << std::endl;
00372 exit(3);
00373 }
00374
00375 clog << "Set server to " << serv->get_id() << std::endl;
00376
00377 } CATCH_STR_OR_DIE(3) {
00378 std::cerr << "** Uncaught exception while initializing and/or connecting "
00379 << "to the server **" << std::endl;
00380 exit(3);
00381 }
00382
00383 try {
00384
00385
00386 ConnectorP user(new UserTTYConn(STDIN_FILENO, STDOUT_FILENO));
00387 tty = new BiDirConn(user);
00388
00389
00390 serv->add_recipient(tty);
00391 tty->add_recipient(serv);
00392 } CATCH_OR_DIE(5) {
00393 clog << "Error! Dunno what, but an exception happened." << std::endl;
00394 throw;
00395 }
00396
00397
00398
00399 add_recipient(serv);
00400 add_recipient(tty);
00401 }
00402 }
00403
00408 void
00409 MasterController::destroy_children(void)
00410 {
00411 Guard locker(&recip_mutex);
00412
00413 clog << "MasterController::destroy_children: iterating " << recipients.size()
00414 << " children" << endl;
00415 for (recipient_const_iterator ri = recipients.begin() ;
00416 ri != recipients.end() ; ++ri) {
00417 if (dynamic_cast<Connection*>(*ri)) {
00418 clog << "Stopping " << (*ri)->get_id() << endl;
00419 dynamic_cast<Connection*>(*ri)->shutdown();
00420 }
00421 clog << "Deleting " << (*ri)->get_id() << endl;
00422 delete *ri;
00423 }
00424 return;
00425 }
00426
00427
00428
00429
00430
00431
00432 void *
00433 MasterController::signal_handler_thread(void *instance)
00434 {
00435 MasterController *mc = (MasterController*) instance;
00436
00437 clog << "MasterController signal-handling thread starting, thread id "
00438 << pthread_self() << endl;
00439
00440 mc->handle_signals();
00441
00442 return NULL;
00443 }
00444
00445 void
00446 MasterController::block_signals()
00447 {
00448 if (sigfillset(&all) != 0)
00449 throw;
00450 sigprocmask(SIG_BLOCK, &all, &prev);
00451 }
00452
00453
00454 int
00455 MasterController::wait_for_signal()
00456 {
00457 int ret;
00460 # if NO_SIGTIMEDWAIT
00461 int signo;
00462 # define SIGNO signo
00463 # else
00464
00465 siginfo_t si;
00466 timespec timer = { 5, 0 };
00467 # define SIGNO si.si_signo
00468 # endif
00469
00470
00471 sigemptyset(&all);
00472 sigaddset(&all, SIGHUP);
00473 sigaddset(&all, SIGINT);
00474 sigaddset(&all, SIGTERM);
00475 # if NO_SIGTIMEDWAIT
00476 ret = sigwait(&all, &signo);
00477 # else
00478 ret = sigtimedwait(&all, &si, &timer);
00479 if ((ret < 0) && (errno == EAGAIN)) {
00480 clog << "Timeout from sigtimedwait(), waiting again..." << std::endl;
00481 SIGNO = 0;
00482 } else
00483 # endif
00484 if (ret < 0) {
00485
00486 if (errno != EINTR)
00487 err(6, "sigwait()/sigtimedwait() failure");
00488 SIGNO = 0;
00489 }
00490
00491 return(SIGNO);
00492 #undef SIGNO
00493 }
00494
00495
00496
00497
00498
00499
00500
00501 void
00502 MasterController::handle_signals()
00503 {
00504 clog << "MasterController::handle_signals (thread id " << pthread_self()
00505 << ") running and waiting for signals" << endl;
00506 do {
00507 int sig = wait_for_signal();
00508 switch (sig) {
00509 case 0:
00512 break;
00513 case SIGHUP:
00514 {
00515
00516
00517
00518 if (server) {
00519 clog << "Got a HUP; doing nothing for now." << std::endl;
00520 } else {
00521 MessageP msg(new Message(Message::C_Exit));
00522
00523 clog << "Got a " << strsignal(sig) << ", queueing a message"
00524 << std::endl;
00525
00526 clog << "Sending shutdown message to MasterController"
00527 << std::endl;
00528 queue_message(msg);
00529 }
00530 }
00531 break;
00532 case SIGINT:
00533 case SIGTERM:
00534 {
00535 clog << "Got a " << strsignal(sig) << ", queueing a message" << std::endl;
00536 MessageP msg(new Message(Message::C_Exit));
00537
00538 clog << "Sending shutdown message to MasterController"
00539 << std::endl;
00540 queue_message(msg);
00541 }
00542 break;
00543 default:
00544 std::cerr << "Got an unexpected signal (" << sig << "; "
00545 << strsignal(sig) << ") - exiting suddenly." << std::endl;
00546 exit(50 + sig);
00547
00548 }
00549 } while (true);
00550 }
00551
00552 std::string
00553 MasterController::get_id(void) const
00554 {
00555 std::string id("MasterController");
00556
00557
00558 if (server)
00559 id += "(server)";
00560 else
00561 id += "(client)";
00562
00563 return(id);
00564 }