spectrum2_manager can run as web-server providing simple web-interface
This commit is contained in:
parent
5daa8bb514
commit
254143e164
8 changed files with 5786 additions and 449 deletions
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
FILE(GLOB SRC *.cpp)
|
||||
FILE(GLOB SRC *.cpp *.c)
|
||||
|
||||
ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc)
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "managerconfig.h"
|
||||
#include "methods.h"
|
||||
#include "server.h"
|
||||
#include "transport/config.h"
|
||||
#include "transport/protocol.pb.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
|
@ -14,11 +16,6 @@
|
|||
#include "signal.h"
|
||||
#include "sys/wait.h"
|
||||
|
||||
#define WRAP(MESSAGE, TYPE) pbnetwork::WrapperMessage wrap; \
|
||||
wrap.set_type(TYPE); \
|
||||
wrap.set_payload(MESSAGE); \
|
||||
wrap.SerializeToString(&MESSAGE);
|
||||
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
|
@ -26,447 +23,6 @@ using namespace boost::filesystem;
|
|||
|
||||
using namespace boost;
|
||||
|
||||
std::string _data;
|
||||
|
||||
static std::string searchForBinary(const std::string &binary) {
|
||||
std::vector<std::string> 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<std::string>::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, std::string jid = "") {
|
||||
// fork and exec
|
||||
pid_t pid = fork();
|
||||
if ( pid == 0 ) {
|
||||
// child process
|
||||
if (jid.empty()) {
|
||||
exit(execl(path.c_str(), path.c_str(), config.c_str(), NULL));
|
||||
}
|
||||
else {
|
||||
exit(execl(path.c_str(), path.c_str(), "-j", jid.c_str(), config.c_str(), NULL));
|
||||
}
|
||||
} else if ( pid < 0 ) {
|
||||
// fork failed
|
||||
}
|
||||
else {
|
||||
waitpid(pid, 0, 0);
|
||||
}
|
||||
|
||||
return (unsigned long) pid;
|
||||
}
|
||||
|
||||
static int getPort(const std::string &portfile) {
|
||||
path p(portfile);
|
||||
if (!exists(p) || is_directory(p)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::ifstream f(p.string().c_str(), std::ios_base::in);
|
||||
std::string port;
|
||||
f >> port;
|
||||
|
||||
if (port.empty())
|
||||
return 0;
|
||||
|
||||
return boost::lexical_cast<int>(port);
|
||||
}
|
||||
|
||||
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<int>(pid), 0) != 0)
|
||||
return 0;
|
||||
|
||||
return boost::lexical_cast<int>(pid);
|
||||
}
|
||||
|
||||
static void start_instances(ManagerConfig *config, const std::string &_jid = "") {
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_jid.empty() && _jid != vhost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid == 0) {
|
||||
std::cout << "Starting " << itr->path() << ": OK\n";
|
||||
exec_(spectrum2_binary, itr->path().string(), vhost);
|
||||
}
|
||||
else {
|
||||
std::cout << "Starting " << itr->path() << ": Already started (PID=" << pid << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_instances(ManagerConfig *config, const std::string &_jid = "") {
|
||||
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";
|
||||
}
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_jid.empty() && _jid != vhost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid) {
|
||||
std::cout << "Stopping " << itr->path() << ": ";
|
||||
kill(pid, SIGTERM);
|
||||
|
||||
sleep(1);
|
||||
int count = 20;
|
||||
while (kill(pid, 0) == 0 && count != 0) {
|
||||
std::cout << ".";
|
||||
sleep(1);
|
||||
count--;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << " ERROR (timeout)\n";
|
||||
}
|
||||
else {
|
||||
std::cout << " OK\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Stopping " << itr->path() << ": Not running\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
static int show_status(ManagerConfig *config) {
|
||||
int ret = 0;
|
||||
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";
|
||||
}
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid) {
|
||||
std::cout << itr->path() << ": " << vhost << " Running\n";
|
||||
}
|
||||
else {
|
||||
ret = 3;
|
||||
std::cout << itr->path() << ": " << vhost << " Stopped\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handleDataRead(boost::shared_ptr<Swift::Connection> m_conn, boost::shared_ptr<Swift::SafeByteArray> data) {
|
||||
_data += std::string(data->begin(), data->end());
|
||||
|
||||
// Parse data while there are some
|
||||
while (_data.size() != 0) {
|
||||
// expected_size of wrapper message
|
||||
unsigned int expected_size;
|
||||
|
||||
// if data is >= 4, we have whole header and we can
|
||||
// read expected_size.
|
||||
if (_data.size() >= 4) {
|
||||
expected_size = *((unsigned int*) &_data[0]);
|
||||
expected_size = ntohl(expected_size);
|
||||
// If we don't have whole wrapper message, wait for next
|
||||
// handleDataRead call.
|
||||
if (_data.size() - 4 < expected_size)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse wrapper message and erase it from buffer.
|
||||
pbnetwork::WrapperMessage wrapper;
|
||||
if (wrapper.ParseFromArray(&_data[4], expected_size) == false) {
|
||||
std::cout << "PARSING ERROR " << expected_size << "\n";
|
||||
_data.erase(_data.begin(), _data.begin() + 4 + expected_size);
|
||||
continue;
|
||||
}
|
||||
_data.erase(_data.begin(), _data.begin() + 4 + expected_size);
|
||||
|
||||
if (wrapper.type() == pbnetwork::WrapperMessage_Type_TYPE_QUERY) {
|
||||
pbnetwork::BackendConfig payload;
|
||||
if (payload.ParseFromString(wrapper.payload()) == false) {
|
||||
std::cout << "PARSING ERROR\n";
|
||||
// TODO: ERROR
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << payload.config() << "\n";
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handleConnected(boost::shared_ptr<Swift::Connection> m_conn, const std::string &msg, bool error) {
|
||||
if (error) {
|
||||
std::cerr << "Can't connect the server\n";
|
||||
exit(50);
|
||||
}
|
||||
else {
|
||||
pbnetwork::BackendConfig m;
|
||||
m.set_config(msg);
|
||||
|
||||
std::string message;
|
||||
m.SerializeToString(&message);
|
||||
|
||||
WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_QUERY);
|
||||
|
||||
uint32_t size = htonl(message.size());
|
||||
char *header = (char *) &size;
|
||||
|
||||
|
||||
// send header together with wrapper message
|
||||
m_conn->write(Swift::createSafeByteArray(std::string(header, 4) + message));
|
||||
}
|
||||
}
|
||||
|
||||
static void ask_local_server(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &jid, const std::string &message) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CONFIG_STRING(&cfg, "service.jid") != jid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
boost::shared_ptr<Swift::Connection> m_conn;
|
||||
m_conn = networkFactories.getConnectionFactory()->createConnection();
|
||||
m_conn->onDataRead.connect(boost::bind(&handleDataRead, m_conn, _1));
|
||||
m_conn->onConnectFinished.connect(boost::bind(&handleConnected, m_conn, message, _1));
|
||||
m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(CONFIG_STRING(&cfg, "service.backend_host")), getPort(CONFIG_STRING(&cfg, "service.portfile"))));
|
||||
|
||||
// finished++;
|
||||
// Swift::Client *client = new Swift::Client(CONFIG_VECTOR(&cfg, "service.admin_jid")[0], CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories);
|
||||
// client->setAlwaysTrustCertificates();
|
||||
// client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// Swift::ClientOptions opt;
|
||||
// opt.allowPLAINWithoutTLS = true;
|
||||
// client->connect(opt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
std::cerr << "Config file for Spectrum instance with this JID was not found\n";
|
||||
exit(20);
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_list(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);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << CONFIG_STRING(&cfg, "service.jid") << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
// static void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) {
|
||||
// path p(CONFIG_STRING(config, "service.config_directory"));
|
||||
|
@ -579,7 +135,12 @@ int main(int argc, char **argv)
|
|||
return show_status(&config);
|
||||
}
|
||||
else if (command[0] == "list") {
|
||||
show_list(&config);
|
||||
std::vector<std::string> list = show_list(&config);
|
||||
}
|
||||
else if (command[0] == "server") {
|
||||
Server server(&config);
|
||||
server.start(8080, "test", "test");
|
||||
while (1) { sleep(10); }
|
||||
}
|
||||
else {
|
||||
if (command.size() < 2) {
|
||||
|
@ -608,6 +169,23 @@ int main(int argc, char **argv)
|
|||
|
||||
// ask_local_server(&config, networkFactories, message);
|
||||
|
||||
eventLoop.run();
|
||||
eventLoop.runUntilEvents();
|
||||
|
||||
|
||||
struct timeval td_start,td_end;
|
||||
float elapsed = 0;
|
||||
gettimeofday(&td_start, NULL);
|
||||
|
||||
time_t started = time(NULL);
|
||||
while(get_response().empty()) {
|
||||
eventLoop.runUntilEvents();
|
||||
}
|
||||
if (!get_response().empty()) {
|
||||
gettimeofday(&td_end, NULL);
|
||||
elapsed = 1000000.0 * (td_end.tv_sec -td_start.tv_sec); \
|
||||
elapsed += (td_end.tv_usec - td_start.tv_usec); \
|
||||
elapsed = elapsed / 1000 / 1000; \
|
||||
std::cout << "Response received after " << (elapsed) << " seconds\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
492
spectrum_manager/src/methods.cpp
Normal file
492
spectrum_manager/src/methods.cpp
Normal file
|
@ -0,0 +1,492 @@
|
|||
#include "methods.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cstdlib>
|
||||
#include "signal.h"
|
||||
#include "sys/wait.h"
|
||||
|
||||
#define WRAP(MESSAGE, TYPE) pbnetwork::WrapperMessage wrap; \
|
||||
wrap.set_type(TYPE); \
|
||||
wrap.set_payload(MESSAGE); \
|
||||
wrap.SerializeToString(&MESSAGE);
|
||||
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
using namespace boost::filesystem;
|
||||
|
||||
using namespace boost;
|
||||
|
||||
std::string _data;
|
||||
static std::string response;
|
||||
|
||||
std::string get_response() {
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string searchForBinary(const std::string &binary) {
|
||||
std::vector<std::string> 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<std::string>::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
|
||||
unsigned long exec_(std::string path, std::string config, std::string jid) {
|
||||
// fork and exec
|
||||
pid_t pid = fork();
|
||||
if ( pid == 0 ) {
|
||||
// child process
|
||||
if (jid.empty()) {
|
||||
exit(execl(path.c_str(), path.c_str(), config.c_str(), NULL));
|
||||
}
|
||||
else {
|
||||
exit(execl(path.c_str(), path.c_str(), "-j", jid.c_str(), config.c_str(), NULL));
|
||||
}
|
||||
} else if ( pid < 0 ) {
|
||||
// fork failed
|
||||
}
|
||||
else {
|
||||
waitpid(pid, 0, 0);
|
||||
}
|
||||
|
||||
return (unsigned long) pid;
|
||||
}
|
||||
|
||||
int getPort(const std::string &portfile) {
|
||||
path p(portfile);
|
||||
if (!exists(p) || is_directory(p)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::ifstream f(p.string().c_str(), std::ios_base::in);
|
||||
std::string port;
|
||||
f >> port;
|
||||
|
||||
if (port.empty())
|
||||
return 0;
|
||||
|
||||
return boost::lexical_cast<int>(port);
|
||||
}
|
||||
|
||||
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<int>(pid), 0) != 0)
|
||||
return 0;
|
||||
|
||||
return boost::lexical_cast<int>(pid);
|
||||
}
|
||||
|
||||
void start_instances(ManagerConfig *config, const std::string &_jid) {
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_jid.empty() && _jid != vhost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid == 0) {
|
||||
std::cout << "Starting " << itr->path() << ": OK\n";
|
||||
exec_(spectrum2_binary, itr->path().string(), vhost);
|
||||
}
|
||||
else {
|
||||
std::cout << "Starting " << itr->path() << ": Already started (PID=" << pid << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
void stop_instances(ManagerConfig *config, const std::string &_jid) {
|
||||
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";
|
||||
}
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_jid.empty() && _jid != vhost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid) {
|
||||
std::cout << "Stopping " << itr->path() << ": ";
|
||||
kill(pid, SIGTERM);
|
||||
|
||||
sleep(1);
|
||||
int count = 20;
|
||||
while (kill(pid, 0) == 0 && count != 0) {
|
||||
std::cout << ".";
|
||||
sleep(1);
|
||||
count--;
|
||||
}
|
||||
if (count == 0) {
|
||||
std::cout << " ERROR (timeout)\n";
|
||||
}
|
||||
else {
|
||||
std::cout << " OK\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Stopping " << itr->path() << ": Not running\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
int show_status(ManagerConfig *config) {
|
||||
int ret = 0;
|
||||
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";
|
||||
}
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid) {
|
||||
std::cout << itr->path() << ": " << vhost << " Running\n";
|
||||
}
|
||||
else {
|
||||
ret = 3;
|
||||
std::cout << itr->path() << ": " << vhost << " Stopped\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handleDataRead(boost::shared_ptr<Swift::Connection> m_conn, boost::shared_ptr<Swift::SafeByteArray> data) {
|
||||
_data += std::string(data->begin(), data->end());
|
||||
|
||||
// Parse data while there are some
|
||||
while (_data.size() != 0) {
|
||||
// expected_size of wrapper message
|
||||
unsigned int expected_size;
|
||||
|
||||
// if data is >= 4, we have whole header and we can
|
||||
// read expected_size.
|
||||
if (_data.size() >= 4) {
|
||||
expected_size = *((unsigned int*) &_data[0]);
|
||||
expected_size = ntohl(expected_size);
|
||||
// If we don't have whole wrapper message, wait for next
|
||||
// handleDataRead call.
|
||||
if (_data.size() - 4 < expected_size)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse wrapper message and erase it from buffer.
|
||||
pbnetwork::WrapperMessage wrapper;
|
||||
if (wrapper.ParseFromArray(&_data[4], expected_size) == false) {
|
||||
std::cout << "PARSING ERROR " << expected_size << "\n";
|
||||
_data.erase(_data.begin(), _data.begin() + 4 + expected_size);
|
||||
continue;
|
||||
}
|
||||
_data.erase(_data.begin(), _data.begin() + 4 + expected_size);
|
||||
|
||||
if (wrapper.type() == pbnetwork::WrapperMessage_Type_TYPE_QUERY) {
|
||||
pbnetwork::BackendConfig payload;
|
||||
if (payload.ParseFromString(wrapper.payload()) == false) {
|
||||
std::cout << "PARSING ERROR\n";
|
||||
// TODO: ERROR
|
||||
continue;
|
||||
}
|
||||
m_conn->onDataRead.disconnect(boost::bind(&handleDataRead, m_conn, _1));
|
||||
response = payload.config();
|
||||
std::cout << payload.config() << "\n";
|
||||
// exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handleConnected(boost::shared_ptr<Swift::Connection> m_conn, const std::string &msg, bool error) {
|
||||
m_conn->onConnectFinished.disconnect(boost::bind(&handleConnected, m_conn, msg, _1));
|
||||
if (error) {
|
||||
std::cerr << "Can't connect the server\n";
|
||||
response = "Can't connect the server\n";
|
||||
m_conn->onDataRead.disconnect(boost::bind(&handleDataRead, m_conn, _1));
|
||||
|
||||
// exit(50);
|
||||
}
|
||||
else {
|
||||
pbnetwork::BackendConfig m;
|
||||
m.set_config(msg);
|
||||
|
||||
std::string message;
|
||||
m.SerializeToString(&message);
|
||||
|
||||
WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_QUERY);
|
||||
|
||||
uint32_t size = htonl(message.size());
|
||||
char *header = (char *) &size;
|
||||
|
||||
|
||||
// send header together with wrapper message
|
||||
m_conn->write(Swift::createSafeByteArray(std::string(header, 4) + message));
|
||||
}
|
||||
}
|
||||
|
||||
void ask_local_server(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &jid, const std::string &message) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CONFIG_STRING(&cfg, "service.jid") != jid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
boost::shared_ptr<Swift::Connection> m_conn;
|
||||
m_conn = networkFactories.getConnectionFactory()->createConnection();
|
||||
m_conn->onDataRead.connect(boost::bind(&handleDataRead, m_conn, _1));
|
||||
m_conn->onConnectFinished.connect(boost::bind(&handleConnected, m_conn, message, _1));
|
||||
m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(CONFIG_STRING(&cfg, "service.backend_host")), getPort(CONFIG_STRING(&cfg, "service.portfile"))));
|
||||
|
||||
// finished++;
|
||||
// Swift::Client *client = new Swift::Client(CONFIG_VECTOR(&cfg, "service.admin_jid")[0], CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories);
|
||||
// client->setAlwaysTrustCertificates();
|
||||
// client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid")));
|
||||
// Swift::ClientOptions opt;
|
||||
// opt.allowPLAINWithoutTLS = true;
|
||||
// client->connect(opt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
std::cerr << "Config file for Spectrum instance with this JID was not found\n";
|
||||
exit(20);
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> show_list(ManagerConfig *config, bool show) {
|
||||
path p(CONFIG_STRING(config, "service.config_directory"));
|
||||
std::vector<std::string> list;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
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";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
std::cout << CONFIG_STRING(&cfg, "service.jid") << "\n";
|
||||
}
|
||||
list.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
56
spectrum_manager/src/methods.h
Normal file
56
spectrum_manager/src/methods.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
#include "managerconfig.h"
|
||||
#include "transport/config.h"
|
||||
#include "transport/protocol.pb.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "Swiften/EventLoop/SimpleEventLoop.h"
|
||||
|
||||
|
||||
|
||||
std::string searchForBinary(const std::string &binary);
|
||||
|
||||
// Executes new backend
|
||||
unsigned long exec_(std::string path, std::string config, std::string jid = "");
|
||||
|
||||
int getPort(const std::string &portfile);
|
||||
|
||||
int isRunning(const std::string &pidfile);
|
||||
void start_instances(ManagerConfig *config, const std::string &_jid = "");
|
||||
void stop_instances(ManagerConfig *config, const std::string &_jid = "");
|
||||
|
||||
int show_status(ManagerConfig *config);
|
||||
|
||||
void ask_local_server(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &jid, const std::string &message);
|
||||
|
||||
std::vector<std::string> show_list(ManagerConfig *config, bool show = true);
|
||||
|
||||
std::string get_response();
|
4470
spectrum_manager/src/mongoose.c
Normal file
4470
spectrum_manager/src/mongoose.c
Normal file
File diff suppressed because it is too large
Load diff
301
spectrum_manager/src/mongoose.h
Normal file
301
spectrum_manager/src/mongoose.h
Normal file
|
@ -0,0 +1,301 @@
|
|||
// Copyright (c) 2004-2012 Sergey Lyubka
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef MONGOOSE_HEADER_INCLUDED
|
||||
#define MONGOOSE_HEADER_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
struct mg_context; // Handle for the HTTP service itself
|
||||
struct mg_connection; // Handle for the individual connection
|
||||
|
||||
|
||||
// This structure contains information about the HTTP request.
|
||||
struct mg_request_info {
|
||||
void *user_data; // User-defined pointer passed to mg_start()
|
||||
char *request_method; // "GET", "POST", etc
|
||||
char *uri; // URL-decoded URI
|
||||
char *http_version; // E.g. "1.0", "1.1"
|
||||
char *query_string; // URL part after '?' (not including '?') or NULL
|
||||
char *remote_user; // Authenticated user, or NULL if no auth used
|
||||
char *log_message; // Mongoose error log message, MG_EVENT_LOG only
|
||||
long remote_ip; // Client's IP address
|
||||
int remote_port; // Client's port
|
||||
int status_code; // HTTP reply status code, e.g. 200
|
||||
int is_ssl; // 1 if SSL-ed, 0 if not
|
||||
int num_headers; // Number of headers
|
||||
struct mg_header {
|
||||
char *name; // HTTP header name
|
||||
char *value; // HTTP header value
|
||||
} http_headers[64]; // Maximum 64 headers
|
||||
};
|
||||
|
||||
// Various events on which user-defined function is called by Mongoose.
|
||||
enum mg_event {
|
||||
MG_NEW_REQUEST, // New HTTP request has arrived from the client
|
||||
MG_REQUEST_COMPLETE, // Mongoose has finished handling the request
|
||||
MG_HTTP_ERROR, // HTTP error must be returned to the client
|
||||
MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
|
||||
MG_INIT_SSL // Mongoose initializes SSL. Instead of mg_connection *,
|
||||
// SSL context is passed to the callback function.
|
||||
};
|
||||
|
||||
// Prototype for the user-defined function. Mongoose calls this function
|
||||
// on every MG_* event.
|
||||
//
|
||||
// Parameters:
|
||||
// event: which event has been triggered.
|
||||
// conn: opaque connection handler. Could be used to read, write data to the
|
||||
// client, etc. See functions below that have "mg_connection *" arg.
|
||||
//
|
||||
// Return:
|
||||
// If handler returns non-NULL, that means that handler has processed the
|
||||
// request by sending appropriate HTTP reply to the client. Mongoose treats
|
||||
// the request as served.
|
||||
// If handler returns NULL, that means that handler has not processed
|
||||
// the request. Handler must not send any data to the client in this case.
|
||||
// Mongoose proceeds with request handling as if nothing happened.
|
||||
typedef void * (*mg_callback_t)(enum mg_event event,
|
||||
struct mg_connection *conn);
|
||||
|
||||
|
||||
// Start web server.
|
||||
//
|
||||
// Parameters:
|
||||
// callback: user defined event handling function or NULL.
|
||||
// options: NULL terminated list of option_name, option_value pairs that
|
||||
// specify Mongoose configuration parameters.
|
||||
//
|
||||
// Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
|
||||
// processing is required for these, signal handlers must be set up
|
||||
// after calling mg_start().
|
||||
//
|
||||
//
|
||||
// Example:
|
||||
// const char *options[] = {
|
||||
// "document_root", "/var/www",
|
||||
// "listening_ports", "80,443s",
|
||||
// NULL
|
||||
// };
|
||||
// struct mg_context *ctx = mg_start(&my_func, NULL, options);
|
||||
//
|
||||
// Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual
|
||||
// for the list of valid option and their possible values.
|
||||
//
|
||||
// Return:
|
||||
// web server context, or NULL on error.
|
||||
struct mg_context *mg_start(mg_callback_t callback, void *user_data,
|
||||
const char **options);
|
||||
|
||||
|
||||
// Stop the web server.
|
||||
//
|
||||
// Must be called last, when an application wants to stop the web server and
|
||||
// release all associated resources. This function blocks until all Mongoose
|
||||
// threads are stopped. Context pointer becomes invalid.
|
||||
void mg_stop(struct mg_context *);
|
||||
|
||||
|
||||
// Get the value of particular configuration parameter.
|
||||
// The value returned is read-only. Mongoose does not allow changing
|
||||
// configuration at run time.
|
||||
// If given parameter name is not valid, NULL is returned. For valid
|
||||
// names, return value is guaranteed to be non-NULL. If parameter is not
|
||||
// set, zero-length string is returned.
|
||||
const char *mg_get_option(const struct mg_context *ctx, const char *name);
|
||||
|
||||
|
||||
// Return array of strings that represent valid configuration options.
|
||||
// For each option, a short name, long name, and default value is returned.
|
||||
// Array is NULL terminated.
|
||||
const char **mg_get_valid_option_names(void);
|
||||
|
||||
|
||||
// Add, edit or delete the entry in the passwords file.
|
||||
//
|
||||
// This function allows an application to manipulate .htpasswd files on the
|
||||
// fly by adding, deleting and changing user records. This is one of the
|
||||
// several ways of implementing authentication on the server side. For another,
|
||||
// cookie-based way please refer to the examples/chat.c in the source tree.
|
||||
//
|
||||
// If password is not NULL, entry is added (or modified if already exists).
|
||||
// If password is NULL, entry is deleted.
|
||||
//
|
||||
// Return:
|
||||
// 1 on success, 0 on error.
|
||||
int mg_modify_passwords_file(const char *passwords_file_name,
|
||||
const char *domain,
|
||||
const char *user,
|
||||
const char *password);
|
||||
|
||||
|
||||
// Return mg_request_info structure associated with the request.
|
||||
// Always succeeds.
|
||||
const struct mg_request_info *mg_get_request_info(const struct mg_connection *);
|
||||
|
||||
|
||||
// Send data to the client.
|
||||
// Return:
|
||||
// 0 when the connection has been closed
|
||||
// -1 on error
|
||||
// number of bytes written on success
|
||||
int mg_write(struct mg_connection *, const void *buf, size_t len);
|
||||
|
||||
|
||||
// Send data to the browser using printf() semantics.
|
||||
//
|
||||
// Works exactly like mg_write(), but allows to do message formatting.
|
||||
// Below are the macros for enabling compiler-specific checks for
|
||||
// printf-like arguments.
|
||||
|
||||
#undef PRINTF_FORMAT_STRING
|
||||
#if _MSC_VER >= 1400
|
||||
#include <sal.h>
|
||||
#if _MSC_VER > 1400
|
||||
#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
|
||||
#else
|
||||
#define PRINTF_FORMAT_STRING(s) __format_string s
|
||||
#endif
|
||||
#else
|
||||
#define PRINTF_FORMAT_STRING(s) s
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
|
||||
#else
|
||||
#define PRINTF_ARGS(x, y)
|
||||
#endif
|
||||
|
||||
int mg_printf(struct mg_connection *,
|
||||
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
||||
|
||||
|
||||
// Send contents of the entire file together with HTTP headers.
|
||||
void mg_send_file(struct mg_connection *conn, const char *path);
|
||||
|
||||
|
||||
// Read data from the remote end, return number of bytes read.
|
||||
int mg_read(struct mg_connection *, void *buf, size_t len);
|
||||
|
||||
|
||||
// Get the value of particular HTTP header.
|
||||
//
|
||||
// This is a helper function. It traverses request_info->http_headers array,
|
||||
// and if the header is present in the array, returns its value. If it is
|
||||
// not present, NULL is returned.
|
||||
const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||
|
||||
|
||||
// Get a value of particular form variable.
|
||||
//
|
||||
// Parameters:
|
||||
// data: pointer to form-uri-encoded buffer. This could be either POST data,
|
||||
// or request_info.query_string.
|
||||
// data_len: length of the encoded data.
|
||||
// var_name: variable name to decode from the buffer
|
||||
// buf: destination buffer for the decoded variable
|
||||
// buf_len: length of the destination buffer
|
||||
//
|
||||
// Return:
|
||||
// On success, length of the decoded variable.
|
||||
// On error:
|
||||
// -1 (variable not found, or destination buffer is too small).
|
||||
// -2 (destination buffer is NULL or zero length).
|
||||
//
|
||||
// Destination buffer is guaranteed to be '\0' - terminated if it is not
|
||||
// NULL or zero length. In case of failure, dst[0] == '\0'.
|
||||
int mg_get_var(const char *data, size_t data_len,
|
||||
const char *var_name, char *buf, size_t buf_len);
|
||||
|
||||
// Fetch value of certain cookie variable into the destination buffer.
|
||||
//
|
||||
// Destination buffer is guaranteed to be '\0' - terminated. In case of
|
||||
// failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
|
||||
// parameter. This function returns only first occurrence.
|
||||
//
|
||||
// Return:
|
||||
// On success, value length.
|
||||
// On error, -1 (either "Cookie:" header is not present at all, or the
|
||||
// requested parameter is not found, or destination buffer is too small
|
||||
// to hold the value).
|
||||
int mg_get_cookie(const struct mg_connection *,
|
||||
const char *cookie_name, char *buf, size_t buf_len);
|
||||
|
||||
|
||||
// Connect to the remote web server.
|
||||
// Return:
|
||||
// On success, valid pointer to the new connection
|
||||
// On error, NULL
|
||||
struct mg_connection *mg_connect(struct mg_context *ctx,
|
||||
const char *host, int port, int use_ssl);
|
||||
|
||||
|
||||
// Close the connection opened by mg_connect().
|
||||
void mg_close_connection(struct mg_connection *conn);
|
||||
|
||||
|
||||
// Download given URL to a given file.
|
||||
// url: URL to download
|
||||
// path: file name where to save the data
|
||||
// request_info: pointer to a structure that will hold parsed reply headers
|
||||
// buf, bul_len: a buffer for the reply headers
|
||||
// Return:
|
||||
// On error, NULL
|
||||
// On success, opened file stream to the downloaded contents. The stream
|
||||
// is positioned to the end of the file. It is the user's responsibility
|
||||
// to fclose() the opened file stream.
|
||||
FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
|
||||
char *buf, size_t buf_len, struct mg_request_info *request_info);
|
||||
|
||||
|
||||
// Convenience function -- create detached thread.
|
||||
// Return: 0 on success, non-0 on error.
|
||||
typedef void * (*mg_thread_func_t)(void *);
|
||||
int mg_start_thread(mg_thread_func_t f, void *p);
|
||||
|
||||
|
||||
// Return builtin mime type for the given file name.
|
||||
// For unrecognized extensions, "text/plain" is returned.
|
||||
const char *mg_get_builtin_mime_type(const char *file_name);
|
||||
|
||||
|
||||
// Return Mongoose version.
|
||||
const char *mg_version(void);
|
||||
|
||||
|
||||
// MD5 hash given strings.
|
||||
// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
|
||||
// ASCIIz strings. When function returns, buf will contain human-readable
|
||||
// MD5 hash. Example:
|
||||
// char buf[33];
|
||||
// mg_md5(buf, "aa", "bb", NULL);
|
||||
void mg_md5(char buf[33], ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // MONGOOSE_HEADER_INCLUDED
|
365
spectrum_manager/src/server.cpp
Normal file
365
spectrum_manager/src/server.cpp
Normal file
|
@ -0,0 +1,365 @@
|
|||
#include "server.h"
|
||||
#include "methods.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define SESSION_TTL 120
|
||||
|
||||
static std::string get_header() {
|
||||
return "\
|
||||
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\
|
||||
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> \
|
||||
<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" dir=\"ltr\"> \
|
||||
<head>\
|
||||
<title>Spectrum 2 web interface</title>\
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\
|
||||
<style type=\"text/css\">\
|
||||
body{ background-color: #F9F9F9; color: #444444; font: normal normal 14px \"Helvetica\", \"Arial\", Sans-Serif; }\
|
||||
\
|
||||
pre, kbd, var, samp, tt{ font-family: \"Courier\", Monospace; }\
|
||||
\
|
||||
pre { font-size: 12px; }\
|
||||
\
|
||||
h1, h2, h3, h4, h5, h6, pre{ color: #094776; }\
|
||||
\
|
||||
h1{ font-size: 28px; }\
|
||||
\
|
||||
h2{ font-size: 24px; font-weight: normal; }\
|
||||
\
|
||||
h1, h2, h3, h4, h5, h6{ margin-bottom: 20px; }\
|
||||
\
|
||||
h2, h3{ border-bottom: 2px solid #EEEEEE; padding: 0 0 3px; } \
|
||||
\
|
||||
h3{ border-color: #E5E5E5; border-width: 1px; }\
|
||||
\
|
||||
h4{ font-size: 18px; }\
|
||||
\
|
||||
h1 a, h2 a{ font-weight: normal; }\
|
||||
\
|
||||
h1 a, h2 a, h3 a{ text-decoration: none; }\
|
||||
\
|
||||
h3, h5, h6{ font-size: 18px; }\
|
||||
\
|
||||
h4, h5, h6{ font-size: 14px; }\
|
||||
\
|
||||
p, dl, ul, ol{ margin: 20px 0; }\
|
||||
\
|
||||
p, dl, ul, ol, h3, h4, h5, h6{ margin-left: 20px; }\
|
||||
\
|
||||
li > ul,\
|
||||
li > ol{ margin: 0; margin-left: 40px; }\
|
||||
\
|
||||
dl > dd{ margin-left: 20px; }\
|
||||
\
|
||||
li > p { margin: 0; }\
|
||||
\
|
||||
p, li, dd, dt, pre{ line-height: 1.5; }\
|
||||
\
|
||||
table {\
|
||||
border-collapse: collapse;\
|
||||
margin-bottom: 20px;\
|
||||
margin-left:20px;\
|
||||
}\
|
||||
\
|
||||
th {\
|
||||
padding: 0 0.5em;\
|
||||
text-align: center;\
|
||||
}\
|
||||
\
|
||||
th {\
|
||||
border: 1px solid #FB7A31;\
|
||||
background: #FFC;\
|
||||
}\
|
||||
\
|
||||
td {\
|
||||
border-bottom: 1px solid #CCC;\
|
||||
border-right: 1px solid #CCC;\
|
||||
border-left: 1px solid #CCC;\
|
||||
padding: 0 0.5em;\
|
||||
}\
|
||||
\
|
||||
\
|
||||
a:link,\
|
||||
a:visited{ color: #1A5B8D; }\
|
||||
\
|
||||
a:hover,\
|
||||
a:active{ color: #742CAC; }\
|
||||
\
|
||||
a.headerlink{ visibility: hidden; }\
|
||||
\
|
||||
:hover > a.headerlink { visibility: visible; }\
|
||||
\
|
||||
a img{ \
|
||||
border: 0;\
|
||||
outline: 0;\
|
||||
}\
|
||||
\
|
||||
img{ display: block; max-width: 100%; }\
|
||||
\
|
||||
code {\
|
||||
border: 1px solid #FB7A31;\
|
||||
background: #FFC;\
|
||||
}\
|
||||
\
|
||||
pre {\
|
||||
white-space: pre-wrap;\
|
||||
white-space: -moz-pre-wrap;\
|
||||
white-space: -o-pre-wrap;\
|
||||
border: 1px solid #FB7A31;\
|
||||
background: #FFC;\
|
||||
padding:5px;\
|
||||
padding-left: 15px;\
|
||||
}\
|
||||
\
|
||||
</style>\
|
||||
</head><body><h1>Spectrum 2 web interface</h1>";
|
||||
}
|
||||
|
||||
|
||||
static void get_qsvar(const struct mg_request_info *request_info,
|
||||
const char *name, char *dst, size_t dst_len) {
|
||||
const char *qs = request_info->query_string;
|
||||
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
|
||||
}
|
||||
|
||||
static void my_strlcpy(char *dst, const char *src, size_t len) {
|
||||
strncpy(dst, src, len);
|
||||
dst[len - 1] = '\0';
|
||||
}
|
||||
|
||||
// Generate session ID. buf must be 33 bytes in size.
|
||||
// Note that it is easy to steal session cookies by sniffing traffic.
|
||||
// This is why all communication must be SSL-ed.
|
||||
static void generate_session_id(char *buf, const char *random,
|
||||
const char *user) {
|
||||
mg_md5(buf, random, user, NULL);
|
||||
}
|
||||
|
||||
Server::Server(ManagerConfig *config) {
|
||||
srand((unsigned) time(0));
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
Server::~Server() {
|
||||
mg_stop(ctx);
|
||||
}
|
||||
|
||||
|
||||
static void *_event_handler(enum mg_event event, struct mg_connection *conn) {
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
return static_cast<Server *>(request_info->user_data)->event_handler(event, conn);
|
||||
}
|
||||
|
||||
bool Server::start(int port, const std::string &user, const std::string &password) {
|
||||
m_user = user;
|
||||
m_password = password;
|
||||
const char *options[] = {
|
||||
"listening_ports", boost::lexical_cast<std::string>(port).c_str(),
|
||||
"num_threads", "1",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Setup and start Mongoose
|
||||
if ((ctx = mg_start(&_event_handler, this, options)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Server::check_password(const char *user, const char *password) {
|
||||
return (m_user == user && m_password == password);
|
||||
}
|
||||
|
||||
// Allocate new session object
|
||||
Server::session *Server::new_session(const char *user) {
|
||||
Server::session *session = new Server::session;
|
||||
|
||||
my_strlcpy(session->user, user, sizeof(session->user));
|
||||
snprintf(session->random, sizeof(session->random), "%d", rand());
|
||||
generate_session_id(session->session_id, session->random, session->user);
|
||||
session->expire = time(0) + SESSION_TTL;
|
||||
|
||||
sessions[session->session_id] = session;
|
||||
return session;
|
||||
}
|
||||
|
||||
// Get session object for the connection. Caller must hold the lock.
|
||||
Server::session *Server::get_session(const struct mg_connection *conn) {
|
||||
time_t now = time(NULL);
|
||||
char session_id[33];
|
||||
mg_get_cookie(conn, "session", session_id, sizeof(session_id));
|
||||
|
||||
if (sessions.find(session_id) == sessions.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sessions[session_id]->expire != 0 && sessions[session_id]->expire > now) {
|
||||
return sessions[session_id];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Server::authorize(struct mg_connection *conn, const struct mg_request_info *request_info) {
|
||||
char user[255], password[255];
|
||||
Server::session *session;
|
||||
|
||||
// Fetch user name and password.
|
||||
get_qsvar(request_info, "user", user, sizeof(user));
|
||||
get_qsvar(request_info, "password", password, sizeof(password));
|
||||
|
||||
if (check_password(user, password) && (session = new_session(user)) != NULL) {
|
||||
std::cout << "User authorized\n";
|
||||
// Authentication success:
|
||||
// 1. create new session
|
||||
// 2. set session ID token in the cookie
|
||||
// 3. remove original_url from the cookie - not needed anymore
|
||||
// 4. redirect client back to the original URL
|
||||
//
|
||||
// The most secure way is to stay HTTPS all the time. However, just to
|
||||
// show the technique, we redirect to HTTP after the successful
|
||||
// authentication. The danger of doing this is that session cookie can
|
||||
// be stolen and an attacker may impersonate the user.
|
||||
// Secure application must use HTTPS all the time.
|
||||
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
|
||||
"Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
|
||||
"Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
|
||||
"Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
|
||||
"Location: /\r\n\r\n",
|
||||
session->session_id, session->user);
|
||||
} else {
|
||||
// Authentication failure, redirect to login.
|
||||
redirect_to(conn, request_info, "/login");
|
||||
}
|
||||
}
|
||||
|
||||
bool Server::is_authorized(const struct mg_connection *conn, const struct mg_request_info *request_info) {
|
||||
Server::session *session;
|
||||
char valid_id[33];
|
||||
bool authorized = false;
|
||||
|
||||
// Always authorize accesses to login page and to authorize URI
|
||||
if (!strcmp(request_info->uri, "/login") ||
|
||||
!strcmp(request_info->uri, "/authorize")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// pthread_rwlock_rdlock(&rwlock);
|
||||
if ((session = get_session(conn)) != NULL) {
|
||||
generate_session_id(valid_id, session->random, session->user);
|
||||
if (strcmp(valid_id, session->session_id) == 0) {
|
||||
session->expire = time(0) + SESSION_TTL;
|
||||
authorized = true;
|
||||
}
|
||||
}
|
||||
// pthread_rwlock_unlock(&rwlock);
|
||||
|
||||
return authorized;
|
||||
}
|
||||
|
||||
void Server::redirect_to(struct mg_connection *conn, const struct mg_request_info *request_info, const char *where) {
|
||||
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
|
||||
"Set-Cookie: original_url=%s\r\n"
|
||||
"Location: %s\r\n\r\n",
|
||||
request_info->uri, where);
|
||||
}
|
||||
|
||||
void Server::print_html(struct mg_connection *conn, const struct mg_request_info *request_info, const std::string &html) {
|
||||
mg_printf(conn,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: %d\r\n" // Always set Content-Length
|
||||
"\r\n"
|
||||
"%s",
|
||||
(int) html.size(), html.c_str());
|
||||
}
|
||||
|
||||
void Server::serve_login(struct mg_connection *conn, const struct mg_request_info *request_info) {
|
||||
std::string html= "\
|
||||
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\
|
||||
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> \
|
||||
<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" dir=\"ltr\"> \
|
||||
<head>\
|
||||
<title>Spectrum 2 web interface</title>\
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\
|
||||
</head>\
|
||||
<body>\
|
||||
<center>\
|
||||
<h2>Spectrum 2 web interface login</h2>\
|
||||
<br/>\
|
||||
<form action=\"/authorize\">\
|
||||
Username: <input type=\"text\" name=\"user\"></input><br/>\
|
||||
Password: <input type=\"text\" name=\"password\"></input><br/>\
|
||||
<input type=\"submit\" value=\"Login\"></input>\
|
||||
</form>\
|
||||
</center>\
|
||||
</body>\
|
||||
</html>";
|
||||
|
||||
print_html(conn, request_info, html);
|
||||
}
|
||||
|
||||
void Server::serve_root(struct mg_connection *conn, const struct mg_request_info *request_info) {
|
||||
std::vector<std::string> list = show_list(m_config, false);
|
||||
std::string html= get_header() + "<h2>List of instances</h2><table><tr><th>JID<th>Status</th><th>Command</th></tr>";
|
||||
|
||||
BOOST_FOREACH(std::string &instance, list) {
|
||||
html += "<tr>";
|
||||
html += "<td>" + instance + "</td>";
|
||||
Swift::SimpleEventLoop eventLoop;
|
||||
Swift::BoostNetworkFactories networkFactories(&eventLoop);
|
||||
|
||||
ask_local_server(m_config, networkFactories, instance, "status");
|
||||
eventLoop.runUntilEvents();
|
||||
while(get_response().empty()) {
|
||||
eventLoop.runUntilEvents();
|
||||
}
|
||||
html += "<td>" + get_response() + "</td>";
|
||||
if (get_response().find("Running") == 0) {
|
||||
html += "<td><a href=\"/stop?jid=" + instance + "\">Stop</a></td>";
|
||||
}
|
||||
else {
|
||||
html += "<td><a href=\"/start?jid=" + instance + "\">Start</a></td>";
|
||||
}
|
||||
html += "</tr>";
|
||||
}
|
||||
|
||||
html += "</table></body></html>";
|
||||
print_html(conn, request_info, html);
|
||||
}
|
||||
|
||||
void *Server::event_handler(enum mg_event event, struct mg_connection *conn) {
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
void *processed = (void *) 0x1;
|
||||
|
||||
if (event == MG_NEW_REQUEST) {
|
||||
if (!is_authorized(conn, request_info)) {
|
||||
redirect_to(conn, request_info, "/login");
|
||||
} else if (strcmp(request_info->uri, "/authorize") == 0) {
|
||||
authorize(conn, request_info);
|
||||
} else if (strcmp(request_info->uri, "/login") == 0) {
|
||||
serve_login(conn, request_info);
|
||||
} else if (strcmp(request_info->uri, "/") == 0) {
|
||||
serve_root(conn, request_info);
|
||||
} else {
|
||||
// No suitable handler found, mark as not processed. Mongoose will
|
||||
// try to serve the request.
|
||||
processed = NULL;
|
||||
}
|
||||
} else {
|
||||
processed = NULL;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
75
spectrum_manager/src/server.h
Normal file
75
spectrum_manager/src/server.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "managerconfig.h"
|
||||
|
||||
class Server {
|
||||
public:
|
||||
struct session {
|
||||
char session_id[33]; // Session ID, must be unique
|
||||
char random[20]; // Random data used for extra user validation
|
||||
char user[255]; // Authenticated user
|
||||
time_t expire; // Expiration timestamp, UTC
|
||||
};
|
||||
|
||||
/// Constructor.
|
||||
Server(ManagerConfig *config);
|
||||
|
||||
/// Destructor
|
||||
virtual ~Server();
|
||||
|
||||
bool start(int port, const std::string &user, const std::string &password);
|
||||
|
||||
void *event_handler(enum mg_event event, struct mg_connection *conn);
|
||||
|
||||
private:
|
||||
void serve_login(struct mg_connection *conn, const struct mg_request_info *request_info);
|
||||
void serve_root(struct mg_connection *conn, const struct mg_request_info *request_info);
|
||||
void print_html(struct mg_connection *conn, const struct mg_request_info *request_info, const std::string &html);
|
||||
|
||||
private:
|
||||
bool check_password(const char *user, const char *password);
|
||||
session *new_session(const char *user);
|
||||
session *get_session(const struct mg_connection *conn);
|
||||
|
||||
void authorize(struct mg_connection *conn, const struct mg_request_info *request_info);
|
||||
|
||||
bool is_authorized(const struct mg_connection *conn, const struct mg_request_info *request_info);
|
||||
|
||||
void redirect_to(struct mg_connection *conn, const struct mg_request_info *request_info, const char *where);
|
||||
|
||||
private:
|
||||
struct mg_context *ctx;
|
||||
std::map<std::string, session *> sessions;
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
ManagerConfig *m_config;
|
||||
};
|
Loading…
Add table
Reference in a new issue