<commit_before>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "context.h"
#include "logging.h"
#include "sconnect.h"
#include "contextgroup.h"
#include "listeners.h"

using namespace ContextProvider;

/*!
    \page CApi C Api

    \brief The libcontextprovider library offers a simple plain-C API to be used
    from any C program.

    \section Usage

    \code
    context_provider_init(DBUS_BUS_SESSION, "org.test.provider");

    context_provider_install_key("Battery.OnBattery", 0, NULL, NULL);
    context_provider_install_key("Battery.ChargePercentage", 0, NULL, NULL);

    context_provider_set_boolean("Battery.OnBattery", 1);
    context_provider_set_integer("Battery.ChargePercentage", 55);
    \endcode

    The above code snippet starts a service at "org.test.provider" with two
    keys ("Battery.OnBattery", "Battery.ChargePercentage") and sets their
    respective values.

    \section Callbacks

    The context_provider_install_key function and context_provider_install_group function
    take arguments specyfying the callback function. The callback is executed when the
    subscription status changes for the key or the key group (first subscriber
    appears or last subscriber goes away). Basing on this info the provider can
    manage it's resources. It's okay also to use the callback function to actually
    set the value.

    \code
    void callback_function_example(int subscribed, void* user_data)
    {
        if (subscribed) {
            // First subscriber appeared.
            // Start ie. pooling the data.
        } else {
            // Last subscribed disappeared.
            // Stop  pooling data, release resources.
        }
    }
    \endcode
*/

QStringList *serviceKeyList = NULL;
QString *serviceBusName = NULL;
QDBusConnection::BusType serviceBusType;
QList<Listener*> *listeners = NULL;

/// Stops and restarts the service with proper key. Not part of the
/// public API.
static int reinitialize_service()
{
    if (serviceKeyList->length() > 0)
        Context::stopService(*serviceBusName);

    return Context::initService(serviceBusType, *serviceBusName, *serviceKeyList);
}

/// Initializes and starts the service with a given \a bus_type and a \a bus_name.
/// Te \a bus_type can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM. This function can be
/// called only once till a matching context_provider_stop is called.
int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    if (serviceBusName != NULL) {
    contextCritical() << "Service already initialize. You can only initialize one service with C API";
        return 0;
    }

    serviceBusType = (bus_type == DBUS_BUS_SESSION) ?
                      QDBusConnection::SessionBus   :
                      QDBusConnection::SystemBus;
    serviceBusName = new QString(bus_name);
    serviceKeyList = new QStringList();
    listeners = new QList<Listener*>;

    return reinitialize_service();
}

/// Stops the currently started service with context_provider_init. After calling
/// this function a new service can be started by calling context_provider_init.
void context_provider_stop (void)
{
    contextDebug() << "Stopping service";

    if (serviceBusName) {
        Context::stopService(*serviceBusName);
    }

    // Delete all listeners
    if (listeners) {
        foreach (Listener *listener, *listeners)
            delete listener;
    }

    delete serviceBusName; serviceBusName = NULL;
    delete serviceKeyList; serviceKeyList = NULL;
    delete listeners; listeners = NULL;
}

/// Installs (adds) a \a key to be provided by the service. The callback function \a
/// subscription_changed_cb will be called with the passed user data \a subscription_changed_cb_target
/// when the status of the subscription changes -- when the first subscriber appears or the
/// last subscriber disappears.
void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    if (serviceKeyList->contains(QString(key))) {
        contextCritical() << "Key:" << key << "is already installed";
        return;
    }

    serviceKeyList->append(key);
    reinitialize_service();

    listeners->append(new ContextListener(key, clear_values_on_subscribe, subscription_changed_cb, subscription_changed_cb_target));
}

/// Installs (adds) a \a key_group to be provided by the service. The \a key_group is a NULL-terminated
/// array containing the keys. The callback function \a subscription_changed_cb will be called with the
/// passed user data \a subscription_changed_cb_target when the status of the subscription changes --
/// when the first subscriber appears or the last subscriber disappears.
void context_provider_install_group (const char** key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        if (serviceKeyList->contains(key)) {
            contextCritical() << "Key:" << key << "is already installed";
            return;
        }

        keys << key;
        serviceKeyList->append(key);
        i++;
    }

    reinitialize_service();
    listeners->append(new ContextGroupListener(keys, clear_values_on_subscribe, subscription_changed_cb, subscription_changed_cb_target));
}

/// Sets the \a key to a specified integer \a value.
void context_provider_set_integer (const char* key, int value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified double \a value.
void context_provider_set_double (const char* key, double value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified boolean \a value.
void context_provider_set_boolean (const char* key, int value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified string \a value.
void context_provider_set_string (const char* key, const char* value)
{
    Context(key).set(value);
}

/// Sets the \a key to NULL. In other words - unsets the key.
void context_provider_set_null (const char* key)
{
    Context(key).unset();
}

<commit_msg>Documentation for clear values on subscribe.<commit_after>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "context.h"
#include "logging.h"
#include "sconnect.h"
#include "contextgroup.h"
#include "listeners.h"

using namespace ContextProvider;

/*!
    \page CApi C Api

    \brief The libcontextprovider library offers a simple plain-C API to be used
    from any C program.

    \section Usage

    \code
    context_provider_init(DBUS_BUS_SESSION, "org.test.provider");

    context_provider_install_key("Battery.OnBattery", 0, NULL, NULL);
    context_provider_install_key("Battery.ChargePercentage", 0, NULL, NULL);

    context_provider_set_boolean("Battery.OnBattery", 1);
    context_provider_set_integer("Battery.ChargePercentage", 55);
    \endcode

    The above code snippet starts a service at "org.test.provider" with two
    keys ("Battery.OnBattery", "Battery.ChargePercentage") and sets their
    respective values.

    \section Callbacks

    The context_provider_install_key function and context_provider_install_group function
    take arguments specyfying the callback function. The callback is executed when the
    subscription status changes for the key or the key group (first subscriber
    appears or last subscriber goes away). Basing on this info the provider can
    manage it's resources. It's okay also to use the callback function to actually
    set the value.

    \code
    void callback_function_example(int subscribed, void* user_data)
    {
        if (subscribed) {
            // First subscriber appeared.
            // Start ie. pooling the data.
        } else {
            // Last subscribed disappeared.
            // Stop  pooling data, release resources.
        }
    }
    \endcode
*/

QStringList *serviceKeyList = NULL;
QString *serviceBusName = NULL;
QDBusConnection::BusType serviceBusType;
QList<Listener*> *listeners = NULL;

/// Stops and restarts the service with proper key. Not part of the
/// public API.
static int reinitialize_service()
{
    if (serviceKeyList->length() > 0)
        Context::stopService(*serviceBusName);

    return Context::initService(serviceBusType, *serviceBusName, *serviceKeyList);
}

/// Initializes and starts the service with a given \a bus_type and a \a bus_name.
/// Te \a bus_type can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM. This function can be
/// called only once till a matching context_provider_stop is called.
int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    if (serviceBusName != NULL) {
    contextCritical() << "Service already initialize. You can only initialize one service with C API";
        return 0;
    }

    serviceBusType = (bus_type == DBUS_BUS_SESSION) ?
                      QDBusConnection::SessionBus   :
                      QDBusConnection::SystemBus;
    serviceBusName = new QString(bus_name);
    serviceKeyList = new QStringList();
    listeners = new QList<Listener*>;

    return reinitialize_service();
}

/// Stops the currently started service with context_provider_init. After calling
/// this function a new service can be started by calling context_provider_init.
void context_provider_stop (void)
{
    contextDebug() << "Stopping service";

    if (serviceBusName) {
        Context::stopService(*serviceBusName);
    }

    // Delete all listeners
    if (listeners) {
        foreach (Listener *listener, *listeners)
            delete listener;
    }

    delete serviceBusName; serviceBusName = NULL;
    delete serviceKeyList; serviceKeyList = NULL;
    delete listeners; listeners = NULL;
}

/// Installs (adds) a \a key to be provided by the service. The callback function \a
/// subscription_changed_cb will be called with the passed user data \a subscription_changed_cb_target
/// when the status of the subscription changes -- when the first subscriber appears or the
/// last subscriber disappears. The \a clear_values_on_subscribe when enabled will automatically
/// clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    if (serviceKeyList->contains(QString(key))) {
        contextCritical() << "Key:" << key << "is already installed";
        return;
    }

    serviceKeyList->append(key);
    reinitialize_service();

    listeners->append(new ContextListener(key, clear_values_on_subscribe, subscription_changed_cb, subscription_changed_cb_target));
}

/// Installs (adds) a \a key_group to be provided by the service. The \a key_group is a NULL-terminated
/// array containing the keys. The callback function \a subscription_changed_cb will be called with the
/// passed user data \a subscription_changed_cb_target when the status of the subscription changes --
/// when the first subscriber appears or the last subscriber disappears. The \a clear_values_on_subscribe
/// when enabled will automatically clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_group (const char** key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        if (serviceKeyList->contains(key)) {
            contextCritical() << "Key:" << key << "is already installed";
            return;
        }

        keys << key;
        serviceKeyList->append(key);
        i++;
    }

    reinitialize_service();
    listeners->append(new ContextGroupListener(keys, clear_values_on_subscribe, subscription_changed_cb, subscription_changed_cb_target));
}

/// Sets the \a key to a specified integer \a value.
void context_provider_set_integer (const char* key, int value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified double \a value.
void context_provider_set_double (const char* key, double value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified boolean \a value.
void context_provider_set_boolean (const char* key, int value)
{
    Context(key).set(value);
}

/// Sets the \a key to a specified string \a value.
void context_provider_set_string (const char* key, const char* value)
{
    Context(key).set(value);
}

/// Sets the \a key to NULL. In other words - unsets the key.
void context_provider_set_null (const char* key)
{
    Context(key).unset();
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/socket.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include <boost/shared_ptr.hpp>
#include <stdexcept>

namespace libtorrent
{
	TORRENT_EXPORT bool instantiate_connection(io_service& ios
		, proxy_settings const& ps, socket_type& s
		, void* ssl_context
		, utp_socket_manager* sm
		, bool peer_connection)
	{
		if (sm)
		{
			utp_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<utp_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<utp_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<utp_stream>(ios);
				str = s.get<utp_stream>();
			}
			str->set_impl(sm->new_utp_socket(str));
		}
#if TORRENT_USE_I2P
		else if (ps.type == proxy_settings::i2p_proxy)
		{
			// it doesn't make any sense to try ssl over i2p
			TORRENT_ASSERT(ssl_context == 0);
			s.instantiate<i2p_stream>(ios);
			s.get<i2p_stream>()->set_proxy(ps.hostname, ps.port);
		}
#endif
		else if (ps.type == proxy_settings::none
			|| (peer_connection && !ps.proxy_peer_connections))
		{
			stream_socket* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<stream_socket> >(ios, ssl_context);
				str = &s.get<ssl_stream<stream_socket> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<stream_socket>(ios);
				str = s.get<stream_socket>();
			}
		}
		else if (ps.type == proxy_settings::http
			|| ps.type == proxy_settings::http_pw)
		{
			http_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<http_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<http_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<http_stream>(ios);
				str = s.get<http_stream>();
			}

			str->set_proxy(ps.hostname, ps.port);
			if (ps.type == proxy_settings::http_pw)
				str->set_username(ps.username, ps.password);
		}
		else if (ps.type == proxy_settings::socks5
			|| ps.type == proxy_settings::socks5_pw
			|| ps.type == proxy_settings::socks4)
		{
			socks5_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<socks5_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<socks5_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<socks5_stream>(ios);
				str = s.get<socks5_stream>();
			}
			str->set_proxy(ps.hostname, ps.port);
			if (ps.type == proxy_settings::socks5_pw)
				str->set_username(ps.username, ps.password);
			if (ps.type == proxy_settings::socks4)
				str->set_version(4);
		}
		else
		{
			TORRENT_ASSERT_VAL(false, ps.type);
			return false;
		}
		return true;
	}

}

<commit_msg>remove unused variable<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/socket.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include <boost/shared_ptr.hpp>
#include <stdexcept>

namespace libtorrent
{
	TORRENT_EXPORT bool instantiate_connection(io_service& ios
		, proxy_settings const& ps, socket_type& s
		, void* ssl_context
		, utp_socket_manager* sm
		, bool peer_connection)
	{
		if (sm)
		{
			utp_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<utp_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<utp_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<utp_stream>(ios);
				str = s.get<utp_stream>();
			}
			str->set_impl(sm->new_utp_socket(str));
		}
#if TORRENT_USE_I2P
		else if (ps.type == proxy_settings::i2p_proxy)
		{
			// it doesn't make any sense to try ssl over i2p
			TORRENT_ASSERT(ssl_context == 0);
			s.instantiate<i2p_stream>(ios);
			s.get<i2p_stream>()->set_proxy(ps.hostname, ps.port);
		}
#endif
		else if (ps.type == proxy_settings::none
			|| (peer_connection && !ps.proxy_peer_connections))
		{
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<stream_socket> >(ios, ssl_context);
			}
			else
#endif
			{
				s.instantiate<stream_socket>(ios);
			}
		}
		else if (ps.type == proxy_settings::http
			|| ps.type == proxy_settings::http_pw)
		{
			http_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<http_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<http_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<http_stream>(ios);
				str = s.get<http_stream>();
			}

			str->set_proxy(ps.hostname, ps.port);
			if (ps.type == proxy_settings::http_pw)
				str->set_username(ps.username, ps.password);
		}
		else if (ps.type == proxy_settings::socks5
			|| ps.type == proxy_settings::socks5_pw
			|| ps.type == proxy_settings::socks4)
		{
			socks5_stream* str;
#ifdef TORRENT_USE_OPENSSL
			if (ssl_context)
			{
				s.instantiate<ssl_stream<socks5_stream> >(ios, ssl_context);
				str = &s.get<ssl_stream<socks5_stream> >()->next_layer();
			}
			else
#endif
			{
				s.instantiate<socks5_stream>(ios);
				str = s.get<socks5_stream>();
			}
			str->set_proxy(ps.hostname, ps.port);
			if (ps.type == proxy_settings::socks5_pw)
				str->set_username(ps.username, ps.password);
			if (ps.type == proxy_settings::socks4)
				str->set_version(4);
		}
		else
		{
			TORRENT_ASSERT_VAL(false, ps.type);
			return false;
		}
		return true;
	}

}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "context.h"
#include "logging.h"
#include "sconnect.h"
#include "contextgroup.h"
#include "listeners.h"

using namespace ContextProvider;

QStringList *serviceKeyList = NULL;
QString *serviceBusName = NULL;
QDBusConnection::BusType serviceBusType;
QList<Listener*> *listeners = NULL;

static int reinitialize_service()
{
    if (serviceKeyList->length() > 0)
        Context::stopService(*serviceBusName);

    return Context::initService(serviceBusType, *serviceBusName, *serviceKeyList);
}

int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    if (serviceBusName != NULL) {
    contextCritical() << "Service already initialize. You can only initialize one service with C API";
        return 0;
    }

    serviceBusType = (bus_type == DBUS_BUS_SESSION) ?
                      QDBusConnection::SessionBus   :
                      QDBusConnection::SystemBus;
    serviceBusName = new QString(bus_name);
    serviceKeyList = new QStringList();
    listeners = new QList<Listener*>;

    return reinitialize_service();
}

void context_provider_stop (void)
{
    contextDebug() << "Stopping service";

    if (serviceBusName) {
        Context::stopService(*serviceBusName);
    }

    // Delete all listeners
    if (listeners) {
        foreach (Listener *listener, *listeners)
            delete listener;
    }

    delete serviceBusName; serviceBusName = NULL;
    delete serviceKeyList; serviceKeyList = NULL;
    delete listeners; listeners = NULL;
}

void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    if (serviceKeyList->contains(QString(key))) {
        contextCritical() << "Key:" << key << "is already installed";
        return;
    }

    serviceKeyList->append(key);
    reinitialize_service();

    listeners->append(new ContextListener(key, subscription_changed_cb, subscription_changed_cb_target));
}

void
context_provider_install_group  (char** key_group,
                                 int clear_values_on_subscribe,
                                 ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                 void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        if (serviceKeyList->contains(key)) {
            contextCritical() << "Key:" << key << "is already installed";
            return;
        }

        keys << key;
        i++;
    }

    reinitialize_service();
    listeners->append(new ContextGroupListener(keys, subscription_changed_cb, subscription_changed_cb_target));
}

void
context_provider_set_integer (const char* key, int value)
{
    Context(key).set(value);
}

void
context_provider_set_double (const char* key, double value)
{
    Context(key).set(value);
}

void
context_provider_set_boolean (const char* key, int value)
{
    Context(key).set(value);
}

void
context_provider_set_string (const char* key, const char* value)
{
    Context(key).set(value);
}

void
context_provider_set_null (const char* key)
{
    Context(key).unset();
}

<commit_msg>Const here.<commit_after>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "context.h"
#include "logging.h"
#include "sconnect.h"
#include "contextgroup.h"
#include "listeners.h"

using namespace ContextProvider;

QStringList *serviceKeyList = NULL;
QString *serviceBusName = NULL;
QDBusConnection::BusType serviceBusType;
QList<Listener*> *listeners = NULL;

static int reinitialize_service()
{
    if (serviceKeyList->length() > 0)
        Context::stopService(*serviceBusName);

    return Context::initService(serviceBusType, *serviceBusName, *serviceKeyList);
}

int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    if (serviceBusName != NULL) {
    contextCritical() << "Service already initialize. You can only initialize one service with C API";
        return 0;
    }

    serviceBusType = (bus_type == DBUS_BUS_SESSION) ?
                      QDBusConnection::SessionBus   :
                      QDBusConnection::SystemBus;
    serviceBusName = new QString(bus_name);
    serviceKeyList = new QStringList();
    listeners = new QList<Listener*>;

    return reinitialize_service();
}

void context_provider_stop (void)
{
    contextDebug() << "Stopping service";

    if (serviceBusName) {
        Context::stopService(*serviceBusName);
    }

    // Delete all listeners
    if (listeners) {
        foreach (Listener *listener, *listeners)
            delete listener;
    }

    delete serviceBusName; serviceBusName = NULL;
    delete serviceKeyList; serviceKeyList = NULL;
    delete listeners; listeners = NULL;
}

void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    if (serviceKeyList->contains(QString(key))) {
        contextCritical() << "Key:" << key << "is already installed";
        return;
    }

    serviceKeyList->append(key);
    reinitialize_service();

    listeners->append(new ContextListener(key, subscription_changed_cb, subscription_changed_cb_target));
}

void context_provider_install_group (const char** key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    if (! serviceKeyList) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        if (serviceKeyList->contains(key)) {
            contextCritical() << "Key:" << key << "is already installed";
            return;
        }

        keys << key;
        i++;
    }

    reinitialize_service();
    listeners->append(new ContextGroupListener(keys, subscription_changed_cb, subscription_changed_cb_target));
}

void
context_provider_set_integer (const char* key, int value)
{
    Context(key).set(value);
}

void
context_provider_set_double (const char* key, double value)
{
    Context(key).set(value);
}

void
context_provider_set_boolean (const char* key, int value)
{
    Context(key).set(value);
}

void
context_provider_set_string (const char* key, const char* value)
{
    Context(key).set(value);
}

void
context_provider_set_null (const char* key)
{
    Context(key).unset();
}

<|endoftext|>


<commit_before>/*  Sirikata Utilities -- Dynamic Library Loading
 *  DynamicLibrary.cpp
 *
 *  Copyright (c) 2009, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sirikata/core/util/Standard.hh>
#include <sirikata/core/util/DynamicLibrary.hpp>
#include <sirikata/core/util/Paths.hpp>

#include <boost/filesystem.hpp>

#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
#  include <dlfcn.h>
#endif

namespace Sirikata {

static std::vector<String> DL_search_paths;

void DynamicLibrary::Initialize() {
    using namespace boost::filesystem;
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    // On mac, we might be in a .app, specifically at .app/Contents. To load the
    // libs we need, we add .app/Contents/MacOS to the LD_LIBRARY_PATH
    path to_macos_dir = path(Path::Get(Path::DIR_CURRENT)) / path("MacOS");
    if (exists(to_macos_dir) && is_directory(to_macos_dir))
        AddLoadPath(to_macos_dir.string());
#endif

    // On all platforms, allow plugins to load from within the same
    // directory as the executable
    String exe_path = Path::Get(Path::DIR_EXE);
    if (!exe_path.empty())
        AddLoadPath(exe_path);
    // Also, if it differs, add the bundle's path
    String exe_bundle_path = Path::Get(Path::DIR_EXE_BUNDLE);
    if (!exe_bundle_path.empty() && exe_bundle_path != exe_path)
        AddLoadPath(exe_bundle_path);
}

void DynamicLibrary::AddLoadPath(const String& path) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
#define LD_LIBRARY_PATH_STR "LD_LIBRARY_PATH"
    {
        String oldLdLibraryPath = getenv(LD_LIBRARY_PATH_STR)?getenv(LD_LIBRARY_PATH_STR):"";
        String ldLibraryPath = path;
        if (!oldLdLibraryPath.empty())
            ldLibraryPath = ldLibraryPath + ":" + oldLdLibraryPath;
        setenv(LD_LIBRARY_PATH_STR,ldLibraryPath.c_str(),1);
    }
#endif
    // OSX and Ubuntu 10.04 don't seem to like setting DYLD_LIBRARY_PATH dynamically. Instead,
    // we add to the search paths and handle the search ourselves.
    DL_search_paths.push_back(path);
}

DynamicLibrary::DynamicLibrary(const String& path)
 : mPath(path),
   mHandle(NULL)
{
}
static bool unloadLibrary(DL_HANDLE lib) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    bool success = !FreeLibrary(lib);
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    bool success = dlclose(lib)==0;
#endif
    return success;
}
void DynamicLibrary::gc(DL_HANDLE handle) {
    static std::vector<DL_HANDLE> *sHandles=new std::vector<DL_HANDLE>;
    if (handle) {
        if (sHandles==NULL)
            sHandles=new std::vector<DL_HANDLE>;
        sHandles->push_back(handle);
    }else if(sHandles){
        for (std::vector<DL_HANDLE>::iterator i=sHandles->begin();i!=sHandles->end();++i) {
            unloadLibrary(*i);
        }
        delete sHandles;
        sHandles=NULL;
    }
}
DynamicLibrary::~DynamicLibrary() {
    if (mHandle != NULL)
        gc(mHandle);
}

bool DynamicLibrary::load() {
    if (mHandle != NULL)
        return true;

    if (!isValidLibraryFilename())
        return false;

#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    mHandle = LoadLibrary(mPath.c_str());
    if (mHandle == NULL) {
        // Try any registered search paths
        for(uint32 i = 0; mHandle == NULL && i < DL_search_paths.size(); i++) {
            std::string str =(boost::filesystem::path(DL_search_paths[i]) / mPath).string();
            mHandle = LoadLibrary(str.c_str());
        }
    }
    if (mHandle == NULL) {
        DWORD errnum = GetLastError();
        SILOG(plugin,error,"Failed to open library "<<mPath<<": "<<errnum);
    }
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX

// Use RTLD_NOW in debug builds to make it more likely to catch missing symbols
// in simple tests, i.e. just by loading the library, since other tests might
// not get good enough coverage.
#if SIRIKATA_DEBUG
#define SIRIKATA_DLOPEN_FLAGS (RTLD_NOW | RTLD_GLOBAL)
#else
#define SIRIKATA_DLOPEN_FLAGS (RTLD_LAZY | RTLD_GLOBAL)
#endif

    mHandle = dlopen(mPath.c_str(), SIRIKATA_DLOPEN_FLAGS);
    if (mHandle == NULL) {
        // Try any registered search paths
        for(uint32 i = 0; mHandle == NULL && i < DL_search_paths.size(); i++) {
            std::string str = (boost::filesystem::path(DL_search_paths[i]) / mPath).string();
            mHandle = dlopen(
                str.c_str(),
                SIRIKATA_DLOPEN_FLAGS
            );
        }
    }
    if (mHandle == NULL) {
        const char *errorstr = dlerror();
        SILOG(plugin,error,"Failed to open library "<<mPath<<": "<<errorstr);
    }
#endif

    return (mHandle != NULL);
}

bool DynamicLibrary::unload() {
    if (mHandle == NULL)
        return true;
    bool success=unloadLibrary(mHandle);
    mHandle=NULL;
    return success;
}

void* DynamicLibrary::symbol(const String& name) const {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return (void*)GetProcAddress(mHandle, name.c_str());
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return (void*)dlsym(mHandle, name.c_str());
#endif
}

String DynamicLibrary::prefix() {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return "";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    return "lib";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return "lib";
#endif
}

String DynamicLibrary::postfix() {
#if SIRIKATA_DEBUG
    return "_d";
#else
    return "";
#endif
}

String DynamicLibrary::extension() {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return ".dll";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    return ".dylib";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return ".so";
#endif
}

String DynamicLibrary::filename(const String& name) {
    return ( prefix() + name + postfix() + extension() );
}

String DynamicLibrary::filename(const String& path, const String& name) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    const char file_separator = '\\';
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    const char file_separator = '/';
#endif

    String result = path;
    if (result.size() > 0 && result[result.size()-1] != file_separator)
        result += file_separator;
    result += filename(name);

    return result;
}

bool DynamicLibrary::isValidLibraryFilename() const {
    using namespace boost::filesystem;

    String pref = prefix();
    String ext = extension();

    path bfs_path = mPath;
    // FIXME this should be bfs_path.leaf() in 1.35, bfs_path.filename() in
    // 1.37.  Instead, just do this manually.
    String libfilename = bfs_path.empty() ? String() : *--bfs_path.end();

    if (libfilename.substr(0, pref.size()) != pref)
        return false;

    if (libfilename.size() < ext.size() ||
        libfilename.substr(libfilename.size() - ext.size()) != ext )
        return false;

    return true;
}

} // namespace Sirikata
<commit_msg>Make failure to load library a warning and give details about load paths.<commit_after>/*  Sirikata Utilities -- Dynamic Library Loading
 *  DynamicLibrary.cpp
 *
 *  Copyright (c) 2009, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sirikata/core/util/Standard.hh>
#include <sirikata/core/util/DynamicLibrary.hpp>
#include <sirikata/core/util/Paths.hpp>

#include <boost/filesystem.hpp>

#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
#  include <dlfcn.h>
#endif

namespace Sirikata {

static std::vector<String> DL_search_paths;

void DynamicLibrary::Initialize() {
    using namespace boost::filesystem;
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    // On mac, we might be in a .app, specifically at .app/Contents. To load the
    // libs we need, we add .app/Contents/MacOS to the LD_LIBRARY_PATH
    path to_macos_dir = path(Path::Get(Path::DIR_CURRENT)) / path("MacOS");
    if (exists(to_macos_dir) && is_directory(to_macos_dir))
        AddLoadPath(to_macos_dir.string());
#endif

    // On all platforms, allow plugins to load from within the same
    // directory as the executable
    String exe_path = Path::Get(Path::DIR_EXE);
    if (!exe_path.empty())
        AddLoadPath(exe_path);
    // Also, if it differs, add the bundle's path
    String exe_bundle_path = Path::Get(Path::DIR_EXE_BUNDLE);
    if (!exe_bundle_path.empty() && exe_bundle_path != exe_path)
        AddLoadPath(exe_bundle_path);
}

void DynamicLibrary::AddLoadPath(const String& path) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
#define LD_LIBRARY_PATH_STR "LD_LIBRARY_PATH"
    {
        String oldLdLibraryPath = getenv(LD_LIBRARY_PATH_STR)?getenv(LD_LIBRARY_PATH_STR):"";
        String ldLibraryPath = path;
        if (!oldLdLibraryPath.empty())
            ldLibraryPath = ldLibraryPath + ":" + oldLdLibraryPath;
        setenv(LD_LIBRARY_PATH_STR,ldLibraryPath.c_str(),1);
    }
#endif
    // OSX and Ubuntu 10.04 don't seem to like setting DYLD_LIBRARY_PATH dynamically. Instead,
    // we add to the search paths and handle the search ourselves.
    DL_search_paths.push_back(path);
}

DynamicLibrary::DynamicLibrary(const String& path)
 : mPath(path),
   mHandle(NULL)
{
}
static bool unloadLibrary(DL_HANDLE lib) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    bool success = !FreeLibrary(lib);
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    bool success = dlclose(lib)==0;
#endif
    return success;
}
void DynamicLibrary::gc(DL_HANDLE handle) {
    static std::vector<DL_HANDLE> *sHandles=new std::vector<DL_HANDLE>;
    if (handle) {
        if (sHandles==NULL)
            sHandles=new std::vector<DL_HANDLE>;
        sHandles->push_back(handle);
    }else if(sHandles){
        for (std::vector<DL_HANDLE>::iterator i=sHandles->begin();i!=sHandles->end();++i) {
            unloadLibrary(*i);
        }
        delete sHandles;
        sHandles=NULL;
    }
}
DynamicLibrary::~DynamicLibrary() {
    if (mHandle != NULL)
        gc(mHandle);
}

bool DynamicLibrary::load() {
    if (mHandle != NULL)
        return true;

    if (!isValidLibraryFilename())
        return false;

#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    // Paths + resulting errors, in case we need to report them
    std::vector<String> dlopen_paths;
    std::vector<DWORD> dlopen_errors;

    dlopen_paths.push_back(mPath.c_str());
    mHandle = LoadLibrary(mPath.c_str());
    if (mHandle == NULL) {
        dlopen_errors.push_back(GetLastError());
        // Try any registered search paths
        for(uint32 i = 0; mHandle == NULL && i < DL_search_paths.size(); i++) {
            std::string str =(boost::filesystem::path(DL_search_paths[i]) / mPath).string();
            dlopen_paths.push_back(str);
            mHandle = LoadLibrary(str.c_str());
            if (mHandle == NULL) dlopen_errors.push_back(GetLastError());
        }
    }
    if (mHandle == NULL) {
        SILOG(plugin,warning,"Failed to open library " << mPath << ": ");
        for(uint32 i = 0; i < dlopen_paths.size(); i++)
            SILOG(plugin,warning," Tried to load " << dlopen_paths[i] << ": " << dlopen_errors[i]);
    }
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX

// Use RTLD_NOW in debug builds to make it more likely to catch missing symbols
// in simple tests, i.e. just by loading the library, since other tests might
// not get good enough coverage.
#if SIRIKATA_DEBUG
#define SIRIKATA_DLOPEN_FLAGS (RTLD_NOW | RTLD_GLOBAL)
#else
#define SIRIKATA_DLOPEN_FLAGS (RTLD_LAZY | RTLD_GLOBAL)
#endif

    // Paths + resulting errors, in case we need to report them
    std::vector<String> dlopen_paths;
    std::vector<String> dlopen_errors;

    dlopen_paths.push_back(mPath.c_str());
    mHandle = dlopen(mPath.c_str(), SIRIKATA_DLOPEN_FLAGS);
    if (mHandle == NULL) {
        dlopen_errors.push_back(String(dlerror()));
        // Try any registered search paths
        for(uint32 i = 0; mHandle == NULL && i < DL_search_paths.size(); i++) {
            std::string str = (boost::filesystem::path(DL_search_paths[i]) / mPath).string();
            dlopen_paths.push_back(str);
            mHandle = dlopen(
                str.c_str(),
                SIRIKATA_DLOPEN_FLAGS
            );
            if (mHandle == NULL) dlopen_errors.push_back(String(dlerror()));
        }
    }
    if (mHandle == NULL) {
        SILOG(plugin,warning,"Failed to open library " << mPath << ": ");
        for(uint32 i = 0; i < dlopen_paths.size(); i++)
            SILOG(plugin,warning," Tried to load " << dlopen_paths[i] << ": " << dlopen_errors[i]);
    }
#endif

    return (mHandle != NULL);
}

bool DynamicLibrary::unload() {
    if (mHandle == NULL)
        return true;
    bool success=unloadLibrary(mHandle);
    mHandle=NULL;
    return success;
}

void* DynamicLibrary::symbol(const String& name) const {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return (void*)GetProcAddress(mHandle, name.c_str());
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return (void*)dlsym(mHandle, name.c_str());
#endif
}

String DynamicLibrary::prefix() {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return "";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    return "lib";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return "lib";
#endif
}

String DynamicLibrary::postfix() {
#if SIRIKATA_DEBUG
    return "_d";
#else
    return "";
#endif
}

String DynamicLibrary::extension() {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    return ".dll";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC
    return ".dylib";
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    return ".so";
#endif
}

String DynamicLibrary::filename(const String& name) {
    return ( prefix() + name + postfix() + extension() );
}

String DynamicLibrary::filename(const String& path, const String& name) {
#if SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_WINDOWS
    const char file_separator = '\\';
#elif SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_MAC || SIRIKATA_PLATFORM == SIRIKATA_PLATFORM_LINUX
    const char file_separator = '/';
#endif

    String result = path;
    if (result.size() > 0 && result[result.size()-1] != file_separator)
        result += file_separator;
    result += filename(name);

    return result;
}

bool DynamicLibrary::isValidLibraryFilename() const {
    using namespace boost::filesystem;

    String pref = prefix();
    String ext = extension();

    path bfs_path = mPath;
    // FIXME this should be bfs_path.leaf() in 1.35, bfs_path.filename() in
    // 1.37.  Instead, just do this manually.
    String libfilename = bfs_path.empty() ? String() : *--bfs_path.end();

    if (libfilename.substr(0, pref.size()) != pref)
        return false;

    if (libfilename.size() < ext.size() ||
        libfilename.substr(libfilename.size() - ext.size()) != ext )
        return false;

    return true;
}

} // namespace Sirikata
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH
#define DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH

#if !HAVE_DUNE_PDELAB
# error "This one requires dune-pdelab!"
#endif

#include <memory>
#include <vector>
#include <limits>
#include <complex>
#include <type_traits>

#include <dune/common/timer.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/grid/information.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/functions/combined.hh>

#include <dune/gdt/spaces/nedelec/pdelab.hh>
#include <dune/gdt/operators/curlcurl.hh>
#include <dune/gdt/functionals/l2.hh>
#include <dune/gdt/assembler/system.hh>
#include <dune/gdt/spaces/constraints.hh>

/** \brief Class to discretize curl-curl problems
 *
 * Problems of the form curl(mu curl E)+kappa E= f are solved, which admit a unique solution if the complex parameter kappa has positive imaginary part.
 * The discretization uses Nedelec spaces of the first family in lowest order on simplicial grids. The functions and parameters can be complex-valued.
 * The parameters mu and kappa have to be computed out of the material parameters permability, permittivity and conductivity by the user.
 * Note that mu in most cases will be the inverse (!) permability.
 * \note As boundary conditions, only a homogenous Dirchlet condition is supported at the moment.
 *
 * \tparam GridViewType  Type of grid
 * \tparam polynomialOrder Polynomial order of the function space to be used, only polynomialOrder=1 is possible at the moment
 * \tparam MatrixImp Type of the system matrix
 * \tparam VectorImp Type of the vectors for the right hand side and the solution
 */

template< class GridViewType,
          int polynomialOrder,
          class MatrixImp = Dune::Stuff::LA::Container< std::complex< double >, Dune::Stuff::LA::ChooseBackend::istl_sparse >::MatrixType,  //Matrix-interface atm inable to handle complex!
          class VectorImp = Dune::Stuff::LA::Container< std::complex< double >, Dune::Stuff::LA::ChooseBackend::istl_sparse >::VectorType >
class Discretization{
public:
    static const size_t dimDomain = GridViewType::dimension;
    typedef typename GridViewType::ctype DomainFieldType;
    static const size_t dimRange = dimDomain;
    static const unsigned int polOrder = polynomialOrder;

    typedef Dune::Stuff::Grid::BoundaryInfoInterface< typename GridViewType::Intersection > BoundaryInfoType;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, std::complex< double >, dimRange > FunctionType1;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, double, dimRange > FunctionType2;

    typedef MatrixImp MatrixType;
    typedef VectorImp VectorType;

    typedef Dune::GDT::Spaces::Nedelec::PdelabBased< GridViewType, polOrder, double, dimRange > SpaceType;

    typedef Dune::GDT::DiscreteFunction< SpaceType, VectorType > DiscreteFunctionType;
    typedef Dune::GDT::ConstDiscreteFunction < SpaceType, VectorType > ConstDiscreteFunctionType;

    Discretization(const GridViewType& gp,
                   const BoundaryInfoType& info,
                   const FunctionType2& mu,
                   const FunctionType1& kappa,
                   const FunctionType1& src)
        : space_(gp)
        , boundary_info_(info)
        , mu_(mu)
        , kappa_(kappa)
        , sourceterm_(src)
        , is_assembled_(false)
        , system_matrix_(0,0)
        , rhs_vector_(0)
    {}

    const SpaceType& space() const
    {
        return space_;
    }

    VectorType create_vector() const
    {
        return VectorType(space_.mapper().size());
    }

    void assemble() const
    {
      using namespace Dune;
      using namespace Dune::GDT;
      if (!is_assembled_) {
        //prepare
        Stuff::LA::SparsityPatternDefault sparsity_pattern = space_.compute_face_and_volume_pattern();
        system_matrix_ = MatrixType(space_.mapper().size(), space_.mapper().size(), sparsity_pattern);
        rhs_vector_ = VectorType(space_.mapper().size());
        SystemAssembler< SpaceType > grid_walker(space_);

        //rhs
        typedef GDT::Functionals::L2Volume< FunctionType1, VectorType, SpaceType > L2FunctionalType;
        L2FunctionalType source_functional(sourceterm_, rhs_vector_, space_);
        grid_walker.add(source_functional);

        //lhs
        typedef GDT::Operators::CurlCurl< FunctionType2, MatrixType, SpaceType > CurlOperatorType;
        CurlOperatorType curlcurl_operator(mu_, system_matrix_, space_);
        grid_walker.add(curlcurl_operator);
        typedef LocalOperator::Codim0Integral< LocalEvaluation::Product< FunctionType1 > > IdOperatorType;
        const IdOperatorType identity_operator(kappa_);
        const LocalAssembler::Codim0Matrix< IdOperatorType > idMatrixAssembler(identity_operator);
        grid_walker.add(idMatrixAssembler, system_matrix_);

        //for non-homogeneous dirichlet boundary values you have to implement an appropriate DirichletProjection!
        //afterwards, the same procedure as in elliptic-cg-discretization can be used

        //apply the dirichlet constraints, atm only for homogenous dirichlet constraints!
        Spaces::DirichletConstraints< typename GridViewType::Intersection >
                dirichlet_constraints(boundary_info_, space_.mapper().maxNumDofs());
        grid_walker.add(dirichlet_constraints);
        grid_walker.assemble();
        dirichlet_constraints.apply(system_matrix_, rhs_vector_);
        is_assembled_ = true;
      }
    } //assemble()

    bool assembled() const
    {
        return is_assembled_;
    }

    const MatrixType& system_matrix() const
    {
        return system_matrix_;
    }

    const VectorType& rhs_vector() const
    {
        return rhs_vector_;
    }

    void solve(VectorType& solution) const
    {
      if(!is_assembled_)
          assemble();

      //solve
      Dune::Stuff::LA::Solver< MatrixType >(system_matrix_).apply(rhs_vector_, solution);
    } //solve()

private:
    const SpaceType space_;
    const BoundaryInfoType& boundary_info_;
    const FunctionType2& mu_;
    const FunctionType1& kappa_;
    const FunctionType1& sourceterm_;
    mutable bool is_assembled_;
    mutable MatrixType system_matrix_;
    mutable VectorType rhs_vector_;
}; //class discretization

#endif // DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH
<commit_msg>[test.curlcurldiscretization] introduce the correct function spaces; add implementation of real discretization (not ready yet!)<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH
#define DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH

#if !HAVE_DUNE_PDELAB
# error "This one requires dune-pdelab!"
#endif

#include <memory>
#include <vector>
#include <limits>
#include <complex>
#include <type_traits>

#include <dune/common/timer.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/grid/information.hh>
#include <dune/stuff/la/container.hh>
#include <dune/stuff/la/solver.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/functions/combined.hh>

#include <dune/gdt/spaces/nedelec/pdelab.hh>
#include <dune/gdt/operators/curlcurl.hh>
#include <dune/gdt/functionals/l2.hh>
#include <dune/gdt/assembler/system.hh>
#include <dune/gdt/spaces/constraints.hh>

/** \brief Class to discretize curl-curl problems
 *
 * Problems of the form curl(mu curl E)+kappa E= f are solved, which admit a unique solution if the complex parameter kappa has positive imaginary part.
 * The discretization uses Nedelec spaces of the first family in lowest order on simplicial grids. The functions and parameters can be complex-valued.
 * The parameters mu and kappa have to be computed out of the material parameters permability, permittivity and conductivity by the user.
 * Note that mu in most cases will be the inverse (!) permability.
 * \note As boundary conditions, only a homogenous Dirchlet condition is supported at the moment.
 *
 * \tparam GridViewType  Type of grid
 * \tparam polynomialOrder Polynomial order of the function space to be used, only polynomialOrder=1 is possible at the moment
 * \tparam MatrixImp Type of the system matrix
 * \tparam VectorImp Type of the vectors for the right hand side and the solution
 */

template< class GridViewType,
          int polynomialOrder,
          class MatrixImp = Dune::Stuff::LA::Container< std::complex< double > >::MatrixType,  //Matrix-interface atm inable to handle complex!
          class VectorImp = Dune::Stuff::LA::Container< std::complex< double > >::VectorType >
class Discretization{
public:
    static const size_t dimDomain = GridViewType::dimension;
    typedef typename GridViewType::ctype DomainFieldType;
    static const size_t dimRange = dimDomain;
    static const unsigned int polOrder = polynomialOrder;

    typedef Dune::Stuff::Grid::BoundaryInfoInterface< typename GridViewType::Intersection > BoundaryInfoType;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, std::complex< double >, dimRange > ComplexVectorfct;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, double, 1 > RealScalarFct;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, std::complex< double >, 1 > ComplexScalarFct;

    typedef MatrixImp MatrixType;
    typedef VectorImp VectorType;

    typedef Dune::GDT::Spaces::Nedelec::PdelabBased< GridViewType, polOrder, double, dimRange > SpaceType;

    typedef Dune::GDT::DiscreteFunction< SpaceType, VectorType > DiscreteFunctionType;
    typedef Dune::GDT::ConstDiscreteFunction < SpaceType, VectorType > ConstDiscreteFunctionType;

    Discretization(const GridViewType& gp,
                   const BoundaryInfoType& info,
                   const RealScalarFct& mu,
                   const ComplexScalarFct& kappa,
                   const ComplexVectorfct& src)
        : space_(gp)
        , boundary_info_(info)
        , mu_(mu)
        , kappa_(kappa)
        , sourceterm_(src)
        , is_assembled_(false)
        , system_matrix_(0,0)
        , rhs_vector_(0)
    {}

    const SpaceType& space() const
    {
        return space_;
    }

    VectorType create_vector() const
    {
        return VectorType(space_.mapper().size());
    }

    void assemble() const
    {
      using namespace Dune;
      using namespace Dune::GDT;
      if (!is_assembled_) {
        //prepare
        Stuff::LA::SparsityPatternDefault sparsity_pattern = space_.compute_face_and_volume_pattern();
        system_matrix_ = MatrixType(space_.mapper().size(), space_.mapper().size(), sparsity_pattern);
        rhs_vector_ = VectorType(space_.mapper().size());
        SystemAssembler< SpaceType > grid_walker(space_);

        //rhs
        /*typedef GDT::Functionals::L2Volume< ComplexVectorfct, VectorType, SpaceType > L2FunctionalType;
        L2FunctionalType source_functional(sourceterm_, rhs_vector_, space_);
        grid_walker.add(source_functional);*/
        auto source_functional = Dune::GDT::Functionals::make_l2_volume(sourceterm_, rhs_vector_, space_);
        grid_walker.add(*source_functional);

        //lhs
        typedef GDT::Operators::CurlCurl< RealScalarFct, MatrixType, SpaceType > CurlOperatorType;
        CurlOperatorType curlcurl_operator(mu_, system_matrix_, space_);
        grid_walker.add(curlcurl_operator);
        typedef LocalOperator::Codim0Integral< LocalEvaluation::Product< ComplexScalarFct > > IdOperatorType;
        const IdOperatorType identity_operator(kappa_);
        const LocalAssembler::Codim0Matrix< IdOperatorType > idMatrixAssembler(identity_operator);
        grid_walker.add(idMatrixAssembler, system_matrix_);

        //for non-homogeneous dirichlet boundary values you have to implement an appropriate DirichletProjection!
        //afterwards, the same procedure as in elliptic-cg-discretization can be used

        //apply the dirichlet constraints, atm only for homogenous dirichlet constraints!
        Spaces::DirichletConstraints< typename GridViewType::Intersection >
                dirichlet_constraints(boundary_info_, space_.mapper().maxNumDofs());
        grid_walker.add(dirichlet_constraints);
        grid_walker.assemble();
        dirichlet_constraints.apply(system_matrix_, rhs_vector_);
        is_assembled_ = true;
      }
    } //assemble()

    bool assembled() const
    {
        return is_assembled_;
    }

    const MatrixType& system_matrix() const
    {
        return system_matrix_;
    }

    const VectorType& rhs_vector() const
    {
        return rhs_vector_;
    }

    void solve(VectorType& solution) const
    {
      if(!is_assembled_)
          assemble();

      //solve
      Dune::Stuff::LA::Solver< MatrixType >(system_matrix_).apply(rhs_vector_, solution);
    } //solve()

private:
    const SpaceType space_;
    const BoundaryInfoType& boundary_info_;
    const RealScalarFct& mu_;
    const ComplexScalarFct& kappa_;
    const ComplexVectorfct& sourceterm_;
    mutable bool is_assembled_;
    mutable MatrixType system_matrix_;
    mutable VectorType rhs_vector_;
}; //class discretization

/** \brief Class to discretize curl-curl problems only using real matrices
 *
 * Problems of the form curl(mu curl E)+kappa E= f are solved, which admit a unique solution if the complex parameter kappa has positive imaginary part.
 * The discretization uses Nedelec spaces of the first family in lowest order on simplicial grids. The functions and parameters can be complex-valued.
 * The parameters mu and kappa have to be computed out of the material parameters permability, permittivity and conductivity by the user.
 * Note that mu in most cases will be the inverse (!) permability.
 * \note As boundary conditions, only a homogenous Dirichlet condition is supported at the moment.
 *
 * \tparam GridViewType  Type of grid
 * \tparam polynomialOrder Polynomial order of the function space to be used, only polynomialOrder=1 is possible at the moment
 * \tparam MatrixImp Type of the system matrix
 * \tparam VectorImp Type of the vectors for the right hand side and the solution
 */

template< class GridViewType,
          int polynomialOrder,
          class MatrixImp = Dune::Stuff::LA::Container< double >::MatrixType,
          class VectorImp = Dune::Stuff::LA::Container< double >::VectorType >
class DiscretizationReal{
public:
    static const size_t dimDomain = GridViewType::dimension;
    typedef typename GridViewType::ctype DomainFieldType;
    static const size_t dimRange = dimDomain;
    static const unsigned int polOrder = polynomialOrder;

    typedef Dune::Stuff::Grid::BoundaryInfoInterface< typename GridViewType::Intersection > BoundaryInfoType;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, double, dimRange > Vectorfct;
    typedef Dune::Stuff::LocalizableFunctionInterface< typename GridViewType::template Codim< 0 >::Entity, DomainFieldType, dimDomain, double, 1 > ScalarFct;

    typedef MatrixImp MatrixType;
    typedef VectorImp VectorType;

    typedef Dune::GDT::Spaces::Nedelec::PdelabBased< GridViewType, polOrder, double, dimRange > SpaceType;

    typedef Dune::GDT::DiscreteFunction< SpaceType, VectorType > DiscreteFunctionType;
    typedef Dune::GDT::ConstDiscreteFunction < SpaceType, VectorType > ConstDiscreteFunctionType;

    DiscretizationReal(const GridViewType& gp,
                       const BoundaryInfoType& info,
                       const ScalarFct& mu,
                       const ScalarFct& kappareal,
                       const ScalarFct& kappaimag,
                       const Vectorfct& srcreal,
                       const Vectorfct& srcimag)
        : space_(gp)
        , boundary_info_(info)
        , mu_(mu)
        , kappa_real_(kappareal)
        , kappa_imag_(kappaimag)
        , sourceterm_real_(srcreal)
        , sourceterm_imag_(srcimag)
        , is_assembled_(false)
        , system_matrix_real_(0,0)
        , system_matrix_imag_(0,0)
        , system_matrix_total_(0,0)
        , rhs_vector_real_(0)
        , rhs_vector_imag_(0)
        , rhs_vector_total_(0)
    {}

    const SpaceType& space() const
    {
        return space_;
    }

    VectorType create_vector() const
    {
        return VectorType(space_.mapper().size());
    }

    void assemble() const
    {
      using namespace Dune;
      using namespace Dune::GDT;
      if (!is_assembled_) {
        //prepare
        Stuff::LA::SparsityPatternDefault sparsity_pattern = space_.compute_face_and_volume_pattern();
        system_matrix_real_ = MatrixType(space_.mapper().size(), space_.mapper().size(), sparsity_pattern);
        system_matrix_imag_ = MatrixType(space_.mapper().size(), space_.mapper().size(), sparsity_pattern);
        system_matrix_total_ = MatrixType(2*space_.mapper().size(), 2*space_.mapper().size());
        rhs_vector_real_ = VectorType(space_.mapper().size());
        rhs_vector_imag_ = VectorType(space_.mapper().size());
        rhs_vector_total_ = VectorType(2*space_.mapper().size());
        SystemAssembler< SpaceType > grid_walker(space_);

        //rhs
        auto source_functional_real = Dune::GDT::Functionals::make_l2_volume(sourceterm_real_, rhs_vector_real_, space_);
        grid_walker.add(*source_functional_real);
        auto source_functional_imag = Dune::GDT::Functionals::make_l2_volume(sourceterm_imag_, rhs_vector_imag_, space_);
        grid_walker.add(*source_functional_imag);

        //lhs
        typedef GDT::Operators::CurlCurl< ScalarFct, MatrixType, SpaceType > CurlOperatorType;
        CurlOperatorType curlcurl_operator(mu_, system_matrix_real_, space_);
        grid_walker.add(curlcurl_operator);
        typedef LocalOperator::Codim0Integral< LocalEvaluation::Product< ScalarFct > > IdOperatorType;
        const IdOperatorType identity_operator1(kappa_real_);
        const LocalAssembler::Codim0Matrix< IdOperatorType > idMatrixAssembler1(identity_operator1);
        grid_walker.add(idMatrixAssembler1, system_matrix_real_);
        typedef LocalOperator::Codim0Integral< LocalEvaluation::Product< ScalarFct > > IdOperatorType;
        const IdOperatorType identity_operator2(kappa_imag_);
        const LocalAssembler::Codim0Matrix< IdOperatorType > idMatrixAssembler2(identity_operator2);
        grid_walker.add(idMatrixAssembler2, system_matrix_imag_);

        //for non-homogeneous dirichlet boundary values you have to implement an appropriate DirichletProjection!
        //afterwards, the same procedure as in elliptic-cg-discretization can be used

        //apply the dirichlet constraints, atm only for homogenous dirichlet constraints!
        Spaces::DirichletConstraints< typename GridViewType::Intersection >
                dirichlet_constraints(boundary_info_, space_.mapper().size());
        grid_walker.add(dirichlet_constraints);
        grid_walker.assemble();
        dirichlet_constraints.apply(system_matrix_real_, rhs_vector_real_);
        dirichlet_constraints.apply(system_matrix_imag_, rhs_vector_imag_);

        // total (block) matrix and (block) vector have to be assembled
        //system_matrix_total_.backend().topLeftCorner(space_.mapper().size(), space_.mapper().size()) = system_matrix_real_.backend().topLeftCorner(space_.mapper().size(), space_.mapper().size());

        is_assembled_ = true;
      }
    } //assemble()

    bool assembled() const
    {
        return is_assembled_;
    }

    const MatrixType& system_matrix() const
    {
        return system_matrix_total_;
    }

    const VectorType& rhs_vector() const
    {
        return rhs_vector_total_;
    }

    void solve(VectorType& solution) const
    {
      if(!is_assembled_)
          assemble();

      //solve
      Dune::Stuff::LA::Solver< MatrixType >(system_matrix_total_).apply(rhs_vector_total_, solution);
    } //solve()

private:
    const SpaceType space_;
    const BoundaryInfoType& boundary_info_;
    const ScalarFct& mu_;
    const ScalarFct& kappa_real_;
    const ScalarFct& kappa_imag_;
    const Vectorfct& sourceterm_real_;
    const Vectorfct& sourceterm_imag_;
    mutable bool is_assembled_;
    mutable MatrixType system_matrix_real_;
    mutable MatrixType system_matrix_imag_;
    mutable MatrixType system_matrix_total_;
    mutable VectorType rhs_vector_real_;
    mutable VectorType rhs_vector_imag_;
    mutable VectorType rhs_vector_total_;
}; //class discretizationreal

#endif // DUNE_GDT_TEST_CURLCURLDISCRETIZATION_HH
<|endoftext|>


<commit_before>/*******************************************************************************
 * This file is part of "Patrick's Programming Library", Version 7 (PPL7).
 * Web: http://www.pfp.de/ppl/
 *
 * $Author$
 * $Revision$
 * $Date$
 * $Id$
 *
 *******************************************************************************
 * Copyright (c) 2013, Patrick Fedick <patrick@pfp.de>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    1. Redistributions of source code must retain the above copyright notice, this
 *       list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER AND CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include "prolog.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef _WIN32
    #include <winsock2.h>
#endif

#include "ppl7.h"
#include "ppl7-inet.h"
#include "socket.h"

//#define DEBUGOUT

namespace ppl7 {

/*!\class CSocketMessage
 * \ingroup PPLGroupInternet
 */

SocketMessage::SocketMessage()
{
	payload_size=0;
	payload_type=0;
	payload=NULL;
	commandId=0;
	ClientSupportsCompression=false;
	Version=1;
	UseCompression=true;
	Id=0;
	SupportMsgChannel=false;
}

SocketMessage::SocketMessage(const SocketMessage &other)
{
	payload=NULL;
	commandId=0;
	ClientSupportsCompression=false;
	Version=1;
	UseCompression=true;
	SupportMsgChannel=false;
	Id=0;
	copy(other);
}

SocketMessage::~SocketMessage()
{
	clear();
}

void SocketMessage::clear()
{
	if (!payload) return;
	free(payload);
	payload=NULL;
}

void SocketMessage::copy(const SocketMessage &other)
{
	clear();
	commandId=other.commandId;
	Id=other.Id;
	Version=other.Version;
	UseCompression=other.UseCompression;
	payload_size=other.payload_size;
	payload_type=other.payload_type;

	if (other.payload) {
		payload=malloc(payload_size);
		if (!payload) throw OutOfMemoryException();
		memcpy(payload,other.payload,payload_size);
	}
}

void SocketMessage::enableCompression(bool flag)
{
	UseCompression=flag;
}

void SocketMessage::enableMsgChannel(bool flag)
{
	SupportMsgChannel=flag;
}

bool SocketMessage::isCompressionSupported() const
{
	return ClientSupportsCompression;
}

bool SocketMessage::isMsgChannelSupported() const
{
	return SupportMsgChannel;
}

void SocketMessage::setCommandId(int id)
{
	commandId=id;
}

void SocketMessage::setId(int id)
{
	Id=id;
}

void SocketMessage::setPayload(const String &msg)
{
	clear();
	payload_type=Variant::TYPE_STRING;
	payload_size=msg.size();
	payload=strndup(msg.c_str(),payload_size);
	if (!payload) throw OutOfMemoryException();
}

void SocketMessage::setPayload(const AssocArray &msg)
{
	clear();
	payload_type=Variant::TYPE_ASSOCARRAY;
	payload_size=msg.binarySize();
	payload=malloc(payload_size);
	if (!payload) throw OutOfMemoryException();
	msg.exportBinary(payload,payload_size,NULL);
}

void SocketMessage::setPayload(const ByteArrayPtr &msg)
{
	clear();
	payload_type=Variant::TYPE_BYTEARRAY;
	payload_size=msg.size();
	payload=malloc(payload_size);
	if (!payload) throw OutOfMemoryException();
	memcpy(payload,msg.ptr(),payload_size);
}

void SocketMessage::getPayload(String &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type==1 || payload_type==Variant::TYPE_STRING) {
		msg.set((const char*)payload,payload_size);
		return;
	}
	throw DataInOtherFormatException();
}

void SocketMessage::getPayload(AssocArray &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type!=Variant::TYPE_ASSOCARRAY) {
		throw DataInOtherFormatException();
	}
	msg.importBinary(payload,payload_size);
}

void SocketMessage::getPayload(ByteArray &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type!=Variant::TYPE_BYTEARRAY) {
		throw DataInOtherFormatException();
	}
	msg.copy(payload,payload_size);
}

int SocketMessage::getId() const
{
	return Id;
}

int SocketMessage::getCommandId() const
{
	return commandId;
}

int SocketMessage::getPayloadType()
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	return payload_type;
}

void SocketMessage::compilePacketHeader(char *buffer, size_t *buffer_size, const void *payload, size_t payload_size, bool is_compressed) const
{
	if (*buffer_size<24) throw BufferTooSmallException();
	bzero(buffer,24);
	int flags=0;
	if (UseCompression) flags|=2;		// Bit 1: Client supports ZLib
	if (SupportMsgChannel) flags|=4;	// Bit 2: Client supports MsgChannel
	if (is_compressed) flags|=1;
	PokeN8(buffer,'V');							// Byte 0:  "V"							(1 Byte)
	PokeN8(buffer+1,2);							// Byte 1:  Version=2					(1 Byte)
	PokeN16(buffer+2,commandId);				// Byte 2:  CommandId					(2 Byte)
	PokeN32(buffer+4,Id);						// Byte 4:  Id							(4 Byte)
	PokeN32(buffer+8,payload_size);				// Byte 8:  Bytes Nutzdaten				(4 Byte)
	PokeN8(buffer+12,flags);					// Byte 12: Flags						(1 Byte)
	//  											        Bit 0: Zlib-Kompression
	//														Bit 1: Client supports ZLib
	//														Bit 2: Client supports MsgChannel
	PokeN8(buffer+13,payload_type);				// Byte 13: Datatype, PPL_ARRAY, usw.	(1 Byte)
	PokeN16(buffer+14,rand(177,65534));			// Byte 14: Zufallszahl					(2 Byte)
	ppluint32 crc_data=0;
	if (payload_size) crc_data=Crc32(payload,payload_size);
	PokeN32(buffer+16,crc_data);				// Byte 16: CRC-Summe ueber die Daten	(4 Byte)
	PokeN32(buffer+20,Crc32(buffer,20));		// Byte 20: CRC-Summe ueber den Header	(4 Byte)
	*buffer_size=24;
}

void SocketMessage::readFromPacketHeader(const char *msgbuffer, int &flags)
{
	commandId=PeekN16(msgbuffer+2);
	flags=PeekN8(msgbuffer+12);
	payload_type=PeekN8(msgbuffer+13);
	Id=PeekN32(msgbuffer+4);
	payload_size=PeekN32(msgbuffer+8);
	if (Version==1) {
		if (PeekN32(msgbuffer+16)!=Crc32(msgbuffer,16)) throw InvalidPacketException("CRC checksum");
	} else if (PeekN8(msgbuffer)=='V' && PeekN8(msgbuffer+1)==2) {
		//int data_crc=PeekN32(msgbuffer+16);
		if (PeekN32(msgbuffer+20)!=Crc32(msgbuffer,20)) throw InvalidPacketException("CRC checksum");
	}
	if (flags&2) ClientSupportsCompression=true;
	else ClientSupportsCompression=false;

	if (flags&4) SupportMsgChannel=true;
	else SupportMsgChannel=false;

}

size_t TCPSocket::write(const SocketMessage &msg)
/*!\brief Nachricht verschicken
 *
 * \desc
 *
 * \copydoc PPLSocketMessage
 */
{
	Compression comp(Compression::Algo_ZLIB,Compression::Level_High);
	ByteArray compressed;
	comp.usePrefix(Compression::Prefix_V1);
	const void *msg_payload=msg.payload;
	size_t msg_size=msg.payload_size;
	bool is_compressed=false;
	if (msg_size>64 && msg.ClientSupportsCompression==true && msg.UseCompression==true) {
		try {
			comp.compress(compressed,msg_payload,msg_size);
			if (compressed.size()<msg_size) {
				is_compressed=true;
				msg_payload=compressed.ptr();
				msg_size=compressed.size();
			}
		} catch (...) {
		}
	}
	if (msg_size>0xffffffff) throw SocketMessage::PayloadTooBigException();
	char header[24];
	size_t headersize=24;
	msg.compilePacketHeader(header,&headersize,msg_payload,msg_size,is_compressed);
	size_t bytes_send=0;
	bytes_send+=write(header,headersize);
	if (msg_size) {
		bytes_send+=write(msg_payload,msg_size);
	}
	return bytes_send;
}

bool TCPSocket::waitForMessage(SocketMessage &msg, int timeout_seconds, Thread *watch_thread)
/*!\brief Auf Nachricht warten
 *
 * \desc
 *
 * \copydoc PPLSocketMessage
 */
{
	Compression comp(Compression::Algo_ZLIB,Compression::Level_High);
	ByteArray uncompressed;
	comp.usePrefix(Compression::Prefix_V1);
	ppluint64 tt=GetTime()+timeout_seconds;
	char msgbuffer[28];
	void *buffer=NULL;
	int flags;
	while (timeout_seconds==0 || GetTime()<=tt) {
		if (watch_thread) {
			if (watch_thread->threadShouldStop()) {
				return false;
			}
		}
		bzero(msgbuffer,24);
		if (!waitForIncomingData(0,100000)) continue;

		// Datenpaket vorhanden
		if (this->read(msgbuffer,20)!=20) return false;
		msg.Version=PeekN8(msgbuffer+1);
		if (msgbuffer[0]=='V' && msg.Version==2) {
			if (this->read(msgbuffer+20,4)!=4) return false;
		} else if (msgbuffer[0]!='V' || msg.Version!=1) {
			throw SocketMessage::InvalidProtocolVersion();
		}
		msg.clear();
		msg.readFromPacketHeader(msgbuffer, flags);
		if (msg.payload_size) {
			buffer=malloc(msg.payload_size);
			if (!buffer) throw OutOfMemoryException();
			if (this->read(buffer,msg.payload_size)!=msg.payload_size) {
				free(buffer);
				throw SocketMessage::InvalidPacketException("Packet incomplete");
			}
			if (msg.Version>1) {	// CRC prüfen
				if (PeekN32(msgbuffer+16)!=Crc32(buffer,msg.payload_size)) {
					free(buffer);
					throw SocketMessage::InvalidPacketException("CRC checksum of payload");
				}
			}
			if (flags&1) {
				comp.uncompress(uncompressed,buffer,msg.payload_size);
				free(buffer);
				msg.payload_size=uncompressed.size();
				msg.payload=malloc(msg.payload_size);
				if (!msg.payload) throw OutOfMemoryException();
				memcpy(msg.payload,uncompressed.ptr(),msg.payload_size);
			} else {
				msg.payload=buffer;
			}
		}
		return true;
	}
	return false;
}

}

<commit_msg>fixed TCPSocket::waitForMessage<commit_after>/*******************************************************************************
 * This file is part of "Patrick's Programming Library", Version 7 (PPL7).
 * Web: http://www.pfp.de/ppl/
 *
 * $Author$
 * $Revision$
 * $Date$
 * $Id$
 *
 *******************************************************************************
 * Copyright (c) 2013, Patrick Fedick <patrick@pfp.de>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    1. Redistributions of source code must retain the above copyright notice, this
 *       list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER AND CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include "prolog.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef _WIN32
    #include <winsock2.h>
#endif

#include "ppl7.h"
#include "ppl7-inet.h"
#include "socket.h"

//#define DEBUGOUT

namespace ppl7 {

/*!\class CSocketMessage
 * \ingroup PPLGroupInternet
 */

SocketMessage::SocketMessage()
{
	payload_size=0;
	payload_type=0;
	payload=NULL;
	commandId=0;
	ClientSupportsCompression=false;
	Version=1;
	UseCompression=true;
	Id=0;
	SupportMsgChannel=false;
}

SocketMessage::SocketMessage(const SocketMessage &other)
{
	payload=NULL;
	commandId=0;
	ClientSupportsCompression=false;
	Version=1;
	UseCompression=true;
	SupportMsgChannel=false;
	Id=0;
	copy(other);
}

SocketMessage::~SocketMessage()
{
	clear();
}

void SocketMessage::clear()
{
	if (!payload) return;
	free(payload);
	payload=NULL;
}

void SocketMessage::copy(const SocketMessage &other)
{
	clear();
	commandId=other.commandId;
	Id=other.Id;
	Version=other.Version;
	UseCompression=other.UseCompression;
	payload_size=other.payload_size;
	payload_type=other.payload_type;

	if (other.payload) {
		payload=malloc(payload_size);
		if (!payload) throw OutOfMemoryException();
		memcpy(payload,other.payload,payload_size);
	}
}

void SocketMessage::enableCompression(bool flag)
{
	UseCompression=flag;
}

void SocketMessage::enableMsgChannel(bool flag)
{
	SupportMsgChannel=flag;
}

bool SocketMessage::isCompressionSupported() const
{
	return ClientSupportsCompression;
}

bool SocketMessage::isMsgChannelSupported() const
{
	return SupportMsgChannel;
}

void SocketMessage::setCommandId(int id)
{
	commandId=id;
}

void SocketMessage::setId(int id)
{
	Id=id;
}

void SocketMessage::setPayload(const String &msg)
{
	clear();
	payload_type=Variant::TYPE_STRING;
	payload_size=msg.size();
	payload=strndup(msg.c_str(),payload_size);
	if (!payload) throw OutOfMemoryException();
}

void SocketMessage::setPayload(const AssocArray &msg)
{
	clear();
	payload_type=Variant::TYPE_ASSOCARRAY;
	payload_size=msg.binarySize();
	payload=malloc(payload_size);
	if (!payload) throw OutOfMemoryException();
	msg.exportBinary(payload,payload_size,NULL);
}

void SocketMessage::setPayload(const ByteArrayPtr &msg)
{
	clear();
	payload_type=Variant::TYPE_BYTEARRAY;
	payload_size=msg.size();
	payload=malloc(payload_size);
	if (!payload) throw OutOfMemoryException();
	memcpy(payload,msg.ptr(),payload_size);
}

void SocketMessage::getPayload(String &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type==1 || payload_type==Variant::TYPE_STRING) {
		msg.set((const char*)payload,payload_size);
		return;
	}
	throw DataInOtherFormatException();
}

void SocketMessage::getPayload(AssocArray &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type!=Variant::TYPE_ASSOCARRAY) {
		throw DataInOtherFormatException();
	}
	msg.importBinary(payload,payload_size);
}

void SocketMessage::getPayload(ByteArray &msg) const
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	if (payload_type!=Variant::TYPE_BYTEARRAY) {
		throw DataInOtherFormatException();
	}
	msg.copy(payload,payload_size);
}

int SocketMessage::getId() const
{
	return Id;
}

int SocketMessage::getCommandId() const
{
	return commandId;
}

int SocketMessage::getPayloadType()
{
	if (!payload) {
		throw NoDataAvailableException();
	}
	return payload_type;
}

void SocketMessage::compilePacketHeader(char *buffer, size_t *buffer_size, const void *payload, size_t payload_size, bool is_compressed) const
{
	if (*buffer_size<24) throw BufferTooSmallException();
	bzero(buffer,24);
	int flags=0;
	if (UseCompression) flags|=2;		// Bit 1: Client supports ZLib
	if (SupportMsgChannel) flags|=4;	// Bit 2: Client supports MsgChannel
	if (is_compressed) flags|=1;
	PokeN8(buffer,'V');							// Byte 0:  "V"							(1 Byte)
	PokeN8(buffer+1,2);							// Byte 1:  Version=2					(1 Byte)
	PokeN16(buffer+2,commandId);				// Byte 2:  CommandId					(2 Byte)
	PokeN32(buffer+4,Id);						// Byte 4:  Id							(4 Byte)
	PokeN32(buffer+8,payload_size);				// Byte 8:  Bytes Nutzdaten				(4 Byte)
	PokeN8(buffer+12,flags);					// Byte 12: Flags						(1 Byte)
	//  											        Bit 0: Zlib-Kompression
	//														Bit 1: Client supports ZLib
	//														Bit 2: Client supports MsgChannel
	PokeN8(buffer+13,payload_type);				// Byte 13: Datatype, PPL_ARRAY, usw.	(1 Byte)
	PokeN16(buffer+14,rand(177,65534));			// Byte 14: Zufallszahl					(2 Byte)
	ppluint32 crc_data=0;
	if (payload_size) crc_data=Crc32(payload,payload_size);
	PokeN32(buffer+16,crc_data);				// Byte 16: CRC-Summe ueber die Daten	(4 Byte)
	PokeN32(buffer+20,Crc32(buffer,20));		// Byte 20: CRC-Summe ueber den Header	(4 Byte)
	*buffer_size=24;
}

void SocketMessage::readFromPacketHeader(const char *msgbuffer, int &flags)
{
	commandId=PeekN16(msgbuffer+2);
	flags=PeekN8(msgbuffer+12);
	payload_type=PeekN8(msgbuffer+13);
	Id=PeekN32(msgbuffer+4);
	payload_size=PeekN32(msgbuffer+8);
	if (Version==1) {
		if (PeekN32(msgbuffer+16)!=Crc32(msgbuffer,16)) throw InvalidPacketException("CRC checksum");
	} else if (PeekN8(msgbuffer)=='V' && PeekN8(msgbuffer+1)==2) {
		//int data_crc=PeekN32(msgbuffer+16);
		if (PeekN32(msgbuffer+20)!=Crc32(msgbuffer,20)) throw InvalidPacketException("CRC checksum");
	}
	if (flags&2) ClientSupportsCompression=true;
	else ClientSupportsCompression=false;

	if (flags&4) SupportMsgChannel=true;
	else SupportMsgChannel=false;

}

//#define DEBUG_LOG 1

size_t TCPSocket::write(const SocketMessage &msg)
/*!\brief Nachricht verschicken
 *
 * \desc
 *
 * \copydoc PPLSocketMessage
 */
{
	Compression comp(Compression::Algo_ZLIB,Compression::Level_High);
	ByteArray compressed;
	comp.usePrefix(Compression::Prefix_V1);
	const void *msg_payload=msg.payload;
	size_t msg_size=msg.payload_size;
	bool is_compressed=false;
	if (msg_size>64 && msg.ClientSupportsCompression==true && msg.UseCompression==true) {
		try {
			comp.compress(compressed,msg_payload,msg_size);
			if (compressed.size()<msg_size) {
				is_compressed=true;
				msg_payload=compressed.ptr();
				msg_size=compressed.size();
			}
		} catch (...) {
		}
	}
	if (msg_size>0xffffffff) throw SocketMessage::PayloadTooBigException();
	char header[24];
	size_t headersize=24;
	msg.compilePacketHeader(header,&headersize,msg_payload,msg_size,is_compressed);
	size_t bytes_send=0;
#ifdef DEBUG_LOG
	printf ("Send Header:\n");
	ppl7::HexDump(header,headersize);
#endif
	bytes_send+=write(header,headersize);
	if (msg_size) {
#ifdef DEBUG_LOG
		printf ("Send Payload:\n");
		ppl7::HexDump(msg_payload,msg_size);
#endif
		bytes_send+=write(msg_payload,msg_size);
	}
	return bytes_send;
}

bool TCPSocket::waitForMessage(SocketMessage &msg, int timeout_seconds, Thread *watch_thread)
/*!\brief Auf Nachricht warten
 *
 * \desc
 *
 * \copydoc PPLSocketMessage
 */
{
	Compression comp(Compression::Algo_ZLIB,Compression::Level_High);
	ByteArray uncompressed;
	comp.usePrefix(Compression::Prefix_V1);
	ppluint64 tt=GetTime()+timeout_seconds;
	char msgbuffer[28];
	void *buffer=NULL;
	int flags;
	while (timeout_seconds==0 || GetTime()<=tt) {
		if (watch_thread) {
			if (watch_thread->threadShouldStop()) {
				return false;
			}
		}
		bzero(msgbuffer,24);
		if (!waitForIncomingData(0,100000)) continue;

		// Datenpaket vorhanden
		this->readLoop(msgbuffer, 20, timeout_seconds, watch_thread);
		msg.Version=PeekN8(msgbuffer+1);
#ifdef DEBUG_LOG
		printf ("received Header:\n");
		HexDump(msgbuffer,20);
#endif
		if (msgbuffer[0]=='V' && msg.Version==2) {
			this->readLoop(msgbuffer+20,4, timeout_seconds, watch_thread);
#ifdef DEBUG_LOG
			printf ("received additional Header:\n");
			HexDump(msgbuffer+20,4);
#endif
		} else if (msgbuffer[0]!='V' || msg.Version!=1) {
			throw SocketMessage::InvalidProtocolVersion();
		}
		msg.clear();
		msg.readFromPacketHeader(msgbuffer, flags);
		if (msg.payload_size) {
			buffer=malloc(msg.payload_size);
			if (!buffer) throw OutOfMemoryException();
			try {
				this->readLoop(buffer,msg.payload_size, timeout_seconds, watch_thread);
			} catch (...) {
				free(buffer);
				throw;
			}
#ifdef DEBUG_LOG
			printf ("received Payload:\n");
			HexDump(buffer,msg.payload_size);
#endif

			if (msg.Version>1) {	// CRC prüfen
				if (PeekN32(msgbuffer+16)!=Crc32(buffer,msg.payload_size)) {
					free(buffer);
					throw SocketMessage::InvalidPacketException("CRC checksum of payload");
				}
			}
			if (flags&1) {
				comp.uncompress(uncompressed,buffer,msg.payload_size);
				free(buffer);
				msg.payload_size=uncompressed.size();
				msg.payload=malloc(msg.payload_size);
				if (!msg.payload) throw OutOfMemoryException();
				memcpy(msg.payload,uncompressed.ptr(),msg.payload_size);
			} else {
				msg.payload=buffer;
			}
		}
		return true;
	}
	return false;
}

}

<|endoftext|>