diff --git a/CMakeLists.txt b/CMakeLists.txt index 64dfa3c8..0a3398e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,9 @@ ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(spectrum) ADD_SUBDIRECTORY(backends) #ADD_SUBDIRECTORY(tests) -ADD_SUBDIRECTORY(spectrum_manager) +if (NOT WIN32) + ADD_SUBDIRECTORY(spectrum_manager) +endif() if (CPPUNIT_FOUND) message("tests : yes") diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 92652201..3acc3d08 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -1697,6 +1697,33 @@ static void spectrum_sigchld_handler(int sig) } } +static int create_socket(char *host, int portno) { + struct sockaddr_in serv_addr; + + int m_sock = socket(AF_INET, SOCK_STREAM, 0); + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(portno); + + hostent *hos; // Resolve name + if ((hos = gethostbyname(host)) == NULL) { + // strerror() will not work for gethostbyname() and hstrerror() + // is supposedly obsolete + exit(1); + } + serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]); + + if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + close(m_sock); + m_sock = 0; + } + + int flags = fcntl(m_sock, F_GETFL); + flags |= O_NONBLOCK; + fcntl(m_sock, F_SETFL, flags); + return m_sock; +} + static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond) { if (cond & PURPLE_INPUT_READ) { char buffer[65535]; @@ -1798,30 +1825,7 @@ int main(int argc, char **argv) { initPurple(); - int portno = port; - struct sockaddr_in serv_addr; - - m_sock = socket(AF_INET, SOCK_STREAM, 0); - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(portno); - - hostent *hos; // Resolve name - if ((hos = gethostbyname(host)) == NULL) { - // strerror() will not work for gethostbyname() and hstrerror() - // is supposedly obsolete - exit(1); - } - serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]); - - if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - close(m_sock); - m_sock = 0; - } - - int flags = fcntl(m_sock, F_GETFL); - flags |= O_NONBLOCK; - fcntl(m_sock, F_SETFL, flags); + m_sock = create_socket(host, port); purple_input_add(m_sock, PURPLE_INPUT_READ, &transportDataReceived, NULL); // purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); diff --git a/cmake_modules/SwiftenConfig.cmake b/cmake_modules/SwiftenConfig.cmake index e28d6470..69aeb3d8 100644 --- a/cmake_modules/SwiftenConfig.cmake +++ b/cmake_modules/SwiftenConfig.cmake @@ -8,8 +8,9 @@ if( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) execute_process( COMMAND ${SWIFTEN_CONFIG_EXECUTABLE} --libs OUTPUT_VARIABLE SWIFTEN_LIBRARY) - string(REGEX REPLACE "[\r\n]" " " SWIFTEN_LIBRARY "${SWIFTEN_LIBRARY}") - string(REGEX REPLACE " +$" "" SWIFTEN_LIBRARY "${SWIFTEN_LIBRARY}") + string(REGEX REPLACE "[\r\n]" " " SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY}) + string(REGEX REPLACE " +$" "" SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY}) + string(REGEX REPLACE " " ";" SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY}) else() message( FATAL_ERROR "Could NOT find swiften-config" ) endif() diff --git a/plugin/src/CMakeLists.txt b/plugin/src/CMakeLists.txt index 6e67ab09..52ce7202 100644 --- a/plugin/src/CMakeLists.txt +++ b/plugin/src/CMakeLists.txt @@ -10,6 +10,12 @@ if (CMAKE_COMPILER_IS_GNUCXX) ADD_DEFINITIONS(-fPIC) endif() +if (NOT WIN32) + TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) +else() + TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ws2_32.lib) +endif() + if (NOT WIN32) TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) else() diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 6447a0d9..5037e6d0 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -65,7 +65,6 @@ static void daemonize(const char *cwd, const char *lock_file) { pid_t pid, sid; FILE* lock_file_f; char process_pid[20]; - /* already a daemon */ if ( getppid() == 1 ) return; @@ -76,11 +75,23 @@ static void daemonize(const char *cwd, const char *lock_file) { } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { + if (lock_file) { + /* write our pid into it & close the file. */ + lock_file_f = fopen(lock_file, "w+"); + if (lock_file_f == NULL) { + std::cerr << "Cannot create lock file " << lock_file << ". Exiting\n"; + exit(1); + } + sprintf(process_pid,"%d\n",pid); + if (fwrite(process_pid,1,strlen(process_pid),lock_file_f) < strlen(process_pid)) { + std::cerr << "Cannot write to lock file " << lock_file << ". Exiting\n"; + exit(1); + } + fclose(lock_file_f); + } exit(0); } - /* At this point we are executing as the child process */ - /* Change the file mode mask */ umask(0); @@ -95,21 +106,6 @@ static void daemonize(const char *cwd, const char *lock_file) { if ((chdir(cwd)) < 0) { exit(1); } - - if (lock_file) { - /* write our pid into it & close the file. */ - lock_file_f = fopen(lock_file, "w+"); - if (lock_file_f == NULL) { - std::cout << "EE cannot create lock file " << lock_file << ". Exiting\n"; - exit(1); - } - sprintf(process_pid,"%d\n",getpid()); - if (fwrite(process_pid,1,strlen(process_pid),lock_file_f) < strlen(process_pid)) { - std::cout << "EE cannot write to lock file " << lock_file << ". Exiting\n"; - exit(1); - } - fclose(lock_file_f); - } if (freopen( "/dev/null", "r", stdin) == NULL) { std::cout << "EE cannot open /dev/null. Exiting\n"; diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 31204ea1..6a4d1efe 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -7,8 +7,22 @@ #include "transport/networkpluginserver.h" #include "Swiften/EventLoop/SimpleEventLoop.h" +#include +#include +#include +#include +#include +#include +#include "signal.h" +#include "sys/wait.h" + + using namespace Transport; +using namespace boost::filesystem; + +using namespace boost; + static int finished; static std::string *m; @@ -37,19 +51,172 @@ static void handleMessageReceived(Swift::Client *client, Swift::Message::ref mes } } +static std::string searchForBinary(const std::string &binary) { + std::vector path_list; + char * env_path = getenv("PATH"); + + if (env_path != NULL) { + std::string buffer = ""; + for (int s = 0; s < strlen(env_path); s++) { + if (env_path[s] == ':') { + path_list.insert(path_list.end(), std::string(buffer)); + buffer = ""; + } + else { + buffer += env_path[s]; + } + } + + if (buffer != "") { + path_list.insert(path_list.end(), std::string(buffer)); + buffer = ""; + } + + for (std::vector::iterator dit = path_list.begin(); dit < path_list.end(); dit++) { + std::string bpath = *dit; + bpath += "/"; + bpath += binary; + path p(bpath); + if (exists(p) && !is_directory(p)) { + return bpath; + } + } + } + return ""; +} + +// Executes new backend +static unsigned long exec_(std::string path, std::string config) { + // fork and exec + pid_t pid = fork(); + if ( pid == 0 ) { + // child process + exit(execl(path.c_str(), path.c_str(), config.c_str(), NULL)); + } else if ( pid < 0 ) { + // fork failed + } + else { + waitpid(pid, 0, 0); + } + + return (unsigned long) pid; +} + +static int isRunning(const std::string &pidfile) { + path p(pidfile); + if (!exists(p) || is_directory(p)) { + return 0; + } + + std::ifstream f(p.string().c_str(), std::ios_base::in); + std::string pid; + f >> pid; + + if (pid.empty()) + return 0; + + if (kill(boost::lexical_cast(pid), 0) != 0) + return 0; + + return boost::lexical_cast(pid); +} + +static void start_all_instances(ManagerConfig *config) { + path p(CONFIG_STRING(config, "service.config_directory")); + + try { + if (!exists(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(6); + } + + if (!is_directory(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(7); + } + + std::string spectrum2_binary = searchForBinary("spectrum2"); + if (spectrum2_binary.empty()) { + std::cerr << "spectrum2 binary not found in PATH\n"; + exit(8); + } + + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { + Config cfg; + if (cfg.load(itr->path().string()) == false) { + std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; + } + + if (!isRunning(CONFIG_STRING(&cfg, "service.pidfile"))) { + exec_(spectrum2_binary, itr->path().string()); + } + } + } + } + catch (const filesystem_error& ex) { + std::cerr << "boost filesystem error\n"; + exit(5); + } +} + +static void stop_all_instances(ManagerConfig *config) { + path p(CONFIG_STRING(config, "service.config_directory")); + + try { + if (!exists(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(6); + } + + if (!is_directory(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(7); + } + + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { + Config cfg; + if (cfg.load(itr->path().string()) == false) { + std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; + } + + int pid = isRunning(CONFIG_STRING(&cfg, "service.pidfile")); + if (pid) { + kill(pid, SIGTERM); + } + } + } + } + catch (const filesystem_error& ex) { + std::cerr << "boost filesystem error\n"; + exit(5); + } +} + int main(int argc, char **argv) { ManagerConfig config; + std::string config_file; + std::string command; + boost::program_options::variables_map vm; - boost::program_options::options_description desc("Usage: spectrum_manager \nAllowed options"); + boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); desc.add_options() - ("help,h", "help") + ("help,h", "Show help output") + ("config,c", boost::program_options::value(&config_file)->default_value("/etc/spectrum2/spectrum-manager.cfg"), "Spectrum manager config file") + ("command", boost::program_options::value(&command)->default_value(""), "Command") ; try { - boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::positional_options_description p; + p.add("command", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).run(), vm); boost::program_options::notify(vm); + if(vm.count("help")) { std::cout << desc << "\n"; @@ -59,44 +226,47 @@ int main(int argc, char **argv) catch (std::runtime_error& e) { std::cout << desc << "\n"; - return 1; + return 2; } catch (...) { std::cout << desc << "\n"; - return 1; - } - - if (argc != 3) { - std::cout << desc << "\n"; - return 1; + return 3; } - if (!config.load(argv[1])) { + if (!config.load(config_file)) { std::cerr << "Can't load configuration file.\n"; - return 1; + return 4; } - Swift::SimpleEventLoop eventLoop; - Swift::BoostNetworkFactories networkFactories(&eventLoop); - - std::string message = argv[2]; - m = &message; - - std::vector servers = CONFIG_VECTOR(&config, "servers.server"); - for (std::vector::const_iterator it = servers.begin(); it != servers.end(); it++) { - finished++; - Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + (*it), CONFIG_STRING(&config, "service.admin_password"), &networkFactories); - client->setAlwaysTrustCertificates(); - client->onConnected.connect(boost::bind(&handleConnected, client)); - client->onDisconnected.connect(bind(&handleDisconnected, client, _1)); - client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1)); - Swift::ClientOptions opt; - opt.allowPLAINWithoutTLS = true; - client->connect(opt); -// std::cout << *it << "\n"; + if (command == "start") { + start_all_instances(&config); } + else if (command == "stop") { + stop_all_instances(&config); + } + else { + Swift::SimpleEventLoop eventLoop; + Swift::BoostNetworkFactories networkFactories(&eventLoop); - eventLoop.run(); + std::string message = argv[1]; + m = &message; + + std::vector servers = CONFIG_VECTOR(&config, "servers.server"); + for (std::vector::const_iterator it = servers.begin(); it != servers.end(); it++) { + finished++; + Swift::Client *client = new Swift::Client(CONFIG_STRING(&config, "service.admin_username") + "@" + (*it), CONFIG_STRING(&config, "service.admin_password"), &networkFactories); + client->setAlwaysTrustCertificates(); + client->onConnected.connect(boost::bind(&handleConnected, client)); + client->onDisconnected.connect(bind(&handleDisconnected, client, _1)); + client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1)); + Swift::ClientOptions opt; + opt.allowPLAINWithoutTLS = true; + client->connect(opt); + // std::cout << *it << "\n"; + } + + eventLoop.run(); + } } diff --git a/spectrum_manager/src/managerconfig.cpp b/spectrum_manager/src/managerconfig.cpp index 4af0300c..807bab8b 100644 --- a/spectrum_manager/src/managerconfig.cpp +++ b/spectrum_manager/src/managerconfig.cpp @@ -31,6 +31,7 @@ bool ManagerConfig::load(const std::string &configfile, boost::program_options:: opts.add_options() ("service.admin_username", value()->default_value(""), "Administrator username.") ("service.admin_password", value()->default_value(""), "Administrator password.") + ("service.config_directory", value()->default_value("/etc/spectrum2/transports/"), "Directory with spectrum2 configuration files. One .cfg file per one instance") ("servers.server", value >()->multitoken(), "Server.") ; diff --git a/spectrum_manager/src/spectrum_manager.cfg b/spectrum_manager/src/spectrum_manager.cfg index 1973021f..d520a467 100644 --- a/spectrum_manager/src/spectrum_manager.cfg +++ b/spectrum_manager/src/spectrum_manager.cfg @@ -1,6 +1,7 @@ [service] admin_username=admin admin_password=test +config_directory=/etc/spectrum2/transports/ [servers] server=localhost