Application::Ptr I2_EXPORT Application::Instance;
+/**
+ * Application
+ *
+ * Constructor for the Application class.
+ */
Application::Application(void)
{
#ifdef _WIN32
m_ConfigHive = make_shared<ConfigHive>();
}
+/**
+ * ~Application
+ *
+ * Destructor for the application class.
+ */
Application::~Application(void)
{
+ /* stop all components */
for (map<string, Component::Ptr>::iterator i = m_Components.begin();
i != m_Components.end(); i++) {
i->second->Stop();
#endif /* _WIN32 */
}
+/**
+ * RunEventLoop
+ *
+ * Processes events (e.g. sockets and timers).
+ */
void Application::RunEventLoop(void)
{
while (!m_ShuttingDown) {
}
}
+/**
+ * Shutdown
+ *
+ * Signals the application to shut down during the next
+ * execution of the event loop.
+ */
void Application::Shutdown(void)
{
m_ShuttingDown = true;
}
+/**
+ * GetConfigHive
+ *
+ * Returns the application's configuration hive.
+ *
+ * @returns The config hive.
+ */
ConfigHive::Ptr Application::GetConfigHive(void) const
{
return m_ConfigHive;
}
+/**
+ * LoadComponent
+ *
+ * Loads a component from a library.
+ *
+ * @param path The path of the component library.
+ * @param componentConfig The configuration for the component.
+ * @returns The component.
+ */
Component::Ptr Application::LoadComponent(const string& path,
const ConfigObject::Ptr& componentConfig)
{
return component;
}
+/**
+ * RegisterComponent
+ *
+ * Registers a component object and starts it.
+ *
+ * @param component The component.
+ */
void Application::RegisterComponent(Component::Ptr component)
{
component->SetApplication(static_pointer_cast<Application>(shared_from_this()));
component->Start();
}
+/**
+ * UnregisterComponent
+ *
+ * Unregisters a component object and stops it.
+ *
+ * @param component The component.
+ */
void Application::UnregisterComponent(Component::Ptr component)
{
string name = component->GetName();
Log("Unloading component '%s'", name.c_str());
map<string, Component::Ptr>::iterator i = m_Components.find(name);
- if (i != m_Components.end()) {
+ if (i != m_Components.end())
m_Components.erase(i);
- component->Stop();
- }
+
+ component->Stop();
}
+/**
+ * GetComponent
+ *
+ * Finds a loaded component by name.
+ *
+ * @param name The name of the component.
+ * @returns The component or a null pointer if the component could not be found.
+ */
Component::Ptr Application::GetComponent(const string& name)
{
map<string, Component::Ptr>::iterator ci = m_Components.find(name);
return ci->second;
}
+/**
+ * Log
+ *
+ * Logs a message.
+ *
+ * @param format The format string.
+ * @param ... Additional parameters for the format string.
+ */
void Application::Log(const char *format, ...)
{
char message[512];
fprintf(stderr, "%s\n", message);
}
+/**
+ * SetArguments
+ *
+ * Sets the application's arguments.
+ *
+ * @param arguments The arguments.
+ */
void Application::SetArguments(const vector<string>& arguments)
{
m_Arguments = arguments;
}
+/**
+ * GetArguments
+ *
+ * Retrieves the application's arguments.
+ *
+ * @returns The arguments.
+ */
const vector<string>& Application::GetArguments(void) const
{
return m_Arguments;
}
+/**
+ * GetExeDirectory
+ *
+ * Retrieves the directory the application's binary is contained in.
+ *
+ * @returns The directory.
+ */
string Application::GetExeDirectory(void) const
{
static string ExePath;
return ExePath;
}
+/**
+ * AddComponentSearchDir
+ *
+ * Adds a directory to the component search path.
+ *
+ * @param componentDirectory The directory.
+ */
void Application::AddComponentSearchDir(const string& componentDirectory)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
+/**
+ * IsDebugging
+ *
+ * Retrieves the debugging mode of the application.
+ *
+ * @returns true if the application is being debugged, false otherwise
+ */
bool Application::IsDebugging(void) const
{
return m_Debugging;
}
#ifndef _WIN32
+/**
+ * ApplicationSigIntHandler
+ *
+ * Signal handler for SIGINT.
+ *
+ * @param signum The signal number.
+ */
static void ApplicationSigIntHandler(int signum)
{
+ assert(signum == SIGINT);
+
Application::Instance->Shutdown();
struct sigaction sa;
}
#endif /* _WIN32 */
+/**
+ * RunApplication
+ *
+ * Runs the specified application.
+ *
+ * @param argc The number of arguments.
+ * @param argv The arguments that should be passed to the application.
+ * @param instance The application instance.
+ * @returns The application's exit code.
+ */
int icinga::RunApplication(int argc, char **argv, Application *instance)
{
int result;
<ClCompile Include="tcpsocket.cpp" />
<ClCompile Include="thread.cpp" />
<ClCompile Include="timer.cpp" />
+ <ClCompile Include="tlsclient.cpp" />
<ClCompile Include="unix.cpp" />
<ClCompile Include="utility.cpp" />
<ClCompile Include="variant.cpp" />
<ClInclude Include="tcpsocket.h" />
<ClInclude Include="thread.h" />
<ClInclude Include="timer.h" />
+ <ClInclude Include="tlsclient.h" />
<ClInclude Include="unix.h" />
<ClInclude Include="utility.h" />
<ClInclude Include="variant.h" />
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;libeay32MTd.lib;ssleay32MTd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;libeay32MT.lib;ssleay32MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib</AdditionalDependencies>
using namespace icinga;
+/**
+ * SetApplication
+ *
+ * Sets the application this component belongs to.
+ *
+ * @param application The application.
+ */
void Component::SetApplication(const Application::WeakPtr& application)
{
m_Application = application;
}
+/**
+ * GetApplication
+ *
+ * Retrieves the application this component belongs to.
+ *
+ * @returns The application.
+ */
Application::Ptr Component::GetApplication(void) const
{
return m_Application.lock();
}
+/**
+ * SetConfig
+ *
+ * Sets the configuration for this component.
+ *
+ * @param componentConfig The configuration.
+ */
void Component::SetConfig(const ConfigObject::Ptr& componentConfig)
{
m_Config = componentConfig;
}
+/**
+ * GetConfig
+ *
+ * Retrieves the configuration for this component.
+ *
+ * @returns The configuration.
+ */
ConfigObject::Ptr Component::GetConfig(void) const
{
return m_Config;
using namespace icinga;
+/**
+ * CondVar
+ *
+ * Constructor for the CondVar class.
+ */
CondVar::CondVar(void)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
+/**
+ * ~CondVar
+ *
+ * Destructor for the CondVar class.
+ */
CondVar::~CondVar(void)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
+/**
+ * Wait
+ *
+ * Waits for the condition variable to be signaled. Releases the specified mutex
+ * before it begins to wait and re-acquires the mutex after waiting.
+ *
+ * @param mtx The mutex that should be released during waiting.
+ */
void CondVar::Wait(Mutex& mtx)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
+/**
+ * Signal
+ *
+ * Wakes up at least one waiting thread.
+ */
void CondVar::Signal(void)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
+/**
+ * Broadcast
+ *
+ * Wakes up all waiting threads.
+ */
void CondVar::Broadcast(void)
{
#ifdef _WIN32
#endif /* _WIN32 */
}
-
+/**
+ * Get
+ *
+ * Retrieves the platform-specific condition variable handle.
+ *
+ * @returns The platform-specific condition variable handle.
+ */
#ifdef _WIN32
CONDITION_VARIABLE *CondVar::Get(void)
#else /* _WIN32 */
using namespace icinga;
+/**
+ * SetHive
+ *
+ * Sets the hive this collection belongs to.
+ *
+ * @param hive The hive.
+ */
void ConfigCollection::SetHive(const ConfigHive::WeakPtr& hive)
{
m_Hive = hive;
}
+/**
+ * GetHive
+ *
+ * Retrieves the hive this collection belongs to.
+ *
+ * @returns The hive.
+ */
ConfigHive::WeakPtr ConfigCollection::GetHive(void) const
{
return m_Hive;
}
+/**
+ * AddObject
+ *
+ * Adds a new object to this collection.
+ *
+ * @param object The new object.
+ */
void ConfigCollection::AddObject(const ConfigObject::Ptr& object)
{
RemoveObject(object);
hive->OnObjectCreated(ea);
}
+/**
+ * RemoveObject
+ *
+ * Removes an object from this collection
+ *
+ * @param object The object that is to be removed.
+ */
void ConfigCollection::RemoveObject(const ConfigObject::Ptr& object)
{
ObjectIterator oi = Objects.find(object->GetName());
}
}
-ConfigObject::Ptr ConfigCollection::GetObject(const string& name)
+/**
+ * GetObject
+ *
+ * Retrieves an object by name.
+ *
+ * @param name The name of the object.
+ * @returns The object or a null pointer if the specified object
+ * could not be found.
+ */
+ConfigObject::Ptr ConfigCollection::GetObject(const string& name) const
{
- ObjectIterator oi = Objects.find(name);
+ ObjectConstIterator oi = Objects.find(name);
if (oi == Objects.end())
return ConfigObject::Ptr();
return oi->second;
}
+/**
+ * ForEachObject
+ *
+ * Invokes the specified callback for each object contained in this collection.
+ *
+ * @param callback The callback.
+ */
void ConfigCollection::ForEachObject(function<int (const EventArgs&)> callback)
{
EventArgs ea;
typedef weak_ptr<ConfigCollection> WeakPtr;
typedef map<string, ConfigObject::Ptr>::iterator ObjectIterator;
+ typedef map<string, ConfigObject::Ptr>::const_iterator ObjectConstIterator;
map<string, ConfigObject::Ptr> Objects;
void SetHive(const weak_ptr<ConfigHive>& hive);
void AddObject(const ConfigObject::Ptr& object);
void RemoveObject(const ConfigObject::Ptr& object);
- ConfigObject::Ptr GetObject(const string& name = string());
+ ConfigObject::Ptr GetObject(const string& name = string()) const;
void ForEachObject(function<int (const EventArgs&)> callback);
using namespace icinga;
+/**
+ * AddObject
+ *
+ * Adds a new object to this hive.
+ *
+ * @param object The new object.
+ */
void ConfigHive::AddObject(const ConfigObject::Ptr& object)
{
object->SetHive(static_pointer_cast<ConfigHive>(shared_from_this()));
GetCollection(object->GetType())->AddObject(object);
}
+/**
+ * RemoveObject
+ *
+ * Removes an object from this hive.
+ *
+ * @param object The object that is to be removed.
+ */
void ConfigHive::RemoveObject(const ConfigObject::Ptr& object)
{
GetCollection(object->GetType())->RemoveObject(object);
}
+/**
+ * GetObject
+ *
+ * Retrieves an object by type and name.
+ *
+ * @param type The type of the object.
+ * @param name The name of the object.
+ * @returns The object or a null pointer if the specified object
+ * could not be found.
+ */
ConfigObject::Ptr ConfigHive::GetObject(const string& type, const string& name)
{
return GetCollection(type)->GetObject(name);
}
+/**
+ * GetCollection
+ *
+ * Retrieves a collection by name. Creates an empty collection
+ * if the collection doesn't already exist.
+ *
+ * @param collection The name of the collection.
+ * @returns The collection or a null pointer if the specified collection
+ * could not be found.
+ */
ConfigCollection::Ptr ConfigHive::GetCollection(const string& collection)
{
- CollectionIterator ci = Collections.find(collection);
+ CollectionConstIterator ci = Collections.find(collection);
if (ci == Collections.end()) {
Collections[collection] = make_shared<ConfigCollection>();
return ci->second;
}
+/**
+ * ForEachObject
+ *
+ * Invokes the specified callback for each object contained in this hive.
+ *
+ * @param callback The callback.
+ */
void ConfigHive::ForEachObject(const string& type,
function<int (const EventArgs&)> callback)
{
typedef weak_ptr<ConfigHive> WeakPtr;
typedef map<string, ConfigCollection::Ptr>::iterator CollectionIterator;
+ typedef map<string, ConfigCollection::Ptr>::const_iterator CollectionConstIterator;
map<string, ConfigCollection::Ptr> Collections;
void AddObject(const ConfigObject::Ptr& object);
using namespace icinga;
+/**
+ * ConfigObject
+ *
+ * Constructor for the ConfigObject class.
+ *
+ * @param type The type of the object.
+ * @param name The name of the object.
+ */
ConfigObject::ConfigObject(const string& type, const string& name)
{
m_Type = type;
m_Replicated = false;
}
+/**
+ * SetHive
+ *
+ * Sets the hive this object belongs to.
+ *
+ * @param hive The hive.
+ */
void ConfigObject::SetHive(const ConfigHive::WeakPtr& hive)
{
if (m_Hive.lock())
OnPropertyChanged += bind_weak(&ConfigObject::PropertyChangedHandler, shared_from_this());
}
+/**
+ * GetHive
+ *
+ * Retrieves the hive this object belongs to.
+ *
+ * @returns The hive.
+ */
ConfigHive::WeakPtr ConfigObject::GetHive(void) const
{
return m_Hive;
}
+/**
+ * SetName
+ *
+ * Sets the name of this object.
+ *
+ * @param name The name.
+ */
void ConfigObject::SetName(const string& name)
{
m_Name = name;
}
+/**
+ * GetName
+ *
+ * Retrieves the name of this object.
+ *
+ * @returns The name.
+ */
string ConfigObject::GetName(void) const
{
return m_Name;
}
+/**
+ * SetType
+ *
+ * Sets the type of this object.
+ *
+ * @param type The type.
+ */
void ConfigObject::SetType(const string& type)
{
m_Type = type;
}
+/**
+ * GetType
+ *
+ * Retrieves the type of this object.
+ *
+ * @returns The type.
+ */
string ConfigObject::GetType(void) const
{
return m_Type;
}
+/**
+ * SetReplicated
+ *
+ * Sets whether this object was replicated.
+ *
+ * @param replicated Whether this object was replicated.
+ */
void ConfigObject::SetReplicated(bool replicated)
{
m_Replicated = replicated;
}
+/**
+ * GetReplicated
+ *
+ * Retrieves whether this object was replicated.
+ *
+ * @returns Whether this object was replicated.
+ */
bool ConfigObject::GetReplicated(void) const
{
return m_Replicated;
}
+/**
+ * PropertyChangedHandler
+ *
+ * Handles changed properties by propagating them to the hive
+ * and collection this object is contained in.
+ *
+ * @param dpcea The event arguments.
+ * @returns 0.
+ */
int ConfigObject::PropertyChangedHandler(const PropertyChangedEventArgs& dpcea)
{
ConfigHive::Ptr hive = m_Hive.lock();
#include <map>
#include <list>
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
#ifdef HAVE_GCC_ABI_DEMANGLE
# include <cxxabi.h>
#endif /* HAVE_GCC_ABI_DEMANGLE */
#include "tcpsocket.h"
#include "tcpclient.h"
#include "tcpserver.h"
+#include "tlsclient.h"
#include "configobject.h"
#include "configcollection.h"
#include "confighive.h"
}
};
-typedef function<Object::Ptr ()> factory_function;
-
-/**
- * factory<T>
- *
- * Returns a new object of type T.
- */
-template<class T>
-Object::Ptr factory(void)
-{
- return make_shared<T>();
-}
-
}
#endif /* OBJECT_H */
Socket::~Socket(void)
{
- Close(true);
+ CloseInternal(true);
}
void Socket::Start(void)
void Socket::Close(void)
{
- Close(false);
+ CloseInternal(false);
}
-void Socket::Close(bool from_dtor)
+void Socket::CloseInternal(bool from_dtor)
{
if (m_FD != INVALID_SOCKET) {
closesocket(m_FD);
Socket(void);
void HandleSocketError(void);
- void Close(bool from_dtor);
+ virtual void CloseInternal(bool from_dtor);
public:
typedef shared_ptr<Socket> Ptr;
using namespace icinga;
-TCPClient::TCPClient(void)
+TCPClient::TCPClient(TCPClientRole role)
{
+ m_Role = role;
+
m_SendQueue = make_shared<FIFO>();
m_RecvQueue = make_shared<FIFO>();
m_PeerPort = 0;
}
+TCPClientRole TCPClient::GetRole(void) const
+{
+ return m_Role;
+}
+
void TCPClient::Start(void)
{
TCPSocket::Start();
HandleSocketError();
}
+ m_Role = RoleOutbound;
m_PeerHost = hostname;
m_PeerPort = port;
}
{
return (m_SendQueue->GetSize() > 0);
}
+
+TCPClient::Ptr icinga::TCPClientFactory(TCPClientRole role)
+{
+ return make_shared<TCPClient>(role);
+}
namespace icinga
{
+enum I2_BASE_API TCPClientRole
+{
+ RoleInbound,
+ RoleOutbound
+};
+
class I2_BASE_API TCPClient : public TCPSocket
{
private:
+ TCPClientRole m_Role;
+
string m_PeerHost;
int m_PeerPort;
FIFO::Ptr m_SendQueue;
FIFO::Ptr m_RecvQueue;
- int ReadableEventHandler(const EventArgs& ea);
- int WritableEventHandler(const EventArgs& ea);
+ virtual int ReadableEventHandler(const EventArgs& ea);
+ virtual int WritableEventHandler(const EventArgs& ea);
public:
typedef shared_ptr<TCPClient> Ptr;
typedef weak_ptr<TCPClient> WeakPtr;
- TCPClient(void);
+ TCPClient(TCPClientRole role);
+
+ TCPClientRole GetRole(void) const;
virtual void Start(void);
Event<EventArgs> OnDataAvailable;
};
+TCPClient::Ptr TCPClientFactory(TCPClientRole role);
+
}
#endif /* TCPCLIENT_H */
TCPServer::TCPServer(void)
{
- m_ClientFactory = factory<TCPClient>;
+ m_ClientFactory = bind(&TCPClientFactory, RoleInbound);
}
-void TCPServer::SetClientFactory(factory_function clientFactory)
+void TCPServer::SetClientFactory(function<TCPClient::Ptr()> clientFactory)
{
m_ClientFactory = clientFactory;
}
-factory_function TCPServer::GetFactoryFunction(void)
+function<TCPClient::Ptr()> TCPServer::GetFactoryFunction(void) const
{
return m_ClientFactory;
}
private:
int ReadableEventHandler(const EventArgs& ea);
- factory_function m_ClientFactory;
+ function<TCPClient::Ptr()> m_ClientFactory;
public:
typedef shared_ptr<TCPServer> Ptr;
TCPServer(void);
- void SetClientFactory(factory_function function);
- factory_function GetFactoryFunction(void);
+ void SetClientFactory(function<TCPClient::Ptr()> function);
+ function<TCPClient::Ptr()> GetFactoryFunction(void) const;
virtual void Start();
--- /dev/null
+#include "i2-base.h"
+
+using namespace icinga;
+
+TLSClient::TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext) : TCPClient(role)
+{
+ m_SSLContext = sslContext;
+}
+
+shared_ptr<X509> TLSClient::GetClientCertificate(void) const
+{
+ return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), X509_free);
+}
+
+shared_ptr<X509> TLSClient::GetPeerCertificate(void) const
+{
+ return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
+}
+
+void TLSClient::Start(void)
+{
+ TCPClient::Start();
+
+ m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free);
+
+ if (!m_SSL)
+ ; /* TODO: deal with error */
+
+ BIO *bio = BIO_new_socket(GetFD(), 0);
+ SSL_set_bio(m_SSL.get(), bio, bio);
+
+ if (GetRole() == RoleInbound)
+ SSL_set_accept_state(m_SSL.get());
+ else
+ SSL_set_connect_state(m_SSL.get());
+}
+
+int TLSClient::ReadableEventHandler(const EventArgs& ea)
+{
+ int rc;
+
+ size_t bufferSize = FIFO::BlockSize / 2;
+ char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize);
+ rc = SSL_read(m_SSL.get(), buffer, bufferSize);
+
+ if (rc <= 0) {
+ switch (SSL_get_error(m_SSL.get(), rc)) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return 0;
+ case SSL_ERROR_ZERO_RETURN:
+ Close();
+
+ return 0;
+ default:
+ /* TODO: deal with error */
+
+ return 0;
+ }
+ }
+
+ GetRecvQueue()->Write(NULL, rc);
+
+ EventArgs dea;
+ dea.Source = shared_from_this();
+ OnDataAvailable(dea);
+
+ return 0;
+}
+
+int TLSClient::WritableEventHandler(const EventArgs& ea)
+{
+ int rc;
+
+ rc = SSL_write(m_SSL.get(), (const char *)GetSendQueue()->GetReadBuffer(), GetSendQueue()->GetSize());
+
+ if (rc <= 0) {
+ switch (SSL_get_error(m_SSL.get(), rc)) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ return 0;
+ case SSL_ERROR_ZERO_RETURN:
+ Close();
+
+ return 0;
+ default:
+ /* TODO: deal with error */
+
+ return 0;
+ }
+ }
+
+ GetSendQueue()->Read(NULL, rc);
+
+ return 0;
+}
+
+bool TLSClient::WantsToWrite(void) const
+{
+ if (SSL_want_write(m_SSL.get()))
+ return true;
+
+ if (SSL_state(m_SSL.get()) != SSL_ST_OK)
+ return false;
+
+ return TCPClient::WantsToWrite();
+}
+
+void TLSClient::CloseInternal(bool from_dtor)
+{
+ SSL_shutdown(m_SSL.get());
+
+ TCPClient::CloseInternal(from_dtor);
+}
+
+TCPClient::Ptr icinga::TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
+{
+ return make_shared<TLSClient>(role, sslContext);
+}
--- /dev/null
+#ifndef TLSCLIENT_H
+#define TLSCLIENT_H
+
+namespace icinga
+{
+
+struct I2_BASE_API VerifyCertificateEventArgs : public EventArgs
+{
+ bool ValidCertificate;
+ X509_STORE_CTX *Context;
+};
+
+class I2_BASE_API TLSClient : public TCPClient
+{
+private:
+ shared_ptr<SSL_CTX> m_SSLContext;
+ shared_ptr<SSL> m_SSL;
+
+ virtual int ReadableEventHandler(const EventArgs& ea);
+ virtual int WritableEventHandler(const EventArgs& ea);
+
+ virtual void CloseInternal(bool from_dtor);
+
+public:
+ TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
+
+ shared_ptr<X509> GetClientCertificate(void) const;
+ shared_ptr<X509> GetPeerCertificate(void) const;
+
+ virtual void Start(void);
+
+ virtual bool WantsToWrite(void) const;
+
+ Event<VerifyCertificateEventArgs> OnVerifyCertificate;
+};
+
+TCPClient::Ptr TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
+
+}
+
+#endif /* TLSCLIENT_H */
using namespace icinga;
+bool I2_EXPORT Utility::m_SSLInitialized = false;
+
/**
* Daemonize
*
throw PosixException("setsid failed", errno);
#endif
}
+
+void Utility::InitializeOpenSSL(void)
+{
+ if (!m_SSLInitialized) {
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ m_SSLInitialized = true;
+ }
+}
+
+shared_ptr<SSL_CTX> Utility::MakeSSLContext(string pubkey, string privkey, string cakey)
+{
+ InitializeOpenSSL();
+
+ SSL_METHOD *sslMethod = (SSL_METHOD *)TLSv1_method();
+
+ shared_ptr<SSL_CTX> sslContext = shared_ptr<SSL_CTX>(SSL_CTX_new(sslMethod), SSL_CTX_free);
+
+ SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.c_str()))
+ throw InvalidArgumentException("Could not load public X509 key file.");
+
+ if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.c_str(), SSL_FILETYPE_PEM))
+ throw InvalidArgumentException("Could not load private X509 key file.");
+
+ if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.c_str(), NULL))
+ throw InvalidArgumentException("Could not load public CA key file.");
+
+ return sslContext;
+}
class I2_BASE_API Utility
{
private:
+ static bool m_SSLInitialized;
+
Utility(void);
+ static void InitializeOpenSSL(void);
+
public:
/**
* GetTypeName
}
static void Daemonize(void);
+
+ static shared_ptr<SSL_CTX> MakeSSLContext(string pubkey, string privkey, string cakey);
};
}
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICnjCCAgegAwIBAgIJAOP3gULX9+xgMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
+BAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMRIwEAYDVQQHDAlOdXJlbWJlcmcxFTAT
+BgNVBAoMDE5FVFdBWVMgR21iSDEcMBoGA1UEAwwTSWNpbmdhIFNuYWtlIE9pbCBD
+QTAeFw0xMjA0MjQxMTQyMzFaFw0yMjA0MjIxMTQyMzFaMGgxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIDAdCYXZhcmlhMRIwEAYDVQQHDAlOdXJlbWJlcmcxFTATBgNVBAoM
+DE5FVFdBWVMgR21iSDEcMBoGA1UEAwwTSWNpbmdhIFNuYWtlIE9pbCBDQTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyxlEqY9AcY0YwpMIsirzy/6o9M29LRa4
+ziHURLugpyTKugtAkS5c2Gyt9lf7gdZBcVZ8KD6cszanQqKlZrl0h74E/S13tDqM
+rhR4DHeZssstn5LNK57WYx/vw84bmd6Yq6SeP4geq0JfO+y3Ruu+eePtQSOSzS9F
+wGpKyAHo4AcCAwEAAaNQME4wHQYDVR0OBBYEFNVJHVPJNwqEcG51lpqZJWVPaysF
+MB8GA1UdIwQYMBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADgYEAA1CMZgzQuQAslZ/i6OpFmRzuT/0KAfd6s8n6rf+6
+xRvbgLlop8b8XfhhC/IwwoHU0i86o3vV3ZJjEVcdwTDEwpnyCfhFjhXzNZFqL8Ak
+Olqy5HFd/+xysTLbdmhHtBIdOeUK1qz/u9I14A71XWiknjcxHya2Ghxg4yIZVdKh
+oTQ=
+-----END CERTIFICATE-----
\ No newline at end of file
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMsZRKmPQHGNGMKT
+CLIq88v+qPTNvS0WuM4h1ES7oKckyroLQJEuXNhsrfZX+4HWQXFWfCg+nLM2p0Ki
+pWa5dIe+BP0td7Q6jK4UeAx3mbLLLZ+SzSue1mMf78POG5nemKuknj+IHqtCXzvs
+t0brvnnj7UEjks0vRcBqSsgB6OAHAgMBAAECgYBg4Ku06cUGpRQjc/lY604hh1bW
+dvD++fCrOs3C/3DRaaZd+hIRbnkRLz4H3M32j9nlkyhkFgGvJqnACk81Yc8oOu86
+Pm7bOdEj8v31qq943NCps5tdKHepXM0Z6A8GjaR2ias39NKxVDacBoFzSDAVArTL
+p6dyqLjsW5Y3INeHmQJBAPB6w9iqa31GLXMEMeP5LA4+2p3aHPQ25ptMCUcp/Vc6
+40GOSIlLb8rfE+q1ZacChv94jSNLybR+U9++8DLIxnMCQQDYNORSo57mVSebDr7e
+Gx8BDbyC+yAgiAi+qfJRekQ0I+R1SxfkCIBSWNrQ944isn0eRcr7+BWVl/WOrVSk
+vccdAkBEwbURU9ib3t7Lzd0941ZXVF1JWL2CjdftexYEBNtsf2fOrJHMv4bdKF8X
+cnn4AF782EjyWI75Tk1I4dzniERFAkBKZ9lzvy9+ISwiJq71DOxclnebtATYbThl
+NWNZOvSh5QBIhXFRXsOak02qwKc/taFte6Nhl30GIGe3lFse3tjZAkBguOZFeSOO
+hIAxMD+QpDUHZRYEjhDtPn3oAkLgBNUdeajffLdt4SmRa26t4QnSAE8kkbadIm6A
+z52CJc8G2ALA
+-----END PRIVATE KEY-----
\ No newline at end of file
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICtzCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJERTEQ
+MA4GA1UECAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxO
+RVRXQVlTIEdtYkgxHDAaBgNVBAMME0ljaW5nYSBTbmFrZSBPaWwgQ0EwHhcNMTIw
+NDI0MTE0NzQ2WhcNMTMwNDI0MTE0NzQ2WjBeMQswCQYDVQQGEwJERTEQMA4GA1UE
+CAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxORVRXQVlT
+IEdtYkgxEjAQBgNVBAMMCWljaW5nYS1jMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAysHrzHs9WfQR4cEUx2hFZQmbM+Ssi5L63yqnzxEvVQ3GlM+uIceK1Kvx
+9EexoUDLhxJOaUmigc6Pcs2mAjcpEwObnzW4pLuMKa7ngGLrnUpmmDXdGoxkCbi7
+CP3s5yC7ZZ6bDiPMhRi/TRvY6+uQf+yew5daA3p87jocgRjhRicCAwEAAaN7MHkw
+CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFPzsYbQZdbq+pcFJWoenWREW6WhMMB8GA1UdIwQY
+MBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMA0GCSqGSIb3DQEBBQUAA4GBAMLP1GJf
+0hFdrEpGq+NvxTVx7wD30enAot5x2HLx4HuFohQJz/VZ45v+srrA+HEXbBFXPOd4
+nB2XtcDDidFKTt5E03HBwDGGZvnB3f1KXYi7B50imKrwVVzgp5nGBM4hSzWGovEX
+EYofmhk0fQg9qiKQrjwNib/4/b0srwEswfdj
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMrB68x7PVn0EeHB
+FMdoRWUJmzPkrIuS+t8qp88RL1UNxpTPriHHitSr8fRHsaFAy4cSTmlJooHOj3LN
+pgI3KRMDm581uKS7jCmu54Bi651KZpg13RqMZAm4uwj97Ocgu2Wemw4jzIUYv00b
+2OvrkH/snsOXWgN6fO46HIEY4UYnAgMBAAECgYBj/1QOG1HcxXT0REe9OP3QoPY8
+l7FJfQnheqYch7syVYL07aBR5Jnh3ZONCLbgcpZuXWbyonBVWMyCsE4Jla7ZYnBB
+plZPMYmzGxEbTM5Bu+PZ0M1NLvdLCRq24IVwTZwBBZ3sr7rVSnAYi2Li0SWQEaCN
+P+PbZP1P9i9WiI+VIQJBAPYBfVWNk3gY1V0YuuH9fmYRBg5/B1qy8bYS9FLVIq2z
+5r7eI1EypcVtyTx6yMmLuWj4mpNOKv5sxQsHalzRo18CQQDS/qPoDqMkDB9r9XeZ
+qS2XQdX6YxzGisqL8vWcZ/Y6YX81qm3Lpp2wEexUXvWXRI5RdguctZFKTVyG/Mic
+C9o5AkAEtvKX+SaiXpd4OUkbm6gYfKsJDBYv/s3zF1nnXH5VpeT+M3Op0raqmfgJ
+WLEQa8UZ5enQeOcKCTudgn7fWIUxAkEAmXWfXP6YZXVzvR+xt08225aEvTItEbKM
+krFJNlLe4aNb1Hp6lO5ALnk6vDq8wSKZqGIFHBtq6vHNZFiix+xO8QJAIZ3pB/Bz
+Il8NjZMg8t/1sJdn32Xe9D0lZRtZTKC8zF/78NDFEo9qqE4Sr1CUfqlx18HXOxCO
+Vg4lv6+jUj+LmA==
+-----END PRIVATE KEY-----
\ No newline at end of file
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICtzCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJERTEQ
+MA4GA1UECAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxO
+RVRXQVlTIEdtYkgxHDAaBgNVBAMME0ljaW5nYSBTbmFrZSBPaWwgQ0EwHhcNMTIw
+NDI0MTE0NzU1WhcNMTMwNDI0MTE0NzU1WjBeMQswCQYDVQQGEwJERTEQMA4GA1UE
+CAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxORVRXQVlT
+IEdtYkgxEjAQBgNVBAMMCWljaW5nYS1jMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEArOcVui1AWojbPuK/7We9uwIBLaOLfBxQRI3+k6PzzjdtaXT4ijT/DSav
+Q5U4wGOLYh0yuSyqS88QX/DsqDGLXnSVs8mT37bioMOw2XinqaNQ6xK4vyi0FYxS
+ewI6YOkYi7135NEaSUgd82hk4wFtiIb67T7hkHRc7Aui6FmT/SkCAwEAAaN7MHkw
+CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFGvpolD5na6L70kNFO1tYGYIwDhqMB8GA1UdIwQY
+MBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMA0GCSqGSIb3DQEBBQUAA4GBAIhhjKWw
+5JKirNidgG9PuD8x47VsRTkESLlq/pS7KjkE1nWCG9JpR5oVSzx2WXomiaAZ4q2C
+WS1z4HD9HF4NbhY+xVBi0Fj/kotuXCCweRo5EVp7Q4fabm1maJemFwMTHGhBLu7a
+v4dquYyOk9Dhkwcjajyn+KWceCoUTdI3LB2t
+-----END CERTIFICATE-----
\ No newline at end of file
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKznFbotQFqI2z7i
+v+1nvbsCAS2ji3wcUESN/pOj8843bWl0+Io0/w0mr0OVOMBji2IdMrksqkvPEF/w
+7Kgxi150lbPJk9+24qDDsNl4p6mjUOsSuL8otBWMUnsCOmDpGIu9d+TRGklIHfNo
+ZOMBbYiG+u0+4ZB0XOwLouhZk/0pAgMBAAECgYEAkbEavslYm7EMRX4dyXcMCaNT
+yNgxNcBJ5qpbpJ6XVuGfoSf+Mb8cV0GMl38K1hpLHb6Kujwntz9ghedmEwfEbcw0
+TkSaNz1+7omM+485S2YvXJyR1kO8eEKONVlGuxgO/ItiR+e1J6wMnY5JhctgRH6W
+aOqy+5Ua1ATIdiOYrI0CQQDku3CNDOipwDmguBIrlxa+6NsATJRjqFmHqWdu2pYh
+KRl3Sypn+LfhdFRbo3licU5a1OqydGmVpRTpQPJO7MoHAkEAwYPQIGZd/60O2LWV
+M5eLnwKrrQSfrQ/Lngz0Qko4Yo913Ef2PC2QQ6p9cOt3vMPZDK5znlzQbBCa6cAH
+tBvzTwJAT+uaaP5wsRdkS17lomt5XB1aoCEh3Cxvk/JCHL6tpEqLBl6yI4AJJ/KQ
+ozBccmQqv5wToWUBm3MB+nph7+fWswJAMKcQQ6UZCvganHeCzJbUXqUQPo7ECoHH
+IrSFEMmSRY1mB3z8NoMKG0kZArPgxc/DmUGfBfi12gWOvSgvh6PjVwJBALKECoe5
+nmxhHTFbs4+UCFTzp6BGtSBdr6to0ID7ykZWT6kBX/BHUnoJUEpDtNLXzbek/KeI
+ymg0LgRkHoWNpLY=
+-----END PRIVATE KEY-----
\ No newline at end of file
using namespace icinga;
+EndpointManager::EndpointManager(shared_ptr<SSL_CTX> sslContext)
+{
+ m_SSLContext = sslContext;
+}
+
void EndpointManager::SetIdentity(string identity)
{
m_Identity = identity;
void EndpointManager::AddListener(unsigned short port)
{
- JsonRpcServer::Ptr server = make_shared<JsonRpcServer>();
+ JsonRpcServer::Ptr server = make_shared<JsonRpcServer>(m_SSLContext);
RegisterServer(server);
server->MakeSocket();
void EndpointManager::AddConnection(string host, unsigned short port)
{
JsonRpcEndpoint::Ptr endpoint = make_shared<JsonRpcEndpoint>();
- endpoint->Connect(host, port);
+ endpoint->Connect(host, port, m_SSLContext);
RegisterEndpoint(endpoint);
}
class I2_ICINGA_API EndpointManager : public Object
{
+ shared_ptr<SSL_CTX> m_SSLContext;
list<JsonRpcServer::Ptr> m_Servers;
list<Endpoint::Ptr> m_Endpoints;
string m_Identity;
typedef shared_ptr<EndpointManager> Ptr;
typedef weak_ptr<EndpointManager> WeakPtr;
+ EndpointManager(shared_ptr<SSL_CTX> sslContext);
+
void SetIdentity(string identity);
string GetIdentity(void) const;
using namespace icinga;
-IcingaApplication::IcingaApplication(void)
-{
- m_EndpointManager = make_shared<EndpointManager>();
-}
-
int IcingaApplication::Main(const vector<string>& args)
{
#ifdef _WIN32
return EXIT_FAILURE;
}
+ shared_ptr<SSL_CTX> sslContext = Utility::MakeSSLContext("icinga-c1.crt", "icinga-c1.key", "ca.crt");
+
+ m_EndpointManager = make_shared<EndpointManager>(sslContext);
+
string componentDirectory = GetExeDirectory() + "/../lib/icinga";
AddComponentSearchDir(componentDirectory);
typedef shared_ptr<IcingaApplication> Ptr;
typedef weak_ptr<IcingaApplication> WeakPtr;
- IcingaApplication(void);
-
int Main(const vector<string>& args);
void PrintUsage(const string& programPath);
return false;
}
-void JsonRpcEndpoint::Connect(string host, unsigned short port)
+void JsonRpcEndpoint::Connect(string host, unsigned short port, shared_ptr<SSL_CTX> sslContext)
{
char portStr[20];
sprintf(portStr, "%d", port);
SetAddress("jsonrpc-tcp://" + host + ":" + portStr);
- JsonRpcClient::Ptr client = make_shared<JsonRpcClient>();
+ JsonRpcClient::Ptr client = make_shared<JsonRpcClient>(RoleOutbound, sslContext);
client->MakeSocket();
client->Connect(host, port);
client->Start();
class I2_ICINGA_API JsonRpcEndpoint : public Endpoint
{
private:
+ shared_ptr<SSL_CTX> m_SSLContext;
string m_Address;
JsonRpcClient::Ptr m_Client;
map<string, Endpoint::Ptr> m_PendingCalls;
typedef shared_ptr<JsonRpcEndpoint> Ptr;
typedef weak_ptr<JsonRpcEndpoint> WeakPtr;
- void Connect(string host, unsigned short port);
+ void Connect(string host, unsigned short port,
+ shared_ptr<SSL_CTX> sslContext);
JsonRpcClient::Ptr GetClient(void);
void SetClient(JsonRpcClient::Ptr client);
using namespace icinga;
+JsonRpcClient::JsonRpcClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
+ : TLSClient(role, sslContext) { }
+
void JsonRpcClient::Start(void)
{
- TCPClient::Start();
+ TLSClient::Start();
OnDataAvailable += bind_weak(&JsonRpcClient::DataAvailableHandler, shared_from_this());
}
return 0;
}
+
+TCPClient::Ptr icinga::JsonRpcClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
+{
+ return make_shared<JsonRpcClient>(role, sslContext);
+}
icinga::Message Message;
};
-class I2_JSONRPC_API JsonRpcClient : public TCPClient
+class I2_JSONRPC_API JsonRpcClient : public TLSClient
{
private:
int DataAvailableHandler(const EventArgs& ea);
typedef shared_ptr<JsonRpcClient> Ptr;
typedef weak_ptr<JsonRpcClient> WeakPtr;
+ JsonRpcClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
+
void SendMessage(const Message& message);
virtual void Start(void);
Event<NewMessageEventArgs> OnNewMessage;
};
+TCPClient::Ptr JsonRpcClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
+
}
#endif /* JSONRPCCLIENT_H */
using namespace icinga;
-JsonRpcServer::JsonRpcServer(void)
+JsonRpcServer::JsonRpcServer(shared_ptr<SSL_CTX> sslContext)
{
- SetClientFactory(factory<JsonRpcClient>);
+ SetClientFactory(bind(&JsonRpcClientFactory, RoleInbound, sslContext));
}
typedef shared_ptr<JsonRpcServer> Ptr;
typedef weak_ptr<JsonRpcServer> WeakPtr;
- JsonRpcServer(void);
+ JsonRpcServer(shared_ptr<SSL_CTX> sslContext);
};
}