From 09b6b338e006bf3e92b289d5987bc52ad3a56d98 Mon Sep 17 00:00:00 2001 From: Marco De Marco <demarco@oats.inaf.it> Date: Fri, 29 Nov 2013 15:54:24 +0100 Subject: [PATCH] Servers, sessions, worker thread, and db manager classes added --- src/Configuration.h | 177 ++++++++++ src/DBManager.cpp | 80 +++++ src/DBManager.h | 80 +++++ src/DataExporter.cpp | 562 +++++++++++++++++++++++++++++-- src/DataExporter.h | 107 +++++- src/DataExporter.xmi | 116 ++++++- src/DataExporterClass.cpp | 437 ++++++++++++++++++++++++ src/DataExporterClass.h | 66 ++++ src/DataExporterStateMachine.cpp | 33 ++ src/PlainServer.cpp | 52 +++ src/PlainServer.h | 42 +++ src/PlainSession.cpp | 161 +++++++++ src/PlainSession.h | 67 ++++ src/SSLServer.cpp | 87 +++++ src/SSLServer.h | 56 +++ src/SSLSession.cpp | 196 +++++++++++ src/SSLSession.h | 77 +++++ src/Server.cpp | 197 +++++++++++ src/Server.h | 103 ++++++ src/Session.cpp | 135 ++++++++ src/Session.h | 97 ++++++ src/WorkerThread.cpp | 59 ++++ src/WorkerThread.h | 37 ++ 23 files changed, 2987 insertions(+), 37 deletions(-) create mode 100644 src/Configuration.h create mode 100644 src/DBManager.cpp create mode 100644 src/DBManager.h create mode 100644 src/PlainServer.cpp create mode 100644 src/PlainServer.h create mode 100644 src/PlainSession.cpp create mode 100644 src/PlainSession.h create mode 100644 src/SSLServer.cpp create mode 100644 src/SSLServer.h create mode 100644 src/SSLSession.cpp create mode 100644 src/SSLSession.h create mode 100644 src/Server.cpp create mode 100644 src/Server.h create mode 100644 src/Session.cpp create mode 100644 src/Session.h create mode 100644 src/WorkerThread.cpp create mode 100644 src/WorkerThread.h diff --git a/src/Configuration.h b/src/Configuration.h new file mode 100644 index 0000000..e25c887 --- /dev/null +++ b/src/Configuration.h @@ -0,0 +1,177 @@ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include <map> +#include <string> +#include <vector> + +#include <boost/shared_ptr.hpp> + +namespace DataExporter_ns +{ + +class Configuration +{ +public: +//------------------------------------------------------------------------------ +// [Public] Shared pointer typedef +//------------------------------------------------------------------------------ + typedef boost::shared_ptr<Configuration> SP; + +//------------------------------------------------------------------------------ +// [Public] Map typedef +//------------------------------------------------------------------------------ + typedef const std::multimap<const std::string, const std::string> ExportedTablesMap; + typedef const std::map<const std::string, const std::string> AuthorisedUsersMap; + +protected: +//------------------------------------------------------------------------------ +// [Private] Constructor destructor deleter +//------------------------------------------------------------------------------ + Configuration(std::string certificateFile, std::string privateKeyFile, + std::string dHTempFile, ExportedTablesMap exportedTablesMap, + AuthorisedUsersMap authorisedUsersMap, std::string storagePath, + std::string localHost, unsigned int localPort, unsigned int workerNumber, + std::string databaseHost, unsigned int databasePort, + std::string databaseUsername, std::string databasePassword, + unsigned int databaseConnectionNumber) : + m_certificateFile(certificateFile), m_privateKeyFile(privateKeyFile), + m_dHTempFile(dHTempFile), m_exportedTablesMap(exportedTablesMap), + m_authorisedUsersMap(authorisedUsersMap), m_storagePath(storagePath), + m_localHost(localHost), m_localPort(localPort), m_workerNumber(workerNumber), + m_databaseHost(databaseHost), m_databasePort(databasePort), + m_databaseUsername(databaseUsername), m_databasePassword(databasePassword), + m_databaseConnectionNumber(databaseConnectionNumber) {} + + virtual ~Configuration() {} + + class Deleter; + friend class Deleter; + class Deleter + { + public: + void operator()(Configuration* c) { delete c; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Create class method +//------------------------------------------------------------------------------ + static Configuration::SP create(std::string certificateFile, + std::string privateKeyFile, std::string dHTempFile, + ExportedTablesMap exportedTablesMap, AuthorisedUsersMap authorisedUsersMap, + std::string storagePath, std::string localHost, + unsigned int localPort, unsigned int workerNumber, + std::string databaseHost, unsigned int databasePort, + std::string databaseUsername, std::string databasePassword, + unsigned int databaseConnectionNumber) + { + Configuration::SP c_sp(new Configuration(certificateFile, privateKeyFile, + dHTempFile, exportedTablesMap, authorisedUsersMap, storagePath, + localHost, localPort, workerNumber, databaseHost, databasePort, + databaseUsername, databasePassword, databaseConnectionNumber), + Configuration::Deleter()); + + return c_sp; + } + +//------------------------------------------------------------------------------ +// [Public] Getter methods +//------------------------------------------------------------------------------ + std::string getCertificateFile() const { return m_certificateFile; } + std::string getPrivateKeyFile() const { return m_privateKeyFile; } + std::string getDHTempFile() const { return m_dHTempFile; } + ExportedTablesMap& getExportedTablesMap() const { return m_exportedTablesMap; } + AuthorisedUsersMap& getAuthorisedUsersMap() const { return m_authorisedUsersMap; } + std::string getStoragePath() const { return m_storagePath; } + std::string getLocalHost() const { return m_localHost; } + unsigned int getLocalPort() const { return m_localPort; } + unsigned int getWorkerNumber() const { return m_workerNumber; } + std::string getDatabaseHost() const { return m_databaseHost; } + unsigned int getDatabasePort() const { return m_databasePort; } + std::string getDatabaseUsername() const { return m_databaseUsername; } + std::string getDatabasePassword() const { return m_databasePassword; } + unsigned int getDatabaseConnectionNumber() const { return m_databaseConnectionNumber; } + +//------------------------------------------------------------------------------ +// [Public] Utilities methods +//------------------------------------------------------------------------------ + bool isTableExported(const std::string schema, const std::string table) + { + std::pair<ExportedTablesMap::const_iterator, ExportedTablesMap::const_iterator > ret; + + ret = m_exportedTablesMap.equal_range(schema); + + ExportedTablesMap::const_iterator it; + + for(it=ret.first; it!=ret.second; ++it) + { + if(it->second.compare(table) == 0) + return true; + } + + return false; + } + + bool isUserAuthorized(const std::string username, const std::string password) + { + AuthorisedUsersMap::const_iterator it = m_authorisedUsersMap.find(username); + + if(it!=m_authorisedUsersMap.end() && + it->second.compare(password)==0) + return true; + + return false; + } + +protected: +//------------------------------------------------------------------------------ +// [Private] class variables +//------------------------------------------------------------------------------ + //Absolute path to certificate chain file + const std::string m_certificateFile; + + //Absolute path to private key file + const std::string m_privateKeyFile; + + //Absolute path to Diffie Hellman temporary file + const std::string m_dHTempFile; + + //Exported tables multi map [schema table] + ExportedTablesMap m_exportedTablesMap; + + //Authorised users map [user password] + AuthorisedUsersMap m_authorisedUsersMap; + + //Absolute path to storage + const std::string m_storagePath; + + //Local host address for incoming connection + const std::string m_localHost; + + //Local port for wait incoming connection + const unsigned int m_localPort; + + //Number of threads that call io service run methods + const unsigned int m_workerNumber; + + //Metadata database host + const std::string m_databaseHost; + + //Metadata database port + const unsigned int m_databasePort; + + //Metadata database login username + const std::string m_databaseUsername; + + //Metadata database login password + const std::string m_databasePassword; + + //Metadata database connections number + const unsigned int m_databaseConnectionNumber; +}; + +} //End of namespace + +#endif /* CONFIGURATION_H */ + diff --git a/src/DBManager.cpp b/src/DBManager.cpp new file mode 100644 index 0000000..e59e6f8 --- /dev/null +++ b/src/DBManager.cpp @@ -0,0 +1,80 @@ +#include <DBManager.h> + +#include <boost/date_time.hpp> + +#include <soci/mysql/soci-mysql.h> +#include <soci/use.h> + +namespace DataExporter_ns +{ + +//============================================================================== +// DBManager::DBManager() +//============================================================================== +DBManager::DBManager(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) : Tango::LogAdapter(deviceImpl_p), + m_configuration_sp(configuration_sp) +{ + DEBUG_STREAM << "DBManager::DBManager()" << endl; +} + +//============================================================================== +// DBManager::DBManager() +//============================================================================== +DBManager::~DBManager() +{ + DEBUG_STREAM << "DBManager::~DBManager()" << endl; +} + +//============================================================================== +// DBManager::DBManager() +//============================================================================== +DBManager::SP DBManager::create(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) +{ + DBManager::SP d_sp(new DBManager(deviceImpl_p, configuration_sp), + DBManager::Deleter()); + + return d_sp; +} + +//============================================================================== +// DBManager::connect() +//============================================================================== +void DBManager::connect() throw(soci::soci_error) +{ + DEBUG_STREAM << "DBManager::connect()" << endl; + + boost::mutex::scoped_lock lock(m_connectionPoolMutex); + + unsigned int connectionNumber = m_configuration_sp->getDatabaseConnectionNumber(); + + m_connectionPool_sp.reset(new soci::connection_pool(connectionNumber)); + + std::stringstream connection; + connection << " host=" << m_configuration_sp->getDatabaseHost(); + connection << " port=" << m_configuration_sp->getDatabasePort(); + connection << " user=" << m_configuration_sp->getDatabaseUsername(); + connection << " password=" << m_configuration_sp->getDatabasePassword(); + + #ifdef VERBOSE_DEBUG + INFO_STREAM << "DBManager::connect(): " << connection.str() << endl; + #endif + + for(unsigned int i=0; i<connectionNumber; ++i) + m_connectionPool_sp->at(i).open(soci::mysql, connection.str()); +} + +//============================================================================== +// DBManager::disconnect() +//============================================================================== +void DBManager::disconnect() +{ + DEBUG_STREAM << "DBManager::disconnect()" << endl; + + boost::mutex::scoped_lock lock(m_connectionPoolMutex); + + m_connectionPool_sp.reset(); +} + +} //namespace diff --git a/src/DBManager.h b/src/DBManager.h new file mode 100644 index 0000000..30c9659 --- /dev/null +++ b/src/DBManager.h @@ -0,0 +1,80 @@ +#ifndef DBMANAGER_H +#define DBMANAGER_H + +#include <Configuration.h> + +#include <tango.h> + +#include <ctime> + +#include <boost/tuple/tuple.hpp> +#include <boost/optional/optional.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/thread/mutex.hpp> + +#include <soci/soci.h> +#include <soci/error.h> +#include <soci/row.h> +#include <soci/rowset.h> +#include <soci/boost-tuple.h> +#include <soci/boost-optional.h> +#include <soci/session.h> +#include <soci/connection-pool.h> + +namespace DataExporter_ns +{ + +class DBManager : public Tango::LogAdapter +{ +public: +//------------------------------------------------------------------------------ +// [Public] Shared pointer typedef +//------------------------------------------------------------------------------ + typedef boost::shared_ptr<DBManager> SP; + +protected: +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + DBManager(Tango::DeviceImpl*, Configuration::SP); + + virtual ~DBManager(); + + class Deleter; + friend Deleter; + class Deleter + { + public: + void operator()(DBManager* d) { delete d; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Class creation method +//------------------------------------------------------------------------------ + static DBManager::SP create(Tango::DeviceImpl*, Configuration::SP); + +//------------------------------------------------------------------------------ +// [Public] Connection management methods +//------------------------------------------------------------------------------ + virtual void connect() throw(soci::soci_error); + + virtual void disconnect(); + +protected: +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //Configuration shared pointer + Configuration::SP m_configuration_sp; + + //Connection pool mutex + boost::mutex m_connectionPoolMutex; + + //Database connection pool scoped pointer + boost::scoped_ptr<soci::connection_pool> m_connectionPool_sp; +}; + +} //End of namespace + +#endif /* DBMANAGER_H */ diff --git a/src/DataExporter.cpp b/src/DataExporter.cpp index 12c9b88..594ac45 100644 --- a/src/DataExporter.cpp +++ b/src/DataExporter.cpp @@ -13,20 +13,20 @@ static const char *RcsId = "$Id: $"; // project : Data exporter // // This file is part of Tango device class. -// +// // Tango 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 3 of the License, or // (at your option) any later version. -// +// // Tango 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 Tango. If not, see <http://www.gnu.org/licenses/>. -// +// // $Author: $ // // $Revision: $ @@ -42,12 +42,16 @@ static const char *RcsId = "$Id: $"; #include <DataExporter.h> #include <DataExporterClass.h> +#include <PlainServer.h> +#include <SSLServer.h> + +#include <boost/filesystem.hpp> /*----- PROTECTED REGION END -----*/ // DataExporter.cpp /** * DataExporter class description: - * + * */ //================================================================ @@ -58,6 +62,8 @@ static const char *RcsId = "$Id: $"; //================================================================ // State | Inherited (no method) // Status | Inherited (no method) +// On | on +// Off | off //================================================================ //================================================================ @@ -85,7 +91,7 @@ DataExporter::DataExporter(Tango::DeviceClass *cl, string &s) { /*----- PROTECTED REGION ID(DataExporter::constructor_1) ENABLED START -----*/ init_device(); - + /*----- PROTECTED REGION END -----*/ // DataExporter::constructor_1 } //-------------------------------------------------------- @@ -94,7 +100,7 @@ DataExporter::DataExporter(Tango::DeviceClass *cl, const char *s) { /*----- PROTECTED REGION ID(DataExporter::constructor_2) ENABLED START -----*/ init_device(); - + /*----- PROTECTED REGION END -----*/ // DataExporter::constructor_2 } //-------------------------------------------------------- @@ -103,7 +109,7 @@ DataExporter::DataExporter(Tango::DeviceClass *cl, const char *s, const char *d) { /*----- PROTECTED REGION ID(DataExporter::constructor_3) ENABLED START -----*/ init_device(); - + /*----- PROTECTED REGION END -----*/ // DataExporter::constructor_3 } @@ -117,9 +123,9 @@ void DataExporter::delete_device() { DEBUG_STREAM << "DataExporter::delete_device() " << device_name << endl; /*----- PROTECTED REGION ID(DataExporter::delete_device) ENABLED START -----*/ - + // Delete device allocated objects - + /*----- PROTECTED REGION END -----*/ // DataExporter::delete_device } @@ -133,21 +139,339 @@ void DataExporter::init_device() { DEBUG_STREAM << "DataExporter::init_device() create device " << device_name << endl; /*----- PROTECTED REGION ID(DataExporter::init_device_before) ENABLED START -----*/ - - // Initialization before get_device_property() call - + + set_state(Tango::INIT); + set_status("Initializing device"); + /*----- PROTECTED REGION END -----*/ // DataExporter::init_device_before - - // No device property to be read from database - + + + // Get the device properties from database + get_device_property(); + /*----- PROTECTED REGION ID(DataExporter::init_device) ENABLED START -----*/ - - // Initialize device - + + if(get_state() != Tango::FAULT) + { + try + { + if(enableSSL) + m_server_sp = SSLServer::create(this, m_configuration_sp); + else + m_server_sp = PlainServer::create(this, m_configuration_sp); + } + catch(std::exception& ex) + { + set_state(Tango::FAULT); + std::stringstream error_stream; + error_stream << "DataExporter::init_device() " << ex.what() << std::endl; + set_status(error_stream.str()); + } + catch(...) + { + set_state(Tango::FAULT); + set_status("DataExporter::init_device() unknown error"); + } + } + /*----- PROTECTED REGION END -----*/ // DataExporter::init_device } +//-------------------------------------------------------- +/** + * Method : DataExporter::get_device_property() + * Description : Read database to initialize property data members. + */ +//-------------------------------------------------------- +void DataExporter::get_device_property() +{ + /*----- PROTECTED REGION ID(DataExporter::get_device_property_before) ENABLED START -----*/ + + //Exported tables multi map [schema table] + std::multimap<const std::string, const std::string> exportedTablesMap; + + //Authorised user map [user password] + std::map<const std::string, const std::string> authorisedUsersMap; + + /*----- PROTECTED REGION END -----*/ // DataExporter::get_device_property_before + + + // Read device properties from database. + Tango::DbData dev_prop; + dev_prop.push_back(Tango::DbDatum("CertificateFile")); + dev_prop.push_back(Tango::DbDatum("PrivateKeyFile")); + dev_prop.push_back(Tango::DbDatum("DHTempFile")); + dev_prop.push_back(Tango::DbDatum("ExportedTables")); + dev_prop.push_back(Tango::DbDatum("AuthorisedUsers")); + dev_prop.push_back(Tango::DbDatum("StoragePath")); + dev_prop.push_back(Tango::DbDatum("LocalHost")); + dev_prop.push_back(Tango::DbDatum("LocalPort")); + dev_prop.push_back(Tango::DbDatum("WorkerNumber")); + dev_prop.push_back(Tango::DbDatum("EnableSSL")); + dev_prop.push_back(Tango::DbDatum("DatabaseHost")); + dev_prop.push_back(Tango::DbDatum("DatabasePort")); + dev_prop.push_back(Tango::DbDatum("DatabaseUsername")); + dev_prop.push_back(Tango::DbDatum("DatabasePassword")); + dev_prop.push_back(Tango::DbDatum("DatabaseConnectionNumber")); + + // is there at least one property to be read ? + if (dev_prop.size()>0) + { + // Call database and extract values + if (Tango::Util::instance()->_UseDb==true) + get_db_device()->get_property(dev_prop); + + // get instance on DataExporterClass to get class property + Tango::DbDatum def_prop, cl_prop; + DataExporterClass *ds_class = + (static_cast<DataExporterClass *>(get_device_class())); + int i = -1; + + // Try to initialize CertificateFile from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> certificateFile; + else { + // Try to initialize CertificateFile from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> certificateFile; + } + // And try to extract CertificateFile value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> certificateFile; + + // Try to initialize PrivateKeyFile from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> privateKeyFile; + else { + // Try to initialize PrivateKeyFile from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> privateKeyFile; + } + // And try to extract PrivateKeyFile value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> privateKeyFile; + + // Try to initialize DHTempFile from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> dHTempFile; + else { + // Try to initialize DHTempFile from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> dHTempFile; + } + // And try to extract DHTempFile value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> dHTempFile; + + // Try to initialize ExportedTables from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> exportedTables; + else { + // Try to initialize ExportedTables from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> exportedTables; + } + // And try to extract ExportedTables value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> exportedTables; + + // Try to initialize AuthorisedUsers from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> authorisedUsers; + else { + // Try to initialize AuthorisedUsers from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> authorisedUsers; + } + // And try to extract AuthorisedUsers value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> authorisedUsers; + + // Try to initialize StoragePath from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> storagePath; + else { + // Try to initialize StoragePath from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> storagePath; + } + // And try to extract StoragePath value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> storagePath; + + // Try to initialize LocalHost from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> localHost; + else { + // Try to initialize LocalHost from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> localHost; + } + // And try to extract LocalHost value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> localHost; + + // Try to initialize LocalPort from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> localPort; + else { + // Try to initialize LocalPort from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> localPort; + } + // And try to extract LocalPort value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> localPort; + + // Try to initialize WorkerNumber from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> workerNumber; + else { + // Try to initialize WorkerNumber from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> workerNumber; + } + // And try to extract WorkerNumber value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> workerNumber; + + // Try to initialize EnableSSL from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> enableSSL; + else { + // Try to initialize EnableSSL from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> enableSSL; + } + // And try to extract EnableSSL value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> enableSSL; + + // Try to initialize DatabaseHost from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> databaseHost; + else { + // Try to initialize DatabaseHost from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> databaseHost; + } + // And try to extract DatabaseHost value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> databaseHost; + + // Try to initialize DatabasePort from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> databasePort; + else { + // Try to initialize DatabasePort from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> databasePort; + } + // And try to extract DatabasePort value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> databasePort; + + // Try to initialize DatabaseUsername from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> databaseUsername; + else { + // Try to initialize DatabaseUsername from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> databaseUsername; + } + // And try to extract DatabaseUsername value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> databaseUsername; + + // Try to initialize DatabasePassword from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> databasePassword; + else { + // Try to initialize DatabasePassword from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> databasePassword; + } + // And try to extract DatabasePassword value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> databasePassword; + + // Try to initialize DatabaseConnectionNumber from class property + cl_prop = ds_class->get_class_property(dev_prop[++i].name); + if (cl_prop.is_empty()==false) cl_prop >> databaseConnectionNumber; + else { + // Try to initialize DatabaseConnectionNumber from default device value + def_prop = ds_class->get_default_device_property(dev_prop[i].name); + if (def_prop.is_empty()==false) def_prop >> databaseConnectionNumber; + } + // And try to extract DatabaseConnectionNumber value from database + if (dev_prop[i].is_empty()==false) dev_prop[i] >> databaseConnectionNumber; + + } + + /*----- PROTECTED REGION ID(DataExporter::get_device_property_after) ENABLED START -----*/ + + try + { + if(enableSSL) + { + if(certificateFile.empty()) + throw(invalid_argument("CertificateFile property is empty or not defined")); + + checkIfFileExists(certificateFile); + + if(privateKeyFile.empty()) + throw(invalid_argument("PrivateKeyFile property is empty or not defined")); + + checkIfFileExists(privateKeyFile); + + if(dHTempFile.empty()) + throw(invalid_argument("DHTempFile property is empty or not defined")); + + checkIfFileExists(dHTempFile); + } + + if(exportedTables.empty()) + throw(invalid_argument("ExportedTables property is empty or not defined")); + + importExportedTables(exportedTables, exportedTablesMap); + + if(authorisedUsers.empty()) + throw(invalid_argument("AuthorisedUsers property is empty or not defined")); + + importAuthorisedUsers(authorisedUsers, authorisedUsersMap); + + if(storagePath.empty()) + throw(invalid_argument("StoragePath property is empty or not defined")); + + checkIfDirectoryExists(storagePath); + + if(localHost.empty()) + throw(invalid_argument("LocalHost property is empty or not defined")); + + if(localPort<1 || localPort>MAX_LOCAL_PORT) + throw(invalid_argument("LocalPort property out of range or not defined")); + + if(workerNumber<1 || workerNumber>MAX_WORKER_NUMBER) + throw(invalid_argument("WorkerNumber property out of range or not defined")); + + if(databaseHost.empty()) + throw(invalid_argument("DatabaseHost property is empty or not defined")); + + if(databasePort<1 || databasePort>MAX_DB_PORT) + throw(invalid_argument("DatabasePort property out of range or not defined")); + + if(databaseUsername.empty()) + throw(invalid_argument("DatabaseUsername property is empty or not defined")); + + if(databasePassword.empty()) + throw(invalid_argument("DatabasePassword property is empty or not defined")); + + if(databaseConnectionNumber<1 || databaseConnectionNumber>MAX_DB_CONNECTION_NUMBER) + throw(invalid_argument("DatabaseConnectionNumber property out of range or not defined")); + + m_configuration_sp = Configuration::create(certificateFile, + privateKeyFile, dHTempFile, exportedTablesMap, authorisedUsersMap, + storagePath, localHost, localPort, workerNumber, + databaseHost, databasePort, databaseUsername, databasePassword, + databaseConnectionNumber); + } + catch(invalid_argument& ex) + { + set_state(Tango::FAULT); + stringstream error_stream; + error_stream << "DataExporter::get_device_property() " << ex.what() << endl; + set_status(error_stream.str()); + } + + /*----- PROTECTED REGION END -----*/ // DataExporter::get_device_property_after +} //-------------------------------------------------------- /** @@ -157,11 +481,19 @@ void DataExporter::init_device() //-------------------------------------------------------- void DataExporter::always_executed_hook() { - INFO_STREAM << "DataExporter::always_executed_hook() " << device_name << endl; + DEBUG_STREAM << "DataExporter::always_executed_hook() " << device_name << endl; /*----- PROTECTED REGION ID(DataExporter::always_executed_hook) ENABLED START -----*/ - - // code always executed before all requests - + + if(get_state() != Tango::FAULT) + { + if(m_server_sp) + { + set_state(m_server_sp->readState()); + + set_status(m_server_sp->readStatus()); + } + } + /*----- PROTECTED REGION END -----*/ // DataExporter::always_executed_hook } @@ -175,9 +507,9 @@ void DataExporter::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list)) { DEBUG_STREAM << "DataExporter::read_attr_hardware(vector<long> &attr_list) entering... " << endl; /*----- PROTECTED REGION ID(DataExporter::read_attr_hardware) ENABLED START -----*/ - + // Add your own code - + /*----- PROTECTED REGION END -----*/ // DataExporter::read_attr_hardware } @@ -192,16 +524,190 @@ void DataExporter::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list)) void DataExporter::add_dynamic_attributes() { /*----- PROTECTED REGION ID(DataExporter::add_dynamic_attributes) ENABLED START -----*/ - + // Add your own code to create and add dynamic attributes if any - + /*----- PROTECTED REGION END -----*/ // DataExporter::add_dynamic_attributes } +//-------------------------------------------------------- +/** + * Command On related method + * Description: Activate data exporter + * + */ +//-------------------------------------------------------- +void DataExporter::on() +{ + DEBUG_STREAM << "DataExporter::On() - " << device_name << endl; + /*----- PROTECTED REGION ID(DataExporter::on) ENABLED START -----*/ + + try + { + if(m_server_sp) + m_server_sp->start(); + } + catch(std::exception& ex) + { + set_state(Tango::FAULT); + std::stringstream error_stream; + error_stream << "DataExporter::On() " << ex.what() << std::endl; + set_status(error_stream.str()); + } + catch(...) + { + set_state(Tango::FAULT); + set_status("DataExporter::On() unknown error"); + } + + /*----- PROTECTED REGION END -----*/ // DataExporter::on +} +//-------------------------------------------------------- +/** + * Command Off related method + * Description: Deactivate data exporter + * + */ +//-------------------------------------------------------- +void DataExporter::off() +{ + DEBUG_STREAM << "DataExporter::Off() - " << device_name << endl; + /*----- PROTECTED REGION ID(DataExporter::off) ENABLED START -----*/ + + try + { + if(m_server_sp) + m_server_sp->stop(); + } + catch(std::exception& ex) + { + set_state(Tango::FAULT); + std::stringstream error_stream; + error_stream << "DataExporter::Off() " << ex.what() << std::endl; + set_status(error_stream.str()); + } + catch(...) + { + set_state(Tango::FAULT); + set_status("DataExporter::Off() unknown error"); + } + + /*----- PROTECTED REGION END -----*/ // DataExporter::off +} /*----- PROTECTED REGION ID(DataExporter::namespace_ending) ENABLED START -----*/ -// Additional Methods +//============================================================================== +// DataExporter::importExportedTables() +//============================================================================== +void DataExporter::importExportedTables(std::vector<std::string>& exportedTables, + std::multimap<const std::string, const std::string>& exportedTablesMap) + throw(std::invalid_argument) +{ + DEBUG_STREAM << "DataExporter::importExportedTables() - " << device_name << endl; + + for(unsigned int i=0; i<exportedTables.size(); ++i) + { + std::size_t found; + + if((found=exportedTables.at(i).find(' ')) == std::string::npos) + { + std::stringstream errorStream; + errorStream << "ExportedTables property has invalid key at " + << i << " position" << std::endl; + throw std::invalid_argument(errorStream.str()); + } + + std::string schema = exportedTables.at(i).substr(0, found); + std::string table = exportedTables.at(i).substr(found+1, std::string::npos); + + INFO_STREAM << "DataExporter::importExportedTables() schema " + << schema << " table " << table << endl; + + exportedTablesMap.insert(std::pair<const std::string, const std::string> (schema, table)); + } +} + +//============================================================================== +// DataExporter::importAuthorisedUsers() +//============================================================================== +void DataExporter::importAuthorisedUsers(std::vector<std::string>& authorisedUsers, + std::map<const std::string, const std::string>& authorisedUsersMap) + throw(std::invalid_argument) +{ + DEBUG_STREAM << "DataExporter::importAuthorisedUsers() - " << device_name << endl; + + for(unsigned int i=0; i<authorisedUsers.size(); ++i) + { + std::size_t found; + + if((found=authorisedUsers.at(i).find(' ')) == std::string::npos) + { + std::stringstream errorStream; + errorStream << "AuthorisedUsers property has invalid key at " + << i << " position" << std::endl; + throw std::invalid_argument(errorStream.str()); + } + + std::string user = authorisedUsers.at(i).substr(0, found); + std::string password = authorisedUsers.at(i).substr(found+1, std::string::npos); + + #ifdef VERBOSE_DEBUG + INFO_STREAM << "DataExporter::importAuthorisedUsers() user " + << user << " password " << password << endl; + #endif + + authorisedUsersMap.insert(std::pair<const std::string, + const std::string>(user, password)); + } +} + +//============================================================================== +// DataExporter::checkIfFileExists() +//============================================================================== +void DataExporter::checkIfFileExists(std::string fileName) + throw(std::invalid_argument) +{ + DEBUG_STREAM << "DataExporter::checkIfFileExists() - " << device_name << endl; + + boost::filesystem::path path(fileName); + + if(!boost::filesystem::exists(path)) + { + std::stringstream errorStream; + errorStream << "File " << fileName << " not exists" << std::endl; + throw std::invalid_argument(errorStream.str()); + } + + INFO_STREAM << "DataExporter::checkIfFileExists() " << fileName << endl; +} + +//============================================================================== +// DataExporter::checkIfFileExists() +//============================================================================== +void DataExporter::checkIfDirectoryExists(std::string directoryName) + throw(std::invalid_argument) +{ + DEBUG_STREAM << "DataExporter::checkIfFileExists() - " << device_name << endl; + + boost::filesystem::path path(directoryName); + + if(!boost::filesystem::exists(path)) + { + std::stringstream errorStream; + errorStream << "Directory " << directoryName << " not exists" << std::endl; + throw std::invalid_argument(errorStream.str()); + } + + if(!boost::filesystem::is_directory(path)) + { + std::stringstream errorStream; + errorStream << directoryName << " is not a directory" << std::endl; + throw std::invalid_argument(errorStream.str()); + } + + INFO_STREAM << "DataExporter::checkIfDirectoryExists() " << directoryName << endl; +} /*----- PROTECTED REGION END -----*/ // DataExporter::namespace_ending } // namespace diff --git a/src/DataExporter.h b/src/DataExporter.h index 3bc9b4c..0aaf826 100644 --- a/src/DataExporter.h +++ b/src/DataExporter.h @@ -8,20 +8,20 @@ // project : Data exporter // // This file is part of Tango device class. -// +// // Tango 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 3 of the License, or // (at your option) any later version. -// +// // Tango 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 Tango. If not, see <http://www.gnu.org/licenses/>. -// +// // $Author: $ // // $Revision: $ @@ -38,6 +38,9 @@ #ifndef DataExporter_H #define DataExporter_H +#include <Configuration.h> +#include <Server.h> + #include <tango.h> @@ -45,7 +48,7 @@ /** * DataExporter class description: - * + * */ namespace DataExporter_ns @@ -61,10 +64,64 @@ class DataExporter : public TANGO_BASE_CLASS /*----- PROTECTED REGION ID(DataExporter::Data Members) ENABLED START -----*/ -// Add your own data members +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //Configuration class shared pointer + Configuration::SP m_configuration_sp; + + //Server base class shared pointer + Server::SP m_server_sp; + + //Max local port number allowed value + static const unsigned int MAX_LOCAL_PORT = 65535; + + //Max number of worker thread allowed + static const unsigned int MAX_WORKER_NUMBER = 100; + + //Max number of database connection allowed + static const unsigned int MAX_DB_CONNECTION_NUMBER = 100; + + //Max database port number allowed value + static const unsigned int MAX_DB_PORT = 65535; + /*----- PROTECTED REGION END -----*/ // DataExporter::Data Members +// Device property data members +public: + // CertificateFile: Absolute path to certificate chain file + string certificateFile; + // PrivateKeyFile: Absolute path to private key file + string privateKeyFile; + // DHTempFile: Absolute path to Diffie Hellman temporary file + string dHTempFile; + // ExportedTables: Tables exported from database: one table per row + // [schema table] + vector<string> exportedTables; + // AuthorisedUsers: Authorised user list: one user per row + // [username password] + vector<string> authorisedUsers; + // StoragePath: Absolute path to storage + string storagePath; + // LocalHost: Local host address for incoming connection + string localHost; + // LocalPort: Local port for wait incoming connection + Tango::DevULong localPort; + // WorkerNumber: Number of threads that call io service run methods + Tango::DevUShort workerNumber; + // EnableSSL: Enable or disable SSL connections + Tango::DevBoolean enableSSL; + // DatabaseHost: Metadata database host + string databaseHost; + // DatabasePort: Metadata database port + Tango::DevULong databasePort; + // DatabaseUsername: Metadata database login username + string databaseUsername; + // DatabasePassword: Metadata database login password + string databasePassword; + // DatabaseConnectionNumber: Number of database connection created + Tango::DevUShort databaseConnectionNumber; // Constructors and destructors @@ -93,7 +150,7 @@ public: DataExporter(Tango::DeviceClass *cl,const char *s,const char *d); /** * The device object destructor. - */ + */ ~DataExporter() {delete_device();}; @@ -107,6 +164,10 @@ public: * Initialize the device */ virtual void init_device(); + /* + * Read the device properties from database + */ + void get_device_property(); /* * Always executed method before execution command method. */ @@ -136,11 +197,41 @@ public: // Command related methods public: + /** + * Command On related method + * Description: Activate data exporter + * + */ + virtual void on(); + virtual bool is_On_allowed(const CORBA::Any &any); + /** + * Command Off related method + * Description: Deactivate data exporter + * + */ + virtual void off(); + virtual bool is_Off_allowed(const CORBA::Any &any); /*----- PROTECTED REGION ID(DataExporter::Additional Method prototypes) ENABLED START -----*/ -// Additional Method prototypes +//------------------------------------------------------------------------------ +// [Protected] Utilities methods +//------------------------------------------------------------------------------ + virtual void importExportedTables(std::vector<std::string>&, + std::multimap<const std::string, const std::string>&) + throw(std::invalid_argument); + + virtual void importAuthorisedUsers(std::vector<std::string>&, + std::map<const std::string, const std::string>&) + throw(std::invalid_argument); + + virtual void checkIfFileExists(std::string) + throw(std::invalid_argument); + + virtual void checkIfDirectoryExists(std::string) + throw(std::invalid_argument); + /*----- PROTECTED REGION END -----*/ // DataExporter::Additional Method prototypes }; diff --git a/src/DataExporter.xmi b/src/DataExporter.xmi index af83bb6..6d53e1a 100644 --- a/src/DataExporter.xmi +++ b/src/DataExporter.xmi @@ -1,10 +1,97 @@ <?xml version="1.0" encoding="ASCII"?> <pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl"> <classes name="DataExporter" pogoRevision="8.1"> - <description description="" title="Data exporter" sourcePath="/home/mdm/workspace/nadir/data_exporter/src" language="Cpp" filestogenerate="XMI file,Code files" license="GPL" hasMandatoryProperty="false" hasConcreteProperty="false" hasAbstractCommand="false" hasAbstractAttribute="false"> + <description description="" title="Data exporter" sourcePath="/home/mdm/workspace/nadir/data_exporter/src" language="Cpp" filestogenerate="XMI file,Code files" license="GPL" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false"> <inheritances classname="Device_Impl" sourcePath=""/> <identification contact="at oats.inaf.it - demarco" author="demarco" emailDomain="oats.inaf.it" classFamily="Communication" siteSpecific="" platform="Unix Like" bus="TCP/UDP" manufacturer="none" reference=""/> </description> + <classProperties name="CertificateFile" description="Absolute path to certificate chain file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <classProperties name="PrivateKeyFile" description="Absolute path to private key file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <classProperties name="DHTempFile" description="Absolute path to Diffie Hellman temporary file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <classProperties name="ExportedTables" description="Tables exported from database: one table per row
[schema table]"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <classProperties name="AuthorisedUsers" description="Authorised user list: one user per row
[username password]"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <classProperties name="StoragePath" description="Absolute path to storage"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </classProperties> + <deviceProperties name="CertificateFile" description="Absolute path to certificate chain file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="PrivateKeyFile" description="Absolute path to private key file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DHTempFile" description="Absolute path to Diffie Hellman temporary file"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="ExportedTables" description="Tables exported from database: one table per row
[schema table]"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="AuthorisedUsers" description="Authorised user list: one user per row
[username password]"> + <type xsi:type="pogoDsl:StringVectorType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="StoragePath" description="Absolute path to storage"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="LocalHost" description="Local host address for incoming connection"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="LocalPort" description="Local port for wait incoming connection"> + <type xsi:type="pogoDsl:UIntType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="WorkerNumber" description="Number of threads that call io service run methods"> + <type xsi:type="pogoDsl:UShortType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + <DefaultPropValue>8</DefaultPropValue> + </deviceProperties> + <deviceProperties name="EnableSSL" description="Enable or disable SSL connections"> + <type xsi:type="pogoDsl:BooleanType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + <DefaultPropValue>0</DefaultPropValue> + </deviceProperties> + <deviceProperties name="DatabaseHost" description="Metadata database host"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DatabasePort" description="Metadata database port"> + <type xsi:type="pogoDsl:UIntType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DatabaseUsername" description="Metadata database login username"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DatabasePassword" description="Metadata database login password"> + <type xsi:type="pogoDsl:StringType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </deviceProperties> + <deviceProperties name="DatabaseConnectionNumber" description="Number of database connection created"> + <type xsi:type="pogoDsl:UShortType"/> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + <DefaultPropValue>2</DefaultPropValue> + </deviceProperties> <commands name="State" description="This command gets the device state (stored in its device_state data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0"> <argin description="none"> <type xsi:type="pogoDsl:VoidType"/> @@ -23,6 +110,33 @@ </argout> <status abstract="true" inherited="true" concrete="true"/> </commands> + <commands name="On" description="Activate data exporter" execMethod="on" displayLevel="OPERATOR" polledPeriod="0"> + <argin description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <commands name="Off" description="Deactivate data exporter" execMethod="off" displayLevel="OPERATOR" polledPeriod="0"> + <argin description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argin> + <argout description=""> + <type xsi:type="pogoDsl:VoidType"/> + </argout> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </commands> + <states name="ON" description="Data exporter is in ON state (ready to incoming connections)"> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </states> + <states name="OFF" description="Data exporter is in OFF state (not ready for incoming connections)"> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </states> + <states name="FAULT" description="Data exporter is in FAULT state (an error occurred)"> + <status abstract="false" inherited="false" concrete="true" concreteHere="true"/> + </states> <preferences docHome="./doc_html" makefileHome="/usr/local/tango-8.1.2/share/pogo/preferences"/> </classes> </pogoDsl:PogoSystem> diff --git a/src/DataExporterClass.cpp b/src/DataExporterClass.cpp index ab3dbab..76a8754 100644 --- a/src/DataExporterClass.cpp +++ b/src/DataExporterClass.cpp @@ -85,6 +85,7 @@ DataExporterClass::DataExporterClass(string &s):Tango::DeviceClass(s) { cout2 << "Entering DataExporterClass constructor" << endl; set_default_property(); + get_class_property(); write_class_property(); /*----- PROTECTED REGION ID(DataExporterClass::constructor) ENABLED START -----*/ @@ -158,6 +159,42 @@ DataExporterClass *DataExporterClass::instance() //=================================================================== // Command execution method calls //=================================================================== +//-------------------------------------------------------- +/** + * method : OnClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *OnClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any)) +{ + cout2 << "OnClass::execute(): arrived" << endl; + ((static_cast<DataExporter *>(device))->on()); + return new CORBA::Any(); +} + +//-------------------------------------------------------- +/** + * method : OffClass::execute() + * description : method to trigger the execution of the command. + * + * @param device The device on which the command must be executed + * @param in_any The command input data + * + * returns The command output data (packed in the Any object) + */ +//-------------------------------------------------------- +CORBA::Any *OffClass::execute(Tango::DeviceImpl *device, TANGO_UNUSED(const CORBA::Any &in_any)) +{ + cout2 << "OffClass::execute(): arrived" << endl; + ((static_cast<DataExporter *>(device))->off()); + return new CORBA::Any(); +} + //=================================================================== // Properties management @@ -207,6 +244,112 @@ Tango::DbDatum DataExporterClass::get_default_class_property(string &prop_name) return Tango::DbDatum(prop_name); } +//-------------------------------------------------------- +/** + * Method : DataExporterClass::get_class_property() + * Description : Read database to initialize class property data members. + */ +//-------------------------------------------------------- +void DataExporterClass::get_class_property() +{ + /*----- PROTECTED REGION ID(DataExporterClass::get_class_property_before) ENABLED START -----*/ + + // Initialize class property data members + + /*----- PROTECTED REGION END -----*/ // DataExporterClass::get_class_property_before + // Read class properties from database. + cl_prop.push_back(Tango::DbDatum("CertificateFile")); + cl_prop.push_back(Tango::DbDatum("PrivateKeyFile")); + cl_prop.push_back(Tango::DbDatum("DHTempFile")); + cl_prop.push_back(Tango::DbDatum("ExportedTables")); + cl_prop.push_back(Tango::DbDatum("AuthorisedUsers")); + cl_prop.push_back(Tango::DbDatum("StoragePath")); + + // Call database and extract values + if (Tango::Util::instance()->_UseDb==true) + get_db_class()->get_property(cl_prop); + Tango::DbDatum def_prop; + int i = -1; + + // Try to extract CertificateFile value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> certificateFile; + else + { + // Check default value for CertificateFile + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> certificateFile; + cl_prop[i] << certificateFile; + } + } + // Try to extract PrivateKeyFile value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> privateKeyFile; + else + { + // Check default value for PrivateKeyFile + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> privateKeyFile; + cl_prop[i] << privateKeyFile; + } + } + // Try to extract DHTempFile value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> dHTempFile; + else + { + // Check default value for DHTempFile + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> dHTempFile; + cl_prop[i] << dHTempFile; + } + } + // Try to extract ExportedTables value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> exportedTables; + else + { + // Check default value for ExportedTables + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> exportedTables; + cl_prop[i] << exportedTables; + } + } + // Try to extract AuthorisedUsers value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> authorisedUsers; + else + { + // Check default value for AuthorisedUsers + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> authorisedUsers; + cl_prop[i] << authorisedUsers; + } + } + // Try to extract StoragePath value + if (cl_prop[++i].is_empty()==false) cl_prop[i] >> storagePath; + else + { + // Check default value for StoragePath + def_prop = get_default_class_property(cl_prop[i].name); + if (def_prop.is_empty()==false) + { + def_prop >> storagePath; + cl_prop[i] << storagePath; + } + } + /*----- PROTECTED REGION ID(DataExporterClass::get_class_property_after) ENABLED START -----*/ + + // Check class property data members init + + /*----- PROTECTED REGION END -----*/ // DataExporterClass::get_class_property_after + +} //-------------------------------------------------------- /** @@ -225,8 +368,284 @@ void DataExporterClass::set_default_property() vector<string> vect_data; // Set Default Class Properties + prop_name = "CertificateFile"; + prop_desc = "Absolute path to certificate chain file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); + prop_name = "PrivateKeyFile"; + prop_desc = "Absolute path to private key file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); + prop_name = "DHTempFile"; + prop_desc = "Absolute path to Diffie Hellman temporary file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); + prop_name = "ExportedTables"; + prop_desc = "Tables exported from database: one table per row\n[schema table]"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); + prop_name = "AuthorisedUsers"; + prop_desc = "Authorised user list: one user per row\n[username password]"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); + prop_name = "StoragePath"; + prop_desc = "Absolute path to storage"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + cl_def_prop.push_back(data); + add_wiz_class_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_class_prop(prop_name, prop_desc); // Set Default device Properties + prop_name = "CertificateFile"; + prop_desc = "Absolute path to certificate chain file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "PrivateKeyFile"; + prop_desc = "Absolute path to private key file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DHTempFile"; + prop_desc = "Absolute path to Diffie Hellman temporary file"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "ExportedTables"; + prop_desc = "Tables exported from database: one table per row\n[schema table]"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "AuthorisedUsers"; + prop_desc = "Authorised user list: one user per row\n[username password]"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "StoragePath"; + prop_desc = "Absolute path to storage"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "LocalHost"; + prop_desc = "Local host address for incoming connection"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "LocalPort"; + prop_desc = "Local port for wait incoming connection"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "WorkerNumber"; + prop_desc = "Number of threads that call io service run methods"; + prop_def = "8"; + vect_data.clear(); + vect_data.push_back("8"); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "EnableSSL"; + prop_desc = "Enable or disable SSL connections"; + prop_def = "0"; + vect_data.clear(); + vect_data.push_back("0"); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DatabaseHost"; + prop_desc = "Metadata database host"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DatabasePort"; + prop_desc = "Metadata database port"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DatabaseUsername"; + prop_desc = "Metadata database login username"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DatabasePassword"; + prop_desc = "Metadata database login password"; + prop_def = ""; + vect_data.clear(); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + prop_name = "DatabaseConnectionNumber"; + prop_desc = "Number of database connection created"; + prop_def = "2"; + vect_data.clear(); + vect_data.push_back("2"); + if (prop_def.length()>0) + { + Tango::DbDatum data(prop_name); + data << vect_data ; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); } //-------------------------------------------------------- @@ -455,6 +874,24 @@ void DataExporterClass::command_factory() /*----- PROTECTED REGION END -----*/ // DataExporterClass::command_factory_before + // Command On + OnClass *pOnCmd = + new OnClass("On", + Tango::DEV_VOID, Tango::DEV_VOID, + "", + "", + Tango::OPERATOR); + command_list.push_back(pOnCmd); + + // Command Off + OffClass *pOffCmd = + new OffClass("Off", + Tango::DEV_VOID, Tango::DEV_VOID, + "", + "", + Tango::OPERATOR); + command_list.push_back(pOffCmd); + /*----- PROTECTED REGION ID(DataExporterClass::command_factory_after) ENABLED START -----*/ // Add your own code diff --git a/src/DataExporterClass.h b/src/DataExporterClass.h index eae172a..86bd2c2 100644 --- a/src/DataExporterClass.h +++ b/src/DataExporterClass.h @@ -56,6 +56,56 @@ namespace DataExporter_ns /*----- PROTECTED REGION END -----*/ // DataExporterClass::classes for dynamic creation +//========================================= +// Define classes for commands +//========================================= +// Command On class definition +class OnClass : public Tango::Command +{ +public: + OnClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + OnClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~OnClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<DataExporter *>(dev))->is_On_allowed(any);} +}; + +// Command Off class definition +class OffClass : public Tango::Command +{ +public: + OffClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out, + const char *in_desc, + const char *out_desc, + Tango::DispLevel level) + :Command(name,in,out,in_desc,out_desc, level) {}; + + OffClass(const char *name, + Tango::CmdArgType in, + Tango::CmdArgType out) + :Command(name,in,out) {}; + ~OffClass() {}; + + virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any); + virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any) + {return (static_cast<DataExporter *>(dev))->is_Off_allowed(any);} +}; + + /** * The DataExporterClass singleton definition */ @@ -71,6 +121,22 @@ class DataExporterClass : public Tango::DeviceClass /*----- PROTECTED REGION END -----*/ // DataExporterClass::Additionnal DServer data members + // Class properties data members + public: + // CertificateFile: Absolute path to certificate chain file + string certificateFile; + // PrivateKeyFile: Absolute path to private key file + string privateKeyFile; + // DHTempFile: Absolute path to Diffie Hellman temporary file + string dHTempFile; + // ExportedTables: Tables exported from database: one table per row + // [schema table] + vector<string> exportedTables; + // AuthorisedUsers: Authorised user list: one user per row + // [username password] + vector<string> authorisedUsers; + // StoragePath: Absolute path to storage + string storagePath; public: // write class properties data members Tango::DbData cl_prop; diff --git a/src/DataExporterStateMachine.cpp b/src/DataExporterStateMachine.cpp index 6029d4e..09afe08 100644 --- a/src/DataExporterStateMachine.cpp +++ b/src/DataExporterStateMachine.cpp @@ -42,6 +42,9 @@ static const char *RcsId = "$Id: $"; //================================================================ // States | Description //================================================================ +// ON | Data exporter is in ON state (ready to incoming connections) +// OFF | Data exporter is in OFF state (not ready for incoming connections) +// FAULT | Data exporter is in FAULT state (an error occurred) namespace DataExporter_ns @@ -54,4 +57,34 @@ namespace DataExporter_ns // Commands Allowed Methods //================================================= +//-------------------------------------------------------- +/** + * Method : DataExporter::is_On_allowed() + * Description : Execution allowed for On attribute + */ +//-------------------------------------------------------- +bool DataExporter::is_On_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for On command. + /*----- PROTECTED REGION ID(DataExporter::OnStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // DataExporter::OnStateAllowed + return true; +} + +//-------------------------------------------------------- +/** + * Method : DataExporter::is_Off_allowed() + * Description : Execution allowed for Off attribute + */ +//-------------------------------------------------------- +bool DataExporter::is_Off_allowed(TANGO_UNUSED(const CORBA::Any &any)) +{ + // Not any excluded states for Off command. + /*----- PROTECTED REGION ID(DataExporter::OffStateAllowed) ENABLED START -----*/ + + /*----- PROTECTED REGION END -----*/ // DataExporter::OffStateAllowed + return true; +} + } // End of namespace diff --git a/src/PlainServer.cpp b/src/PlainServer.cpp new file mode 100644 index 0000000..22c083e --- /dev/null +++ b/src/PlainServer.cpp @@ -0,0 +1,52 @@ +#include <PlainServer.h> +#include <PlainSession.h> + +namespace DataExporter_ns +{ + +//============================================================================== +// PlainServer::PlainServer() +//============================================================================== +PlainServer::PlainServer(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) : + Server::Server(deviceImpl_p, configuration_sp) +{ + DEBUG_STREAM << "PlainServer::PlainServer()" << endl; +} + +//============================================================================== +// PlainServer::~PlainServer() +//============================================================================== +PlainServer::~PlainServer() +{ + DEBUG_STREAM << "PlainServer::~PlainServer()" << endl; +} + +//============================================================================== +// PlainServer::create() +//============================================================================== +Server::SP PlainServer::create(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) +{ + Server::SP s_sp(new PlainServer(deviceImpl_p, configuration_sp), + PlainServer::Deleter()); + + return s_sp; +} + +//============================================================================== +// PlainServer::startAccept() +//============================================================================== +void PlainServer::startAccept() +{ + DEBUG_STREAM << "PlainServer::startAccept()" << endl; + + Session::SP session_sp = PlainSession::create(m_deviceImpl_p, + m_configuration_sp, m_dBManager_sp, m_ioService_sp); + + m_acceptor_sp->async_accept(session_sp->getSocket(), + boost::bind(&PlainServer::handleAccept, this, + session_sp, boost::asio::placeholders::error)); +} + +} //namespace diff --git a/src/PlainServer.h b/src/PlainServer.h new file mode 100644 index 0000000..f3655b6 --- /dev/null +++ b/src/PlainServer.h @@ -0,0 +1,42 @@ +#ifndef PLAINSERVER_H +#define PLAINSERVER_H + +#include <Server.h> +#include <Configuration.h> + +namespace DataExporter_ns +{ + +class PlainServer : public Server +{ +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + PlainServer(Tango::DeviceImpl*, Configuration::SP); + + virtual ~PlainServer(); + + class Deleter; + friend Deleter; + class Deleter + { + public: + void operator()(PlainServer* d) { delete d; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Class creation method +//------------------------------------------------------------------------------ + static Server::SP create(Tango::DeviceImpl*, Configuration::SP); + +//------------------------------------------------------------------------------ +// [Protected] Incoming connection method +//------------------------------------------------------------------------------ + virtual void startAccept(); +}; + +} //End of namespace + +#endif /* PLAINSERVER_H */ + diff --git a/src/PlainSession.cpp b/src/PlainSession.cpp new file mode 100644 index 0000000..c429da0 --- /dev/null +++ b/src/PlainSession.cpp @@ -0,0 +1,161 @@ +#include <PlainSession.h> + +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> + +namespace DataExporter_ns +{ + +//============================================================================== +// PlainSession::PlainSession() +//============================================================================== +PlainSession::PlainSession(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp, DBManager::SP dBManager_sp, + boost::shared_ptr<boost::asio::io_service> ioService_sp) : + Session::Session(deviceImpl_p,configuration_sp, dBManager_sp, ioService_sp), + m_plainSocket(*ioService_sp) +{ + DEBUG_STREAM << "PlainSession::PlainSession()" << endl; +} + +//============================================================================== +// PlainSession::~PlainSession() +//============================================================================== +PlainSession::~PlainSession() +{ + DEBUG_STREAM << "PlainSession::~PlainSession()" << endl; + + INFO_STREAM << "PlainSession::~PlainSession() Disconnection from " + << m_remoteEndpoint << endl; + + boost::system::error_code errorCode; + + m_plainSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorCode); + + m_plainSocket.close(errorCode); +} + +//============================================================================== +// PlainSession::create() +//============================================================================== +Session::SP PlainSession::create(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp, DBManager::SP dBManager_sp, + boost::shared_ptr<boost::asio::io_service> ioService_sp) +{ + Session::SP s_sp(new PlainSession(deviceImpl_p, configuration_sp, + dBManager_sp, ioService_sp), PlainSession::Deleter()); + + return s_sp; +} + +//============================================================================== +// PlainSession::getSocket() +//============================================================================== +boost::asio::ip::tcp::socket& PlainSession::getSocket() +{ + DEBUG_STREAM << "PlainSession::getSocket()" << endl; + + return m_plainSocket; +} + +//============================================================================== +// PlainSession::start() +//============================================================================== +void PlainSession::start() +{ + DEBUG_STREAM << "PlainSession::start()" << endl; + +// m_remoteEndpoint = boost::lexical_cast<std::string>( +// m_plainSocket.remote_endpoint()); +// +// INFO_STREAM << "PlainSession::start() Connection from " +// << m_remoteEndpoint << endl; +// +// m_protocolManager_sp->setRemoteEndpoint(m_remoteEndpoint); +// +// startReadRequestHeader(); +} + +////============================================================================== +//// PlainSession::startReadRequestHeader() +////============================================================================== +//void PlainSession::startReadRequestHeader() +//{ +// DEBUG_STREAM << "PlainSession::startReadRequestHeader()" << endl; +// +// m_readBuff.resize(HEADER_SIZE); +// +// boost::asio::async_read(m_plainSocket, boost::asio::buffer(m_readBuff), +// m_strand.wrap(boost::bind(&PlainSession::handleReadRequestHeader, +// shared_from_this(), boost::asio::placeholders::error))); +//} +// +////============================================================================== +//// PlainSession::startReadRequestBody() +////============================================================================== +//void PlainSession::startReadRequestBody(boost::uint32_t bodySize) +//{ +// DEBUG_STREAM << "PlainSession::startReadRequestBody()" << endl; +// +// m_readBuff.resize(HEADER_SIZE + bodySize); +// +// boost::asio::mutable_buffers_1 mutableBuffer = +// boost::asio::buffer(&m_readBuff[HEADER_SIZE], bodySize); +// +// #ifdef VERBOSE_DEBUG +// INFO_STREAM << "PlainSession::startReadRequestBody() " +// << m_remoteEndpoint << " >>>> " << bodySize << " BYTE" << endl; +// #endif +// +// boost::asio::async_read(m_plainSocket, mutableBuffer, +// m_strand.wrap(boost::bind(&PlainSession::handleReadRequestBody, +// shared_from_this(), boost::asio::placeholders::error))); +//} +// +////============================================================================== +//// PlainSession::startWriteResponse() +////============================================================================== +//void PlainSession::startWriteResponse() +//{ +// DEBUG_STREAM << "PlainSession::startWriteResponse()" << endl; +// +// try +// { +// RequestSP request_sp(new Request); +// +// request_sp->ParseFromArray(&m_readBuff[HEADER_SIZE], m_readBuff.size() - HEADER_SIZE); +// +// ResponseSP response_sp = m_protocolManager_sp->prepareResponse(request_sp); +// +// boost::uint32_t bodySize = response_sp->ByteSize(); +// +// std::vector<boost::uint8_t> writeBuff; +// writeBuff.resize(HEADER_SIZE + bodySize); +// +// encodeHeader(writeBuff, bodySize); +// +// response_sp->SerializeToArray(&writeBuff[HEADER_SIZE], bodySize); +// +// #ifdef VERBOSE_DEBUG +// INFO_STREAM << "PlainSession::startWriteResponse() " +// << m_remoteEndpoint << " <<<< " << bodySize << " byte" << endl; +// #endif +// +// boost::asio::async_write(m_plainSocket, boost::asio::buffer(writeBuff), +// m_strand.wrap(boost::bind(&PlainSession::handleWriteResponse, +// shared_from_this(), boost::asio::placeholders::error))); +// } +// catch(std::exception& ec) +// { +// ERROR_STREAM << "SSLSession::startWriteResponse() " +// << ec.what() << " from " << m_remoteEndpoint << endl; +// } +// catch(...) +// { +// ERROR_STREAM << "SSLSession::startWriteResponse() unknown error from " +// << m_remoteEndpoint << endl; +// +// } +//} + +} //namespace \ No newline at end of file diff --git a/src/PlainSession.h b/src/PlainSession.h new file mode 100644 index 0000000..ea76008 --- /dev/null +++ b/src/PlainSession.h @@ -0,0 +1,67 @@ +#ifndef PLAINSESSION_H +#define PLAINSESSION_H + +#include <Session.h> + +#include <tango.h> + +#include <boost/enable_shared_from_this.hpp> + +namespace DataExporter_ns +{ + +class PlainSession : public Session, + public boost::enable_shared_from_this<PlainSession> +{ +protected: +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + PlainSession(Tango::DeviceImpl*, Configuration::SP, DBManager::SP, + boost::shared_ptr<boost::asio::io_service>); + + virtual ~PlainSession(); + + class Deleter; + friend Deleter; + class Deleter + { + public: + void operator()(PlainSession* d) { delete d; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Class creation method +//------------------------------------------------------------------------------ + static Session::SP create(Tango::DeviceImpl*, Configuration::SP, + DBManager::SP, boost::shared_ptr<boost::asio::io_service>); + +//------------------------------------------------------------------------------ +// [Public] Incoming connection methods +//------------------------------------------------------------------------------ + virtual boost::asio::ip::tcp::socket& getSocket(); + + virtual void start(); + +protected: +////------------------------------------------------------------------------------ +//// [Protected] Request response methods +////------------------------------------------------------------------------------ +// virtual void startReadRequestHeader(); +// +// virtual void startReadRequestBody(boost::uint32_t); +// +// virtual void startWriteResponse(); + +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //TCP socket object + boost::asio::ip::tcp::socket m_plainSocket; +}; + +} //End of namespace + +#endif /* PLAINSESSION_H */ + diff --git a/src/SSLServer.cpp b/src/SSLServer.cpp new file mode 100644 index 0000000..4bc67ff --- /dev/null +++ b/src/SSLServer.cpp @@ -0,0 +1,87 @@ +#include <SSLServer.h> +#include <SSLSession.h> + +#include <boost/bind.hpp> + +namespace DataExporter_ns +{ + +//============================================================================== +// SSLServer::SSLServer() +//============================================================================== +SSLServer::SSLServer(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) : + Server::Server(deviceImpl_p, configuration_sp) +{ + DEBUG_STREAM << "SSLServer::SSLServer()" << endl; + + m_context_sp.reset(new boost::asio::ssl::context(*m_ioService_sp, + boost::asio::ssl::context::sslv23)); + + m_context_sp->set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use); + + //@todo: ssl certificate password + m_context_sp->set_password_callback(boost::bind(&SSLServer::getPassword, this)); + + std::string certificateFile = m_configuration_sp->getCertificateFile(); + std::string privateKey = m_configuration_sp->getPrivateKeyFile(); + std::string dHTempFile = m_configuration_sp->getDHTempFile(); + + INFO_STREAM << "SSLServer::SSLServer() Certificate " << certificateFile << endl; + INFO_STREAM << "SSLServer::SSLServer() Private key " << privateKey << endl; + INFO_STREAM << "SSLServer::SSLServer() DH Temporary " << dHTempFile << endl; + + //@todo: check error_code use in load file methods + m_context_sp->use_certificate_chain_file(certificateFile); + m_context_sp->use_private_key_file(privateKey, boost::asio::ssl::context::pem); + m_context_sp->use_tmp_dh_file(dHTempFile); +} + +//============================================================================== +// SSLServer::~SSLServer() +//============================================================================== +SSLServer::~SSLServer() +{ + DEBUG_STREAM << "SSLServer::~SSLServer()" << endl; +} + +//============================================================================== +// SSLServer::create() +//============================================================================== +Server::SP SSLServer::create(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp) +{ + Server::SP s_sp(new SSLServer(deviceImpl_p, configuration_sp), + SSLServer::Deleter()); + + return s_sp; +} + +//============================================================================== +// SSLServer::startAccept() +//============================================================================== +void SSLServer::startAccept() +{ + DEBUG_STREAM << "SSLServer::startAccept()" << endl; + + Session::SP session_sp = SSLSession::create(m_deviceImpl_p, + m_configuration_sp, m_dBManager_sp, m_ioService_sp, m_context_sp); + + m_acceptor_sp->async_accept(session_sp->getSocket(), + boost::bind(&SSLServer::handleAccept, this, + session_sp, boost::asio::placeholders::error)); +} + +//============================================================================== +// SSLServer::startAccept() +//============================================================================== +std::string SSLServer::getPassword() +{ + DEBUG_STREAM << "SSLServer::getPassword()" << endl; + + return "test"; +} + +} //namespace diff --git a/src/SSLServer.h b/src/SSLServer.h new file mode 100644 index 0000000..db74b71 --- /dev/null +++ b/src/SSLServer.h @@ -0,0 +1,56 @@ +#ifndef SSLSERVER_H +#define SSLSERVER_H + +#include <Server.h> +#include <Configuration.h> + +#include <boost/asio/ssl.hpp> + +namespace DataExporter_ns +{ + +class SSLServer : public Server +{ +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + SSLServer(Tango::DeviceImpl*, Configuration::SP); + + virtual ~SSLServer(); + + class Deleter; + friend Deleter; + class Deleter + { + public: + void operator()(SSLServer* d) { delete d; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Class creation method +//------------------------------------------------------------------------------ + static Server::SP create(Tango::DeviceImpl*, Configuration::SP); + +//------------------------------------------------------------------------------ +// [Protected] Incoming connection method +//------------------------------------------------------------------------------ + virtual void startAccept(); + +protected: +//------------------------------------------------------------------------------ +// [Protected] Utilities methods +//------------------------------------------------------------------------------ + virtual std::string getPassword(); + +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //SSL context shared pointer + boost::shared_ptr<boost::asio::ssl::context> m_context_sp; +}; + +} //End of namespace + +#endif /* SSLSERVER_H */ + diff --git a/src/SSLSession.cpp b/src/SSLSession.cpp new file mode 100644 index 0000000..d971949 --- /dev/null +++ b/src/SSLSession.cpp @@ -0,0 +1,196 @@ +#include <SSLSession.h> + +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> + +namespace DataExporter_ns +{ + +//============================================================================== +// SSLSession::SSLSession() +//============================================================================== +SSLSession::SSLSession(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp, DBManager::SP dBManager_sp, + boost::shared_ptr<boost::asio::io_service> ioService_sp, + boost::shared_ptr<boost::asio::ssl::context> context_sp) : + Session::Session(deviceImpl_p, configuration_sp, dBManager_sp, ioService_sp), + m_sslSocket(*ioService_sp, *context_sp) +{ + DEBUG_STREAM << "SSLSession::SSLSession()" << endl; +} + +//============================================================================== +// SSLSession::~SSLSession() +//============================================================================== +SSLSession::~SSLSession() +{ + DEBUG_STREAM << "SSLSession::~SSLSession()" << endl; + + INFO_STREAM << "SSLSession::~SSLSession() Disconnection from " + << m_remoteEndpoint << endl; + + boost::system::error_code errorCode; + + m_sslSocket.shutdown(errorCode); + + m_sslSocket.lowest_layer().shutdown( + boost::asio::ip::tcp::socket::shutdown_both, errorCode); + + m_sslSocket.lowest_layer().close(errorCode); +} + +//============================================================================== +// SSLSession::create() +//============================================================================== +Session::SP SSLSession::create(Tango::DeviceImpl* deviceImpl_p, + Configuration::SP configuration_sp, DBManager::SP dBManager_sp, + boost::shared_ptr<boost::asio::io_service> ioService_sp, + boost::shared_ptr<boost::asio::ssl::context> context_sp) +{ + Session::SP s_sp(new SSLSession(deviceImpl_p, configuration_sp, + dBManager_sp, ioService_sp, context_sp), SSLSession::Deleter()); + + return s_sp; +} + +//============================================================================== +// SSLSession::getSocket() +//============================================================================== +boost::asio::ip::tcp::socket& SSLSession::getSocket() +{ + DEBUG_STREAM << "SSLSession::getSocket()" << endl; + + return m_sslSocket.next_layer(); +} + +//============================================================================== +// SSLSession::start() +//============================================================================== +void SSLSession::start() +{ + DEBUG_STREAM << "SSLSession::start()" << endl; + +// m_remoteEndpoint = boost::lexical_cast<std::string>( +// m_sslSocket.lowest_layer().remote_endpoint()); +// +// INFO_STREAM << "SSLSession::start() Connection from " +// << m_remoteEndpoint << endl; +// +// m_protocolManager_sp->setRemoteEndpoint(m_remoteEndpoint); +// +// startHandShake(); +} + +////============================================================================== +//// SSLSession::startHandShake() +////============================================================================== +//void SSLSession::startHandShake() +//{ +// DEBUG_STREAM << "SSLSession::startHandShake()" << endl; +// +// m_sslSocket.async_handshake(boost::asio::ssl::stream_base::server, +// boost::bind(&SSLSession::handleHandShake, shared_from_this(), +// boost::asio::placeholders::error)); +//} +// +////============================================================================== +//// SSLSession::handleRequest() +////============================================================================== +//void SSLSession::handleHandShake(const boost::system::error_code& errorCode) +//{ +// DEBUG_STREAM << "SSLSession::handleHandShake()" << endl; +// +// if(!errorCode) +// { +// startReadRequestHeader(); +// } +// else +// { +// ERROR_STREAM << "SSLSession::handleHandShake() error " +// << errorCode.message() << " from " << m_remoteEndpoint << endl; +// } +//} +// +////============================================================================== +//// SSLSession::startReadRequestHeader() +////============================================================================== +//void SSLSession::startReadRequestHeader() +//{ +// DEBUG_STREAM << "SSLSession::startReadRequestHeader()" << endl; +// +// m_readBuff.resize(HEADER_SIZE); +// +// boost::asio::async_read(m_sslSocket, boost::asio::buffer(m_readBuff), +// m_strand.wrap(boost::bind(&SSLSession::handleReadRequestHeader, +// shared_from_this(), boost::asio::placeholders::error))); +//} +// +////============================================================================== +//// SSLSession::startReadRequestBody() +////============================================================================== +//void SSLSession::startReadRequestBody(boost::uint32_t bodySize) +//{ +// DEBUG_STREAM << "SSLSession::startReadRequestBody()" << endl; +// +// m_readBuff.resize(HEADER_SIZE + bodySize); +// +// boost::asio::mutable_buffers_1 mutableBuffer = +// boost::asio::buffer(&m_readBuff[HEADER_SIZE], bodySize); +// +// #ifdef VERBOSE_DEBUG +// INFO_STREAM << "SSLSession::startReadRequestBody() " +// << m_remoteEndpoint << " >>>> " << bodySize << " byte" << endl; +// #endif +// +// boost::asio::async_read(m_sslSocket, mutableBuffer, +// m_strand.wrap(boost::bind(&SSLSession::handleReadRequestBody, +// shared_from_this(), boost::asio::placeholders::error))); +//} +// +////============================================================================== +//// SSLSession::startWriteResponse() +////============================================================================== +//void SSLSession::startWriteResponse() +//{ +// DEBUG_STREAM << "SSLSession::startWriteResponse()" << endl; +// +// try +// { +// RequestSP request_sp(new Request); +// +// request_sp->ParseFromArray(&m_readBuff[HEADER_SIZE], +// m_readBuff.size() - HEADER_SIZE); +// +// ResponseSP response_sp = m_protocolManager_sp->prepareResponse(request_sp); +// +// boost::uint32_t bodySize = response_sp->ByteSize(); +// +// std::vector<boost::uint8_t> writeBuff; +// writeBuff.resize(HEADER_SIZE + bodySize); +// +// encodeHeader(writeBuff, bodySize); +// +// response_sp->SerializeToArray(&writeBuff[HEADER_SIZE], bodySize); +// +// #ifdef VERBOSE_DEBUG +// INFO_STREAM << "SSLSession::startWriteResponse() " +// << m_remoteEndpoint << " <<<< " << bodySize << " byte" << endl; +// #endif +// +// boost::asio::async_write(m_sslSocket, boost::asio::buffer(writeBuff), +// m_strand.wrap(boost::bind(&SSLSession::handleWriteResponse, +// shared_from_this(), boost::asio::placeholders::error))); +// } +// catch(std::exception& ec) +// { +// ERROR_STREAM << "SSLSession::startWriteResponse() " +// << ec.what() << " from " << m_remoteEndpoint << endl; +// } +// catch(...) +// { +// ERROR_STREAM << "SSLSession::startWriteResponse() unknown error from " +// << m_remoteEndpoint << endl; +// } +//} + +} //namespace diff --git a/src/SSLSession.h b/src/SSLSession.h new file mode 100644 index 0000000..7967c21 --- /dev/null +++ b/src/SSLSession.h @@ -0,0 +1,77 @@ +#ifndef SSLSESSION_H +#define SSLSESSION_H + +#include <Session.h> + +#include <tango.h> + +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio/ssl.hpp> + +namespace DataExporter_ns +{ + +class SSLSession : public Session, + public boost::enable_shared_from_this<SSLSession> +{ +protected: +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + SSLSession(Tango::DeviceImpl*, Configuration::SP, DBManager::SP, + boost::shared_ptr<boost::asio::io_service>, + boost::shared_ptr<boost::asio::ssl::context>); + + virtual ~SSLSession(); + + class Deleter; + friend Deleter; + class Deleter + { + public: + void operator()(SSLSession* d) { delete d; } + }; + +public: +//------------------------------------------------------------------------------ +// [Public] Class creation method +//------------------------------------------------------------------------------ + static Session::SP create(Tango::DeviceImpl*, Configuration::SP, + DBManager::SP, boost::shared_ptr<boost::asio::io_service>, + boost::shared_ptr<boost::asio::ssl::context>); + +//------------------------------------------------------------------------------ +// [Public] Incoming connection methods +//------------------------------------------------------------------------------ + virtual boost::asio::ip::tcp::socket& getSocket(); + + virtual void start(); + +protected: +////------------------------------------------------------------------------------ +//// [Protected] SSL handshake initialization methods +////------------------------------------------------------------------------------ +// virtual void startHandShake(); +// +// virtual void handleHandShake(const boost::system::error_code&); +// +////------------------------------------------------------------------------------ +//// [Protected] Request response methods +////------------------------------------------------------------------------------ +// virtual void startReadRequestHeader(); +// +// virtual void startReadRequestBody(boost::uint32_t); +// +// virtual void startWriteResponse(); + +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //SSL socket object + boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_sslSocket; +}; + +} //End of namespace + +#endif /* SSLSESSION_H */ + diff --git a/src/Server.cpp b/src/Server.cpp new file mode 100644 index 0000000..b9c7e10 --- /dev/null +++ b/src/Server.cpp @@ -0,0 +1,197 @@ +#include <Server.h> +#include <WorkerThread.h> + +#include <boost/lexical_cast.hpp> + +namespace DataExporter_ns +{ + +//============================================================================== +// Server::Server() +//============================================================================== +Server::Server(Tango::DeviceImpl* deviceImpl_p, Configuration::SP configuration_sp) : + Tango::LogAdapter(deviceImpl_p), m_deviceImpl_p(deviceImpl_p), + m_configuration_sp(configuration_sp) +{ + DEBUG_STREAM << "Server::Server()" << endl; + + //GOOGLE_PROTOBUF_VERIFY_VERSION; + + m_dBManager_sp = DBManager::create(deviceImpl_p, configuration_sp); + + m_ioService_sp.reset(new boost::asio::io_service); + + m_acceptor_sp.reset(new boost::asio::ip::tcp::acceptor(*m_ioService_sp)); + + m_state = Tango::OFF; + m_status="Disconnected"; +} + +//============================================================================== +// Server::Server() +//============================================================================== +Server::~Server() +{ + DEBUG_STREAM << "Server::~Server()" << endl; + + boost::system::error_code errorCode; + m_acceptor_sp->close(errorCode); + + m_work_sp.reset(); + + m_ioService_sp->stop(); + + if(m_threadGroup_sp) + { + m_threadGroup_sp->interrupt_all(); + + m_threadGroup_sp->join_all(); + } + + //google::protobuf::ShutdownProtobufLibrary(); +} + +//============================================================================== +// Server::start() +//============================================================================== +void Server::start() throw(std::runtime_error) +{ + DEBUG_STREAM << "Server::start()" << endl; + + m_dBManager_sp->connect(); + + m_ioService_sp->reset(); + + m_work_sp.reset(new boost::asio::io_service::work(*m_ioService_sp)); + + std::string localHost = m_configuration_sp->getLocalHost(); + unsigned int localPort = m_configuration_sp->getLocalPort(); + + std::stringstream infoStream; + infoStream << "Listening on " << localHost << ":" << localPort << endl; + + INFO_STREAM << "Server::start()" << infoStream.str() << endl; + + writeState(Tango::ON); + writeStatus(infoStream.str()); + + boost::asio::ip::tcp::resolver::query query(localHost, + boost::lexical_cast<std::string>(localPort)); + + boost::asio::ip::tcp::resolver resolver(*m_ioService_sp); + boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); + + m_acceptor_sp->open(endpoint.protocol()); + m_acceptor_sp->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + m_acceptor_sp->bind(endpoint); + m_acceptor_sp->listen(); + + m_threadGroup_sp.reset(new boost::thread_group); + + unsigned int workerNumber = m_configuration_sp->getWorkerNumber(); + + WorkerThread worker(m_deviceImpl_p, m_ioService_sp); + + for(unsigned int i=0; i<workerNumber; ++i) + m_threadGroup_sp->add_thread(new boost::thread(&WorkerThread::run, worker)); + + startAccept(); +} + +//============================================================================== +// Server::stop() +//============================================================================== +void Server::stop() throw(std::runtime_error) +{ + DEBUG_STREAM << "Server::stop()" << endl; + + writeState(Tango::OFF); + writeStatus("Disconnected"); + + boost::system::error_code errorCode; + m_acceptor_sp->close(errorCode); + + m_work_sp.reset(); + + m_ioService_sp->stop(); + + if(m_threadGroup_sp) + { + m_threadGroup_sp->interrupt_all(); + + m_threadGroup_sp->join_all(); + } + + m_threadGroup_sp.reset(); + + m_dBManager_sp->disconnect(); +} +//============================================================================== +// Server::readState() +//============================================================================== +Tango::DevState Server::readState() +{ + DEBUG_STREAM << "Server::readState()" << endl; + + boost::mutex::scoped_lock stateLock(m_stateMutex); + + return m_state; +} + +//============================================================================== +// Server::readStatus() +//============================================================================== +std::string Server::readStatus() +{ + DEBUG_STREAM << "Server::readStatus()" << endl; + + boost::mutex::scoped_lock statusLock(m_statusMutex); + + return m_status; +} + +//============================================================================== +// Server::writeState() +//============================================================================== +void Server::writeState(Tango::DevState state) +{ + DEBUG_STREAM << "Server::writeState()" << endl; + + boost::mutex::scoped_lock stateLock(m_stateMutex); + + m_state = state; +} + +//============================================================================== +// Server::writeStatus() +//============================================================================== +void Server::writeStatus(std::string status) +{ + DEBUG_STREAM << "Server::writeStatus()" << endl; + + boost::mutex::scoped_lock statusLock(m_statusMutex); + + m_status = status; +} + +//============================================================================== +// Server::handleAccept() +//============================================================================== +void Server::handleAccept(Session::SP session_sp, + const boost::system::error_code& ec) +{ + DEBUG_STREAM << "Server::handleAccept()" << endl; + + if(!ec) + { + session_sp->start(); + } + else + { + ERROR_STREAM << "Server::handleAccept() " << ec.message() << endl; + } + + startAccept(); +} + +} //namespace \ No newline at end of file diff --git a/src/Server.h b/src/Server.h new file mode 100644 index 0000000..9d030a6 --- /dev/null +++ b/src/Server.h @@ -0,0 +1,103 @@ +#ifndef SERVER_H +#define SERVER_H + +#include <Configuration.h> +#include <DBManager.h> +#include <Session.h> + +#include <tango.h> + +#include <boost/shared_ptr.hpp> +#include <boost/asio.hpp> +#include <boost/thread.hpp> + +namespace DataExporter_ns +{ + +class Server : public Tango::LogAdapter +{ +public: +//------------------------------------------------------------------------------ +// [Public] Shared pointer typedef +//------------------------------------------------------------------------------ + typedef boost::shared_ptr<Server> SP; + +protected: +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor +//------------------------------------------------------------------------------ + Server(Tango::DeviceImpl*, Configuration::SP); + + virtual ~Server(); + +public: +//------------------------------------------------------------------------------ +// [Public] Thread management methods +//------------------------------------------------------------------------------ + virtual void start() throw(std::runtime_error); + + virtual void stop() throw(std::runtime_error); + +//------------------------------------------------------------------------------ +// [Public] Read state and status methods +//------------------------------------------------------------------------------ + virtual Tango::DevState readState(); + + virtual std::string readStatus(); + +protected: +//------------------------------------------------------------------------------ +// [Protected] Write state and status methods +//------------------------------------------------------------------------------ + virtual void writeState(Tango::DevState); + + virtual void writeStatus(std::string); + +//------------------------------------------------------------------------------ +// [Protected] Incoming connection methods +//------------------------------------------------------------------------------ + virtual void startAccept() = 0; + + virtual void handleAccept(Session::SP, const boost::system::error_code&); + +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //Device server base class pointer + Tango::DeviceImpl* m_deviceImpl_p; + + //Configuration parameters shared pointer + Configuration::SP m_configuration_sp; + + //Database data access class + DBManager::SP m_dBManager_sp; + + //Io service used for async operations + boost::shared_ptr<boost::asio::io_service> m_ioService_sp; + + //Prevents io service to run out of work and return + boost::shared_ptr<boost::asio::io_service::work> m_work_sp; + + //Acceptor for incoming connection + boost::shared_ptr<boost::asio::ip::tcp::acceptor> m_acceptor_sp; + + //Thread group container shared pointer + boost::shared_ptr<boost::thread_group> m_threadGroup_sp; + + //Tango state property mutex + boost::mutex m_stateMutex; + + //Tango state property + Tango::DevState m_state; + + //Tango status property mutex + boost::mutex m_statusMutex; + + //Tango status property + std::string m_status; +}; + +} //End of namespace + +#endif /* SERVER_H */ + diff --git a/src/Session.cpp b/src/Session.cpp new file mode 100644 index 0000000..a3ca0e5 --- /dev/null +++ b/src/Session.cpp @@ -0,0 +1,135 @@ +#include <Session.h> + +namespace DataExporter_ns +{ + +//============================================================================== +// Session::Session() +//============================================================================== +Session::Session(Tango::DeviceImpl* deviceImpl_p, Configuration::SP configuration_sp, + DBManager::SP dBManager_sp, boost::shared_ptr<boost::asio::io_service> ioService_sp) : + Tango::LogAdapter(deviceImpl_p), m_configuration_sp(configuration_sp), + m_strand(*ioService_sp) +{ + DEBUG_STREAM << "Session::Session()" << endl; + +// m_protocolManager_sp = ProtocolManager::create(deviceImpl_p, +// configuration_sp, dBManager_sp); +} + +//============================================================================== +// Session::~Session() +//============================================================================== +Session::~Session() +{ + DEBUG_STREAM << "Session::~Session()" << endl; +} + +////============================================================================== +//// Session::handleReadRequestHeader() +////============================================================================== +//void Session::handleReadRequestHeader(const boost::system::error_code& errorCode) +//{ +// DEBUG_STREAM << "Session::handleReadRequestHeader()" << endl; +// +// if(!errorCode) +// { +// boost::uint32_t bodySize = decodeHeader(m_readBuff); +// +// startReadRequestBody(bodySize); +// } +// else if(errorCode == boost::asio::error::eof) +// { +// DEBUG_STREAM << "Session::handleReadRequestBody() end of file from " +// << m_remoteEndpoint << endl; +// } +// else +// { +// ERROR_STREAM << "Session::handleReadRequestHeader() " +// << errorCode.message() << " from " << m_remoteEndpoint << endl; +// } +//} +// +////============================================================================== +//// Session::handleReadRequestBody() +////============================================================================== +//void Session::handleReadRequestBody(const boost::system::error_code& errorCode) +//{ +// DEBUG_STREAM << "Session::handleReadRequestBody()" << endl; +// +// if(!errorCode) +// { +// startWriteResponse(); +// } +// else if(errorCode == boost::asio::error::eof) +// { +// DEBUG_STREAM << "Session::handleReadRequestBody() end of file from" +// << m_remoteEndpoint << endl; +// } +// else +// { +// ERROR_STREAM << "Session::handleReadRequestBody() " +// << errorCode.message() << " from " << m_remoteEndpoint << endl; +// } +//} +// +////============================================================================== +//// Session::handleWriteResponse() +////============================================================================== +//void Session::handleWriteResponse(const boost::system::error_code& errorCode) +//{ +// DEBUG_STREAM << "Session::handleWriteResponse()" << endl; +// +// if(!errorCode) +// { +// startReadRequestHeader(); +// } +// else if(errorCode == boost::asio::error::eof) +// { +// DEBUG_STREAM << "Session::handleWriteResponse() end of file from " +// << m_remoteEndpoint << endl; +// } +// else +// { +// ERROR_STREAM << "Session::handleWriteResponse() " +// << errorCode.message() << " from " << m_remoteEndpoint << endl; +// } +//} +// +////============================================================================== +//// Session::encodeHeader() +////============================================================================== +//void Session::encodeHeader(std::vector<boost::uint8_t>& buf, boost::uint32_t size) +// throw(std::runtime_error) +//{ +// DEBUG_STREAM << "Session::encodeHeader()" << endl; +// +// if(buf.size() < HEADER_SIZE) +// throw std::runtime_error("Buffer to small to contain header!"); +// +// buf[0] = static_cast<boost::uint8_t>((size >> 24) & 0xFF); +// buf[1] = static_cast<boost::uint8_t>((size >> 16) & 0xFF); +// buf[2] = static_cast<boost::uint8_t>((size >> 8) & 0xFF); +// buf[3] = static_cast<boost::uint8_t>(size & 0xFF); +//} +// +////============================================================================== +//// Session::decodeHeader() +////============================================================================== +//boost::uint32_t Session::decodeHeader(std::vector<boost::uint8_t>& buf) +// throw(std::runtime_error) +//{ +// DEBUG_STREAM << "Session::decodeHeader()" << endl; +// +// if(buf.size() < HEADER_SIZE) +// throw std::runtime_error("Buffer to small to contain header!"); +// +// boost::uint32_t size = 0; +// +// for (unsigned i = 0; i < HEADER_SIZE; ++i) +// size = size * 256 + (static_cast<unsigned>(buf[i]) & 0xFF); +// +// return size; +//} + +} //namespace diff --git a/src/Session.h b/src/Session.h new file mode 100644 index 0000000..166e34a --- /dev/null +++ b/src/Session.h @@ -0,0 +1,97 @@ +#ifndef SESSION_H +#define SESSION_H + +#include <Configuration.h> +#include <DBManager.h> + +#include <tango.h> + +#include <boost/asio.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> + +namespace DataExporter_ns +{ + +class Session : public Tango::LogAdapter +{ +public: +//------------------------------------------------------------------------------ +// [Public] Shared pointer typedef +//------------------------------------------------------------------------------ + typedef boost::shared_ptr<Session> SP; + +protected: +//------------------------------------------------------------------------------ +// [Protected] Constructor destructor deleter +//------------------------------------------------------------------------------ + Session(Tango::DeviceImpl*, Configuration::SP, DBManager::SP, + boost::shared_ptr<boost::asio::io_service>); + + virtual ~Session(); + +public: +//------------------------------------------------------------------------------ +// [Public] Incoming connection methods +//------------------------------------------------------------------------------ + virtual boost::asio::ip::tcp::socket& getSocket() = 0; + + virtual void start() = 0; + +protected: +////------------------------------------------------------------------------------ +//// [Protected] Read request header methods +////------------------------------------------------------------------------------ +// virtual void startReadRequestHeader() = 0; +// +// virtual void handleReadRequestHeader(const boost::system::error_code&); +// +////------------------------------------------------------------------------------ +//// [Protected] Read request body methods +////------------------------------------------------------------------------------ +// virtual void startReadRequestBody(boost::uint32_t) = 0; +// +// virtual void handleReadRequestBody(const boost::system::error_code&); +// +////------------------------------------------------------------------------------ +//// [Protected] Write response methods +////------------------------------------------------------------------------------ +// virtual void startWriteResponse() = 0; +// +// virtual void handleWriteResponse(const boost::system::error_code&); +// +////------------------------------------------------------------------------------ +//// [Protected] Encode decode header methods +////------------------------------------------------------------------------------ +// virtual void encodeHeader(std::vector<boost::uint8_t>&, boost::uint32_t) +// throw(std::runtime_error); +// +// virtual boost::uint32_t decodeHeader(std::vector<boost::uint8_t>&) +// throw(std::runtime_error); + +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //Configuration parameters shared pointer + Configuration::SP m_configuration_sp; + + //Protocol manager class shared pointer + //ProtocolManager::SP m_protocolManager_sp; + + //Synchronization mechanism + boost::asio::io_service::strand m_strand; + + //Header size written on socket + const unsigned int HEADER_SIZE = 4; + + //Binary buffer for read data + std::vector<boost::uint8_t> m_readBuff; + + //Address and port of remote endpoint + std::string m_remoteEndpoint; +}; + +} //End of namespace + +#endif /* SESSION_H */ + diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp new file mode 100644 index 0000000..132eb63 --- /dev/null +++ b/src/WorkerThread.cpp @@ -0,0 +1,59 @@ +#include <WorkerThread.h> +#include <boost/thread.hpp> + +namespace DataExporter_ns +{ + +//============================================================================== +// WorkerThread::WorkerThread() +//============================================================================== +WorkerThread::WorkerThread(Tango::DeviceImpl* deviceImpl_p, + boost::shared_ptr<boost::asio::io_service> ioService_sp) : + Tango::LogAdapter(deviceImpl_p), m_ioService_sp(ioService_sp) +{ + DEBUG_STREAM << "WorkerThread::WorkerThread()" << endl; +} + +//============================================================================== +// WorkerThread::~WorkerThread() +//============================================================================== +WorkerThread::~WorkerThread() +{ + DEBUG_STREAM << "WorkerThread::~WorkerThread()" << endl; +} + +//============================================================================== +// WorkerThread::run() +//============================================================================== +void WorkerThread::run() +{ + DEBUG_STREAM << "WorkerThread::run() Starting" << endl; + + while(true) + { + try + { + boost::system::error_code ec; + m_ioService_sp->run(ec); + + if(ec) + { + ERROR_STREAM << "WorkerThread::run() " << ec.message() << endl; + } + break; + } + catch(std::exception& ex) + { + ERROR_STREAM << "WorkerThread::run() " << ex.what() << endl; + } + catch(boost::thread_interrupted& ex) + { + DEBUG_STREAM << "WorkerThread::run() interrupt" << endl; + break; + } + } + + DEBUG_STREAM << "WorkerThread::run() Stopping" << endl; +} + +} \ No newline at end of file diff --git a/src/WorkerThread.h b/src/WorkerThread.h new file mode 100644 index 0000000..9d2f183 --- /dev/null +++ b/src/WorkerThread.h @@ -0,0 +1,37 @@ +#ifndef WORKERTHREAD_H +#define WORKERTHREAD_H + +#include <tango.h> + +#include <boost/shared_ptr.hpp> +#include <boost/asio/io_service.hpp> + +namespace DataExporter_ns +{ + +class WorkerThread : public Tango::LogAdapter +{ +public: +//------------------------------------------------------------------------------ +// [Public] Constructor destructor +//------------------------------------------------------------------------------ + WorkerThread(Tango::DeviceImpl*, boost::shared_ptr<boost::asio::io_service>); + virtual ~WorkerThread(); + +//------------------------------------------------------------------------------ +// [Public] Users method +//------------------------------------------------------------------------------ + virtual void run(); + +protected: +//------------------------------------------------------------------------------ +// [Protected] Class variables +//------------------------------------------------------------------------------ + //Io service object common to all threads + boost::shared_ptr<boost::asio::io_service> m_ioService_sp; +}; + +} //End of namespace + +#endif /* WORKERTHREAD_H */ + -- GitLab