<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImage.h"
#include "SkImageGenerator.h"
#include "SkNextID.h"
#include "SkYUVAIndex.h"

SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID)
    : fInfo(info)
    , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
{}

bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
    if (kUnknown_SkColorType == info.colorType()) {
        return false;
    }
    if (nullptr == pixels) {
        return false;
    }
    if (rowBytes < info.minRowBytes()) {
        return false;
    }

    Options defaultOpts;
    return this->onGetPixels(info, pixels, rowBytes, defaultOpts);
}

bool SkImageGenerator::queryYUVA8(SkYUVSizeInfo* sizeInfo,
                                  SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
                                  SkYUVColorSpace* colorSpace) const {
    SkASSERT(sizeInfo);

    if (!this->onQueryYUVA8(sizeInfo, yuvaIndices, colorSpace)) {
        // try the deprecated method and make a guess at the other data
        if (this->onQueryYUV8(sizeInfo, colorSpace)) {
            // take a guess at the number of planes
            int numPlanes = SkYUVSizeInfo::kMaxCount;
            for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
                if (sizeInfo->fSizes[i].isEmpty()) {
                    numPlanes = i;
                    break;
                }
            }
            if (!numPlanes) {
                return false;
            }
            switch (numPlanes) {
                case 1:
                    // Assume 3 interleaved planes
                    sizeInfo->fColorTypes[0] = kRGBA_8888_SkColorType;
                    sizeInfo->fColorTypes[1] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kG;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kB;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
                case 2:
                    // Assume 1 Y plane and interleaved UV planes
                    sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[1] = kRGBA_8888_SkColorType;
                    sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kG;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
                case 3:
                    // Assume 3 separate non-interleaved planes
                    sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[1] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[2] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
                case 4:
                default:
                    // Assume 4 separate non-interleaved planes
                    sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[1] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[2] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[3] = kAlpha_8_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = 3;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
            }

            return true;
        }

        return false;
    }

    return true;
}

bool SkImageGenerator::getYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
                                      const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
                                      void* planes[SkYUVSizeInfo::kMaxCount]) {

    for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
        SkASSERT(sizeInfo.fSizes[i].fWidth >= 0);
        SkASSERT(sizeInfo.fSizes[i].fHeight >= 0);
        SkASSERT(sizeInfo.fWidthBytes[i] >= (size_t) sizeInfo.fSizes[i].fWidth);
    }

    int numPlanes = 0;
    SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
    SkASSERT(planes);
    for (int i = 0; i < numPlanes; ++i) {
        SkASSERT(planes[i]);
    }

    if (!this->onGetYUVA8Planes(sizeInfo, yuvaIndices, planes)) {
        return this->onGetYUV8Planes(sizeInfo, planes);
    }
    return true;
}

#if SK_SUPPORT_GPU
#include "GrTextureProxy.h"

sk_sp<GrTextureProxy> SkImageGenerator::generateTexture(GrContext* ctx, const SkImageInfo& info,
                                                        const SkIPoint& origin,
                                                        bool willNeedMipMaps) {
    SkIRect srcRect = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height());
    if (!SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(srcRect)) {
        return nullptr;
    }
    return this->onGenerateTexture(ctx, info, origin, willNeedMipMaps);
}

sk_sp<GrTextureProxy> SkImageGenerator::onGenerateTexture(GrContext*, const SkImageInfo&,
                                                          const SkIPoint&,
                                                          bool willNeedMipMaps) {
    return nullptr;
}
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////

#include "SkBitmap.h"
#include "SkColorTable.h"

#include "SkGraphics.h"

static SkGraphics::ImageGeneratorFromEncodedDataFactory gFactory;

SkGraphics::ImageGeneratorFromEncodedDataFactory
SkGraphics::SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory)
{
    ImageGeneratorFromEncodedDataFactory prev = gFactory;
    gFactory = factory;
    return prev;
}

std::unique_ptr<SkImageGenerator> SkImageGenerator::MakeFromEncoded(sk_sp<SkData> data) {
    if (!data) {
        return nullptr;
    }
    if (gFactory) {
        if (std::unique_ptr<SkImageGenerator> generator = gFactory(data)) {
            return generator;
        }
    }
    return SkImageGenerator::MakeFromEncodedImpl(std::move(data));
}
<commit_msg>Check correct number of planes in queryYUVA8<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImage.h"
#include "SkImageGenerator.h"
#include "SkNextID.h"
#include "SkYUVAIndex.h"

SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID)
    : fInfo(info)
    , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
{}

bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
    if (kUnknown_SkColorType == info.colorType()) {
        return false;
    }
    if (nullptr == pixels) {
        return false;
    }
    if (rowBytes < info.minRowBytes()) {
        return false;
    }

    Options defaultOpts;
    return this->onGetPixels(info, pixels, rowBytes, defaultOpts);
}

bool SkImageGenerator::queryYUVA8(SkYUVSizeInfo* sizeInfo,
                                  SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
                                  SkYUVColorSpace* colorSpace) const {
    SkASSERT(sizeInfo);

    if (!this->onQueryYUVA8(sizeInfo, yuvaIndices, colorSpace)) {
        // try the deprecated method and make a guess at the other data
        if (this->onQueryYUV8(sizeInfo, colorSpace)) {
            // take a guess at the number of planes
            int numPlanes = 3;  // onQueryYUV8 only supports up to 3 channels
            for (int i = 0; i < 3; ++i) {
                if (sizeInfo->fSizes[i].isEmpty()) {
                    numPlanes = i;
                    break;
                }
            }
            if (!numPlanes) {
                return false;
            }
            switch (numPlanes) {
                case 1:
                    // Assume 3 interleaved planes
                    sizeInfo->fColorTypes[0] = kRGBA_8888_SkColorType;
                    sizeInfo->fColorTypes[1] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kG;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kB;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
                case 2:
                    // Assume 1 Y plane and interleaved UV planes (NV12)
                    sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[1] = kRGBA_8888_SkColorType;
                    sizeInfo->fColorTypes[2] = kUnknown_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kG;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
                case 3:
                default:
                    // Assume 3 separate non-interleaved planes
                    sizeInfo->fColorTypes[0] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[1] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[2] = kAlpha_8_SkColorType;
                    sizeInfo->fColorTypes[3] = kUnknown_SkColorType;
                    yuvaIndices[SkYUVAIndex::kY_Index].fIndex = 0;
                    yuvaIndices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kU_Index].fIndex = 1;
                    yuvaIndices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kV_Index].fIndex = 2;
                    yuvaIndices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;
                    yuvaIndices[SkYUVAIndex::kA_Index].fIndex = -1;
                    yuvaIndices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
                    break;
            }

            return true;
        }

        return false;
    }

    return true;
}

bool SkImageGenerator::getYUVA8Planes(const SkYUVSizeInfo& sizeInfo,
                                      const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
                                      void* planes[SkYUVSizeInfo::kMaxCount]) {

    for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
        SkASSERT(sizeInfo.fSizes[i].fWidth >= 0);
        SkASSERT(sizeInfo.fSizes[i].fHeight >= 0);
        SkASSERT(sizeInfo.fWidthBytes[i] >= (size_t) sizeInfo.fSizes[i].fWidth);
    }

    int numPlanes = 0;
    SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
    SkASSERT(planes);
    for (int i = 0; i < numPlanes; ++i) {
        SkASSERT(planes[i]);
    }

    if (!this->onGetYUVA8Planes(sizeInfo, yuvaIndices, planes)) {
        return this->onGetYUV8Planes(sizeInfo, planes);
    }
    return true;
}

#if SK_SUPPORT_GPU
#include "GrTextureProxy.h"

sk_sp<GrTextureProxy> SkImageGenerator::generateTexture(GrContext* ctx, const SkImageInfo& info,
                                                        const SkIPoint& origin,
                                                        bool willNeedMipMaps) {
    SkIRect srcRect = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height());
    if (!SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(srcRect)) {
        return nullptr;
    }
    return this->onGenerateTexture(ctx, info, origin, willNeedMipMaps);
}

sk_sp<GrTextureProxy> SkImageGenerator::onGenerateTexture(GrContext*, const SkImageInfo&,
                                                          const SkIPoint&,
                                                          bool willNeedMipMaps) {
    return nullptr;
}
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////

#include "SkBitmap.h"
#include "SkColorTable.h"

#include "SkGraphics.h"

static SkGraphics::ImageGeneratorFromEncodedDataFactory gFactory;

SkGraphics::ImageGeneratorFromEncodedDataFactory
SkGraphics::SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory)
{
    ImageGeneratorFromEncodedDataFactory prev = gFactory;
    gFactory = factory;
    return prev;
}

std::unique_ptr<SkImageGenerator> SkImageGenerator::MakeFromEncoded(sk_sp<SkData> data) {
    if (!data) {
        return nullptr;
    }
    if (gFactory) {
        if (std::unique_ptr<SkImageGenerator> generator = gFactory(data)) {
            return generator;
        }
    }
    return SkImageGenerator::MakeFromEncodedImpl(std::move(data));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011  Timo Savola
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

#ifndef CONCRETE_OBJECTS_OBJECT_HPP
#define CONCRETE_OBJECTS_OBJECT_HPP

#include "object-decl.hpp"

#include <cassert>

#include <concrete/block.hpp>
#include <concrete/context.hpp>
#include <concrete/exception.hpp>
#include <concrete/objects/none-fwd.hpp>
#include <concrete/objects/string-decl.hpp>
#include <concrete/objects/type-decl.hpp>
#include <concrete/util/packed.hpp>

namespace concrete {

struct ObjectBlock: Block {
	struct NoRefcountInit {};

	PortableObject type_object;
	portable<int32_t> refcount;

	ObjectBlock(BlockId type_id, NoRefcountInit): type_object(type_id)
	{
	}

	ObjectBlock(const TypeObject &type): type_object(type), refcount(0)
	{
	}

	TypeObject type() const
	{
		// don't use cast<TypeObject>() because it causes an infinite recursion
		return TypeObject(type_object.id());
	}

	StringObject repr(BlockId id) const;

	static void Destroy(ObjectBlock *block) throw ();

} CONCRETE_PACKED;

template <typename Ops>
TypeObject object<Ops>::Type()
{
	return Context::Builtins().object_type;
}

template <typename Ops>
object<Ops> object<Ops>::New() throw (AllocError)
{
	auto id = Context::Alloc(sizeof (ObjectBlock));
	new (Context::Pointer(id)) ObjectBlock(Type());
	return object(id);
}

template <typename Ops>
object<Ops>::object(): m_raw_id(Ops::store(Context::None().id()))
{
	ref();
}

template <typename Ops> template <typename T>
bool object<Ops>::check() const
{
	return type() == T::Type();
}

template <typename Ops> template <typename T>
T object<Ops>::cast() const
{
	assert(check<T>());
	return T(id());
}

template <typename Ops> template <typename T>
T object<Ops>::require() const
{
	if (!check<T>())
		throw TypeError(type());

	return T(id());
}

template <typename Ops>
TypeObject object<Ops>::type() const
{
	return object_block()->type();
}

template <typename Ops>
StringObject object<Ops>::repr() const
{
	return object_block()->repr(id());
}

template <typename Ops>
void object<Ops>::ref() const
{
	auto block = object_block();
	block->refcount = block->refcount + 1;
}

template <typename Ops>
void object<Ops>::unref() const
{
	auto block = object_block();
	int refcount = block->refcount - 1;
	block->refcount = refcount;
	assert(refcount >= 0);
	if (refcount == 0)
		ObjectBlock::Destroy(block);
}

template <typename Ops>
ObjectBlock *object<Ops>::object_block() const
{
	return static_cast<ObjectBlock *> (Context::Pointer(id()));
}

} // namespace

#endif
<commit_msg>Object::check implemented using type_check<commit_after>/*
 * Copyright (c) 2011  Timo Savola
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

#ifndef CONCRETE_OBJECTS_OBJECT_HPP
#define CONCRETE_OBJECTS_OBJECT_HPP

#include "object-decl.hpp"

#include <cassert>

#include <concrete/block.hpp>
#include <concrete/context.hpp>
#include <concrete/exception.hpp>
#include <concrete/objects/none-fwd.hpp>
#include <concrete/objects/string-decl.hpp>
#include <concrete/objects/type-decl.hpp>
#include <concrete/util/packed.hpp>

namespace concrete {

struct ObjectBlock: Block {
	struct NoRefcountInit {};

	PortableObject type_object;
	portable<int32_t> refcount;

	ObjectBlock(BlockId type_id, NoRefcountInit): type_object(type_id)
	{
	}

	ObjectBlock(const TypeObject &type): type_object(type), refcount(0)
	{
	}

	TypeObject type() const
	{
		// don't use cast<TypeObject>() because it causes an infinite recursion
		return TypeObject(type_object.id());
	}

	StringObject repr(BlockId id) const;

	static void Destroy(ObjectBlock *block) throw ();

} CONCRETE_PACKED;

template <typename Ops>
TypeObject object<Ops>::Type()
{
	return Context::Builtins().object_type;
}

template <typename Ops>
object<Ops> object<Ops>::New() throw (AllocError)
{
	auto id = Context::Alloc(sizeof (ObjectBlock));
	new (Context::Pointer(id)) ObjectBlock(Type());
	return object(id);
}

template <typename Ops>
object<Ops>::object(): m_raw_id(Ops::store(Context::None().id()))
{
	ref();
}

template <typename Ops> template <typename T>
bool object<Ops>::check() const
{
	type_check<T> impl;
	return impl(type());
}

template <typename Ops> template <typename T>
T object<Ops>::cast() const
{
	assert(check<T>());
	return T(id());
}

template <typename Ops> template <typename T>
T object<Ops>::require() const
{
	if (!check<T>())
		throw TypeError(type());

	return T(id());
}

template <typename Ops>
TypeObject object<Ops>::type() const
{
	return object_block()->type();
}

template <typename Ops>
StringObject object<Ops>::repr() const
{
	return object_block()->repr(id());
}

template <typename Ops>
void object<Ops>::ref() const
{
	auto block = object_block();
	block->refcount = block->refcount + 1;
}

template <typename Ops>
void object<Ops>::unref() const
{
	auto block = object_block();
	int refcount = block->refcount - 1;
	block->refcount = refcount;
	assert(refcount >= 0);
	if (refcount == 0)
		ObjectBlock::Destroy(block);
}

template <typename Ops>
ObjectBlock *object<Ops>::object_block() const
{
	return static_cast<ObjectBlock *> (Context::Pointer(id()));
}

} // namespace

#endif
<|endoftext|>


<commit_before>/**************************************************************************\
 * The component that goes BOOM! (timed) area effects on contact/damage   *
 *                                               ___                      *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___     *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|    *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \    *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/    *
 *                |___/                              |_|                  *
 *                                                                        *
 * Copyright (c) 2014 Florian Oetke                                       *
 *                                                                        *
 *  This file is part of MagnumOpus and distributed under the MIT License *
 *  See LICENSE file for details.                                         *
\**************************************************************************/

#pragma once

#include <core/ecs/ecs.hpp>
#include <core/units.hpp>

namespace mo {
namespace sys {
namespace combat {

	class Explosive_comp : public ecs::Component<Explosive_comp> {
		public:
			static constexpr const char* name() {return "Explosive";}
			void load(ecs::Entity_state&)override;
			void store(ecs::Entity_state&)override;

			Explosive_comp(ecs::Entity& owner, float damage=10, Distance range=Distance(2),
						   Time delay=Time(0), bool on_contact=false, bool on_damage=false) noexcept
				: Component(owner), _damage(damage), _range(range), _delay(delay),
				  _activate_on_contact(on_contact), _activate_on_damage(on_damage) {}

			struct Persisted_state;
			friend struct Persisted_state;
		private:
			friend class Combat_system;

			float _damage;
			Distance _range;
			Time _delay;
			bool _activate_on_contact;
			bool _activate_on_damage;

			Time _delay_left = Time(0);
			bool _exloded = false;

			// TODO{foe]: add other effects
	};

}
}
}
<commit_msg>missing destructor<commit_after>/**************************************************************************\
 * The component that goes BOOM! (timed) area effects on contact/damage   *
 *                                               ___                      *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___     *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|    *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \    *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/    *
 *                |___/                              |_|                  *
 *                                                                        *
 * Copyright (c) 2014 Florian Oetke                                       *
 *                                                                        *
 *  This file is part of MagnumOpus and distributed under the MIT License *
 *  See LICENSE file for details.                                         *
\**************************************************************************/

#pragma once

#include <core/ecs/ecs.hpp>
#include <core/units.hpp>

namespace mo {
namespace sys {
namespace combat {

	class Explosive_comp : public ecs::Component<Explosive_comp> {
		public:
			static constexpr const char* name() {return "Explosive";}
			void load(ecs::Entity_state&)override;
			void store(ecs::Entity_state&)override;

			Explosive_comp(ecs::Entity& owner, float damage=10, Distance range=Distance(2),
						   Time delay=Time(0), bool on_contact=false, bool on_damage=false) noexcept
				: Component(owner), _damage(damage), _range(range), _delay(delay),
				  _activate_on_contact(on_contact), _activate_on_damage(on_damage) {}
			Explosive_comp(Explosive_comp&&)noexcept = default;
			~Explosive_comp()noexcept = default;
			Explosive_comp& operator=(Explosive_comp&&)noexcept = default;

			struct Persisted_state;
			friend struct Persisted_state;
		private:
			friend class Combat_system;

			float _damage;
			Distance _range;
			Time _delay;
			bool _activate_on_contact;
			bool _activate_on_damage;

			Time _delay_left = Time(0);
			bool _exloded = false;

			// TODO{foe]: add other effects
	};

}
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016, The Monero Project
//
// 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers

#include <sstream>
#include <numeric>
#include <boost/utility/value_init.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/limits.hpp>
#include <boost/foreach.hpp>
#include "misc_language.h"
#include "include_base_utils.h"
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
#include "file_io_utils.h"
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"

using namespace epee;

#include "miner.h"

extern "C" void slow_hash_allocate_state();
extern "C" void slow_hash_free_state();
namespace cryptonote
{

  namespace
  {
    const command_line::arg_descriptor<std::string> arg_extra_messages =  {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
    const command_line::arg_descriptor<std::string> arg_start_mining =    {"start-mining", "Specify wallet address to mining for", "", true};
    const command_line::arg_descriptor<uint32_t>      arg_mining_threads =  {"mining-threads", "Specify mining threads count", 0, true};
  }

  miner::miner(i_miner_handler* phandler):m_stop(1),
    m_template(boost::value_initialized<block>()),
    m_template_no(0),
    m_diffic(0),
    m_thread_index(0),
    m_phandler(phandler),
    m_height(0),
    m_pausers_count(0),
    m_threads_total(0),
    m_starter_nonce(0),
    m_last_hr_merge_time(0),
    m_hashes(0),
    m_do_print_hashrate(false),
    m_do_mining(false),
    m_current_hash_rate(0)
  {

  }
  //-----------------------------------------------------------------------------------------------------
  miner::~miner()
  {
    stop();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
  {
    CRITICAL_REGION_LOCAL(m_template_lock);
    m_template = bl;
    m_diffic = di;
    m_height = height;
    ++m_template_no;
    m_starter_nonce = crypto::rand<uint32_t>();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_block_chain_update()
  {
    if(!is_mining())
      return true;

    return request_block_template();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::request_block_template()
  {
    block bl = AUTO_VAL_INIT(bl);
    difficulty_type di = AUTO_VAL_INIT(di);
    uint64_t height = AUTO_VAL_INIT(height);
    cryptonote::blobdata extra_nonce;
    if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
    {
      extra_nonce = m_extra_messages[m_config.current_extra_message_index];
    }

    if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
    {
      LOG_ERROR("Failed to get_block_template(), stopping mining");
      return false;
    }
    set_block_template(bl, di, height);
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_idle()
  {
    m_update_block_template_interval.do_call([&](){
      if(is_mining())request_block_template();
      return true;
    });

    m_update_merge_hr_interval.do_call([&](){
      merge_hr();
      return true;
    });

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::do_print_hashrate(bool do_hr)
  {
    m_do_print_hashrate = do_hr;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::merge_hr()
  {
    if(m_last_hr_merge_time && is_mining())
    {
      m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
      CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
      m_last_hash_rates.push_back(m_current_hash_rate);
      if(m_last_hash_rates.size() > 19)
        m_last_hash_rates.pop_front();
      if(m_do_print_hashrate)
      {
        uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
        float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
        std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
      }
    }
    m_last_hr_merge_time = misc_utils::get_tick_count();
    m_hashes = 0;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::init_options(boost::program_options::options_description& desc)
  {
    command_line::add_arg(desc, arg_extra_messages);
    command_line::add_arg(desc, arg_start_mining);
    command_line::add_arg(desc, arg_mining_threads);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::init(const boost::program_options::variables_map& vm, bool testnet)
  {
    if(command_line::has_arg(vm, arg_extra_messages))
    {
      std::string buff;
      bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
      CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
      std::vector<std::string> extra_vec;
      boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
      m_extra_messages.resize(extra_vec.size());
      for(size_t i = 0; i != extra_vec.size(); i++)
      {
        string_tools::trim(extra_vec[i]);
        if(!extra_vec[i].size())
          continue;
        std::string buff = string_encoding::base64_decode(extra_vec[i]);
        if(buff != "0")
          m_extra_messages[i] = buff;
      }
      m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
      m_config = AUTO_VAL_INIT(m_config);
      epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
      LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
    }

    if(command_line::has_arg(vm, arg_start_mining))
    {
      if(!cryptonote::get_account_address_from_str(m_mine_address, testnet, command_line::get_arg(vm, arg_start_mining)))
      {
        LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
        return false;
      }
      m_threads_total = 1;
      m_do_mining = true;
      if(command_line::has_arg(vm, arg_mining_threads))
      {
        m_threads_total = command_line::get_arg(vm, arg_mining_threads);
      }
    }

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::is_mining() const
  {
    return !m_stop;
  }
  //-----------------------------------------------------------------------------------------------------
  const account_public_address& miner::get_mining_address() const
  {
    return m_mine_address;
  }
  //-----------------------------------------------------------------------------------------------------
  uint32_t miner::get_threads_count() const {
    return m_threads_total;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
  {
    m_mine_address = adr;
    m_threads_total = static_cast<uint32_t>(threads_count);
    m_starter_nonce = crypto::rand<uint32_t>();
    CRITICAL_REGION_LOCAL(m_threads_lock);
    if(is_mining())
    {
      LOG_ERROR("Starting miner but it's already started");
      return false;
    }

    if(!m_threads.empty())
    {
      LOG_ERROR("Unable to start miner because there are active mining threads");
      return false;
    }

    if(!m_template_no)
      request_block_template();//lets update block template

    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
    boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);

    for(size_t i = 0; i != threads_count; i++)
    {
      m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
    }

    LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" );
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  uint64_t miner::get_speed() const
  {
    if(is_mining()) {
      return m_current_hash_rate;
    }
    else {
      return 0;
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::send_stop_signal()
  {
    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::stop()
  {
    if (!is_mining())
      return true;

    send_stop_signal();
    CRITICAL_REGION_LOCAL(m_threads_lock);

    BOOST_FOREACH(boost::thread& th, m_threads)
      th.join();

    LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" );
    m_threads.clear();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
  {
    for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
    {
      crypto::hash h;
      get_block_longhash(bl, h, height);

      if(check_hash(h, diffic))
      {
        return true;
      }
    }
    return false;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::on_synchronized()
  {
    if(m_do_mining)
    {
      boost::thread::attributes attrs;
      attrs.set_stack_size(THREAD_STACK_SIZE);

      start(m_mine_address, m_threads_total, attrs);
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::pause()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    ++m_pausers_count;
    if(m_pausers_count == 1 && is_mining())
      LOG_PRINT_L2("MINING PAUSED");
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::resume()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    --m_pausers_count;
    if(m_pausers_count < 0)
    {
      m_pausers_count = 0;
      LOG_PRINT_RED_L0("Unexpected miner::resume() called");
    }
    if(!m_pausers_count && is_mining())
      LOG_PRINT_L2("MINING RESUMED");
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::worker_thread()
  {
    uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
    LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
    log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
    uint32_t nonce = m_starter_nonce + th_local_index;
    uint64_t height = 0;
    difficulty_type local_diff = 0;
    uint32_t local_template_ver = 0;
    block b;
    slow_hash_allocate_state();
    while(!m_stop)
    {
      if(m_pausers_count)//anti split workaround
      {
        misc_utils::sleep_no_w(100);
        continue;
      }

      if(local_template_ver != m_template_no)
      {
        CRITICAL_REGION_BEGIN(m_template_lock);
        b = m_template;
        local_diff = m_diffic;
        height = m_height;
        CRITICAL_REGION_END();
        local_template_ver = m_template_no;
        nonce = m_starter_nonce + th_local_index;
      }

      if(!local_template_ver)//no any set_block_template call
      {
        LOG_PRINT_L2("Block template not set yet");
        epee::misc_utils::sleep_no_w(1000);
        continue;
      }

      b.nonce = nonce;
      crypto::hash h;
      get_block_longhash(b, h, height);

      if(check_hash(h, local_diff))
      {
        //we lucky!
        ++m_config.current_extra_message_index;
        LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0);
        if(!m_phandler->handle_block_found(b))
        {
          --m_config.current_extra_message_index;
        }else
        {
          //success update, lets update config
          epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
        }
      }
      nonce+=m_threads_total;
      ++m_hashes;
    }
    slow_hash_free_state();
    LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]");
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
}

<commit_msg>miner: do not try to save config if the path isn't set<commit_after>// Copyright (c) 2014-2016, The Monero Project
//
// 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers

#include <sstream>
#include <numeric>
#include <boost/utility/value_init.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/limits.hpp>
#include <boost/foreach.hpp>
#include "misc_language.h"
#include "include_base_utils.h"
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
#include "file_io_utils.h"
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"

using namespace epee;

#include "miner.h"

extern "C" void slow_hash_allocate_state();
extern "C" void slow_hash_free_state();
namespace cryptonote
{

  namespace
  {
    const command_line::arg_descriptor<std::string> arg_extra_messages =  {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
    const command_line::arg_descriptor<std::string> arg_start_mining =    {"start-mining", "Specify wallet address to mining for", "", true};
    const command_line::arg_descriptor<uint32_t>      arg_mining_threads =  {"mining-threads", "Specify mining threads count", 0, true};
  }

  miner::miner(i_miner_handler* phandler):m_stop(1),
    m_template(boost::value_initialized<block>()),
    m_template_no(0),
    m_diffic(0),
    m_thread_index(0),
    m_phandler(phandler),
    m_height(0),
    m_pausers_count(0),
    m_threads_total(0),
    m_starter_nonce(0),
    m_last_hr_merge_time(0),
    m_hashes(0),
    m_do_print_hashrate(false),
    m_do_mining(false),
    m_current_hash_rate(0)
  {

  }
  //-----------------------------------------------------------------------------------------------------
  miner::~miner()
  {
    stop();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
  {
    CRITICAL_REGION_LOCAL(m_template_lock);
    m_template = bl;
    m_diffic = di;
    m_height = height;
    ++m_template_no;
    m_starter_nonce = crypto::rand<uint32_t>();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_block_chain_update()
  {
    if(!is_mining())
      return true;

    return request_block_template();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::request_block_template()
  {
    block bl = AUTO_VAL_INIT(bl);
    difficulty_type di = AUTO_VAL_INIT(di);
    uint64_t height = AUTO_VAL_INIT(height);
    cryptonote::blobdata extra_nonce;
    if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
    {
      extra_nonce = m_extra_messages[m_config.current_extra_message_index];
    }

    if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
    {
      LOG_ERROR("Failed to get_block_template(), stopping mining");
      return false;
    }
    set_block_template(bl, di, height);
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_idle()
  {
    m_update_block_template_interval.do_call([&](){
      if(is_mining())request_block_template();
      return true;
    });

    m_update_merge_hr_interval.do_call([&](){
      merge_hr();
      return true;
    });

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::do_print_hashrate(bool do_hr)
  {
    m_do_print_hashrate = do_hr;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::merge_hr()
  {
    if(m_last_hr_merge_time && is_mining())
    {
      m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
      CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
      m_last_hash_rates.push_back(m_current_hash_rate);
      if(m_last_hash_rates.size() > 19)
        m_last_hash_rates.pop_front();
      if(m_do_print_hashrate)
      {
        uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
        float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
        std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
      }
    }
    m_last_hr_merge_time = misc_utils::get_tick_count();
    m_hashes = 0;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::init_options(boost::program_options::options_description& desc)
  {
    command_line::add_arg(desc, arg_extra_messages);
    command_line::add_arg(desc, arg_start_mining);
    command_line::add_arg(desc, arg_mining_threads);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::init(const boost::program_options::variables_map& vm, bool testnet)
  {
    if(command_line::has_arg(vm, arg_extra_messages))
    {
      std::string buff;
      bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
      CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
      std::vector<std::string> extra_vec;
      boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
      m_extra_messages.resize(extra_vec.size());
      for(size_t i = 0; i != extra_vec.size(); i++)
      {
        string_tools::trim(extra_vec[i]);
        if(!extra_vec[i].size())
          continue;
        std::string buff = string_encoding::base64_decode(extra_vec[i]);
        if(buff != "0")
          m_extra_messages[i] = buff;
      }
      m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
      m_config = AUTO_VAL_INIT(m_config);
      epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
      LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
    }

    if(command_line::has_arg(vm, arg_start_mining))
    {
      if(!cryptonote::get_account_address_from_str(m_mine_address, testnet, command_line::get_arg(vm, arg_start_mining)))
      {
        LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
        return false;
      }
      m_threads_total = 1;
      m_do_mining = true;
      if(command_line::has_arg(vm, arg_mining_threads))
      {
        m_threads_total = command_line::get_arg(vm, arg_mining_threads);
      }
    }

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::is_mining() const
  {
    return !m_stop;
  }
  //-----------------------------------------------------------------------------------------------------
  const account_public_address& miner::get_mining_address() const
  {
    return m_mine_address;
  }
  //-----------------------------------------------------------------------------------------------------
  uint32_t miner::get_threads_count() const {
    return m_threads_total;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
  {
    m_mine_address = adr;
    m_threads_total = static_cast<uint32_t>(threads_count);
    m_starter_nonce = crypto::rand<uint32_t>();
    CRITICAL_REGION_LOCAL(m_threads_lock);
    if(is_mining())
    {
      LOG_ERROR("Starting miner but it's already started");
      return false;
    }

    if(!m_threads.empty())
    {
      LOG_ERROR("Unable to start miner because there are active mining threads");
      return false;
    }

    if(!m_template_no)
      request_block_template();//lets update block template

    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
    boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);

    for(size_t i = 0; i != threads_count; i++)
    {
      m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
    }

    LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" );
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  uint64_t miner::get_speed() const
  {
    if(is_mining()) {
      return m_current_hash_rate;
    }
    else {
      return 0;
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::send_stop_signal()
  {
    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::stop()
  {
    if (!is_mining())
      return true;

    send_stop_signal();
    CRITICAL_REGION_LOCAL(m_threads_lock);

    BOOST_FOREACH(boost::thread& th, m_threads)
      th.join();

    LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" );
    m_threads.clear();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
  {
    for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
    {
      crypto::hash h;
      get_block_longhash(bl, h, height);

      if(check_hash(h, diffic))
      {
        return true;
      }
    }
    return false;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::on_synchronized()
  {
    if(m_do_mining)
    {
      boost::thread::attributes attrs;
      attrs.set_stack_size(THREAD_STACK_SIZE);

      start(m_mine_address, m_threads_total, attrs);
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::pause()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    ++m_pausers_count;
    if(m_pausers_count == 1 && is_mining())
      LOG_PRINT_L2("MINING PAUSED");
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::resume()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    --m_pausers_count;
    if(m_pausers_count < 0)
    {
      m_pausers_count = 0;
      LOG_PRINT_RED_L0("Unexpected miner::resume() called");
    }
    if(!m_pausers_count && is_mining())
      LOG_PRINT_L2("MINING RESUMED");
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::worker_thread()
  {
    uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
    LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
    log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
    uint32_t nonce = m_starter_nonce + th_local_index;
    uint64_t height = 0;
    difficulty_type local_diff = 0;
    uint32_t local_template_ver = 0;
    block b;
    slow_hash_allocate_state();
    while(!m_stop)
    {
      if(m_pausers_count)//anti split workaround
      {
        misc_utils::sleep_no_w(100);
        continue;
      }

      if(local_template_ver != m_template_no)
      {
        CRITICAL_REGION_BEGIN(m_template_lock);
        b = m_template;
        local_diff = m_diffic;
        height = m_height;
        CRITICAL_REGION_END();
        local_template_ver = m_template_no;
        nonce = m_starter_nonce + th_local_index;
      }

      if(!local_template_ver)//no any set_block_template call
      {
        LOG_PRINT_L2("Block template not set yet");
        epee::misc_utils::sleep_no_w(1000);
        continue;
      }

      b.nonce = nonce;
      crypto::hash h;
      get_block_longhash(b, h, height);

      if(check_hash(h, local_diff))
      {
        //we lucky!
        ++m_config.current_extra_message_index;
        LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0);
        if(!m_phandler->handle_block_found(b))
        {
          --m_config.current_extra_message_index;
        }else
        {
          //success update, lets update config
          if (!m_config_folder_path.empty())
            epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
        }
      }
      nonce+=m_threads_total;
      ++m_hashes;
    }
    slow_hash_free_state();
    LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]");
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
}

<|endoftext|>


<commit_before>/*
     This file is part of libhttpserver
     Copyright (C) 2011, 2012, 2013, 2014, 2015 Sebastiano Merlino

     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
     License as published by the Free Software Foundation; either
     version 2.1 of the License, or (at your option) any later version.

     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 Street, Fifth Floor, Boston, MA  02110-1301
     USA
*/

#include "details/http_endpoint.hpp"
#include "http_utils.hpp"
#include "string_utilities.hpp"

using namespace std;

namespace httpserver
{

using namespace http;

namespace details
{

http_endpoint::~http_endpoint()
{
    if(reg_compiled)
    {
        regfree(&(this->re_url_modded));
    }
}

http_endpoint::http_endpoint
(
    const string& url,
    bool family,
    bool registration,
    bool use_regex
):
    family_url(family),
    reg_compiled(false)
{
    if(use_regex)
        this->url_modded = "^/";
    else
        this->url_modded = "/";
    vector<string> parts;

#ifdef CASE_INSENSITIVE
    string_utilities::to_lower_copy(url, url_complete);
#else
    url_complete = url;
#endif

    if(url_complete[0] != '/')
        url_complete = "/" + url_complete;

    http_utils::tokenize_url(url, parts);
    string buffered;
    bool first = true;
    if(registration)
    {
        for(unsigned int i = 0; i< parts.size(); i++)
        {
            if((parts[i] != "") && (parts[i][0] != '{'))
            {
                if(first)
                {
                    if(parts[i][0] == '^')
                    {
                        this->url_modded = parts[i];
                    }
                    else
                    {
                        this->url_modded += parts[i];
                    }
                    first = false;
                }
                else
                {
                    this->url_modded += "/" + parts[i];
                }
            }
            else
            {
                if(
                    (parts[i].size() >= 3) &&
                    (parts[i][0] == '{') &&
                    (parts[i][parts[i].size() - 1] == '}')
                )
                {
                    std::string::size_type bar = parts[i].find_first_of('|');
                    if(bar != string::npos)
                    {
                        this->url_pars.push_back(parts[i].substr(1, bar - 1));
                        if(first)
                        {
                            this->url_modded += parts[i].substr(
                                    bar + 1, parts[i].size() - bar - 2
                            );
                            first = false;
                        }
                        else
                        {
                            this->url_modded += "/"+parts[i].substr(
                                    bar + 1, parts[i].size() - bar - 2
                            );
                        }
                    }
                    else
                    {
                        this->url_pars.push_back(
                                parts[i].substr(1,parts[i].size() - 2)
                        );
                        if(first)
                        {
                            this->url_modded += "([^\\/]+)";
                            first = false;
                        }
                        else
                        {
                            this->url_modded += "/([^\\/]+)";
                        }
                    }
                    this->chunk_positions.push_back(i);
                }
                else
                {
                    throw bad_http_endpoint();
                }
            }
            this->url_pieces.push_back(parts[i]);
        }
    }
    else
    {
        for(unsigned int i = 0; i< parts.size(); i++)
        {
            if(first)
            {
                this->url_modded += parts[i];
                first = false;
            }
            else
            {
                this->url_modded += "/" + parts[i];
            }
            this->url_pieces.push_back(parts[i]);
        }
    }
    if(use_regex)
    {
        this->url_modded += "$";
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
        reg_compiled = true;
    }
}

http_endpoint::http_endpoint(const http_endpoint& h):
    url_complete(h.url_complete),
    url_modded(h.url_modded),
    url_pars(h.url_pars),
    url_pieces(h.url_pieces),
    chunk_positions(h.chunk_positions),
    family_url(h.family_url),
    reg_compiled(h.reg_compiled)
{
    if(this->reg_compiled)
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
}

http_endpoint& http_endpoint::operator =(const http_endpoint& h)
{
    this->url_complete = h.url_complete;
    this->url_modded = h.url_modded;
    this->family_url = h.family_url;
    this->reg_compiled = h.reg_compiled;
    if(this->reg_compiled)
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
    this->url_pars = h.url_pars;
    this->url_pieces = h.url_pieces;
    this->chunk_positions = h.chunk_positions;
    return *this;
}

bool http_endpoint::operator <(const http_endpoint& b) const
{
    COMPARATOR(this->url_modded, b.url_modded, std::toupper);
}

bool http_endpoint::match(const http_endpoint& url) const
{
    if(this->family_url && (url.url_pieces.size() >= this->url_pieces.size()))
    {
        string nn = "/";
        bool first = true;
        for(unsigned int i = 0; i < this->url_pieces.size(); i++)
        {
            if(first)
            {
                nn += url.url_pieces[i];
                first = false;
            }
            else
            {
                nn += "/" + url.url_pieces[i];
            }
        }
        return regexec(&(this->re_url_modded), nn.c_str(), 0, NULL, 0) == 0;
    }
    else
        return regexec(&(this->re_url_modded),
                url.url_complete.c_str(), 0, NULL, 0) == 0;
}

};

};
<commit_msg>Linearized code to make it more readable<commit_after>/*
     This file is part of libhttpserver
     Copyright (C) 2011, 2012, 2013, 2014, 2015 Sebastiano Merlino

     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
     License as published by the Free Software Foundation; either
     version 2.1 of the License, or (at your option) any later version.

     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 Street, Fifth Floor, Boston, MA  02110-1301
     USA
*/

#include "details/http_endpoint.hpp"
#include "http_utils.hpp"
#include "string_utilities.hpp"

using namespace std;

namespace httpserver
{

using namespace http;

namespace details
{

http_endpoint::~http_endpoint()
{
    if(reg_compiled)
    {
        regfree(&(this->re_url_modded));
    }
}

http_endpoint::http_endpoint
(
    const string& url,
    bool family,
    bool registration,
    bool use_regex
):
    family_url(family),
    reg_compiled(false)
{
    this->url_modded = use_regex ? "^/" : "/";
    vector<string> parts;

#ifdef CASE_INSENSITIVE
    string_utilities::to_lower_copy(url, url_complete);
#else
    url_complete = url;
#endif

    if(url_complete[0] != '/')
        url_complete = "/" + url_complete;

    http_utils::tokenize_url(url, parts);
    string buffered;
    bool first = true;

    for (unsigned int i = 0; i < parts.size(); i++)
    {
        if(!registration)
        {
            this->url_modded += (first ? "" : "/") + parts[i];
            first = false;

            this->url_pieces.push_back(parts[i]);

            continue;
        }

        if((parts[i] != "") && (parts[i][0] != '{'))
        {
            this->url_modded = (first ? "" : "/") + (parts[i][0] == '^' ? "" : this->url_modded) + parts[i];
            first = false;
            this->url_pieces.push_back(parts[i]);

            continue;
        }

        if((parts[i].size() < 3) || (parts[i][0] != '{') || (parts[i][parts[i].size() - 1] != '}'))
            throw bad_http_endpoint();

        std::string::size_type bar = parts[i].find_first_of('|');
        this->url_pars.push_back(parts[i].substr(1, bar != string::npos ? bar - 1 : parts[i].size() - bar - 2));
        this->url_modded += (first ? "" : "/") + (bar != string::npos ? parts[i].substr(bar + 1, parts[i].size() - bar - 2) : "([^\\/]+)");

        first = false;

        this->chunk_positions.push_back(i);

        this->url_pieces.push_back(parts[i]);
    }

    if(use_regex)
    {
        this->url_modded += "$";
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
        this->reg_compiled = true;
    }
}

http_endpoint::http_endpoint(const http_endpoint& h):
    url_complete(h.url_complete),
    url_modded(h.url_modded),
    url_pars(h.url_pars),
    url_pieces(h.url_pieces),
    chunk_positions(h.chunk_positions),
    family_url(h.family_url),
    reg_compiled(h.reg_compiled)
{
    if(this->reg_compiled)
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
}

http_endpoint& http_endpoint::operator =(const http_endpoint& h)
{
    this->url_complete = h.url_complete;
    this->url_modded = h.url_modded;
    this->family_url = h.family_url;
    this->reg_compiled = h.reg_compiled;
    if(this->reg_compiled)
        regcomp(&(this->re_url_modded), url_modded.c_str(),
                REG_EXTENDED|REG_ICASE|REG_NOSUB
        );
    this->url_pars = h.url_pars;
    this->url_pieces = h.url_pieces;
    this->chunk_positions = h.chunk_positions;
    return *this;
}

bool http_endpoint::operator <(const http_endpoint& b) const
{
    COMPARATOR(this->url_modded, b.url_modded, std::toupper);
}

bool http_endpoint::match(const http_endpoint& url) const
{

    if(!this->family_url || url.url_pieces.size() < this->url_pieces.size())
        return regexec(&(this->re_url_modded), url.url_complete.c_str(), 0, NULL, 0) == 0;

    string nn = "/";
    bool first = true;
    for(unsigned int i = 0; i < this->url_pieces.size(); i++)
    {
        nn += (first ? "" : "/") + url.url_pieces[i];
        first = false;
    }
    return regexec(&(this->re_url_modded), nn.c_str(), 0, NULL, 0) == 0;
}

};

};
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>

#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>

#include <string>
#include <map>
#include <sstream>

#include <ext/hash_map>
namespace ext = __gnu_cxx;

typedef std::map< std::string, std::string > AttributeValueMap;
typedef bool (*ActionHandler)( AttributeValueMap & avm, std::string & reply );
typedef std::map< std::string, ActionHandler > ActionToHandlerMap;

/*
 * The GAHP uses the following functions from the Query API:
 *
 *      RunInstances
 *      TerminateInstances
 *      DescribeInstances
 *      CreateKeyPair
 *      DeleteKeyPair
 *      DescribeKeyPairs
 */

/*
 * Inexplicably, this isn't one of the standard specializations.
 * Even less explicably, you can't use namespace aliases to open a namespace.
 *
 * However, by supplying this specialization, all of the ext::hash_maps using
 * std::string as a key work without further ado.
 */

namespace __gnu_cxx {
    template<> struct hash< std::string > {
        size_t operator()( const std::string & s ) const {
            return __stl_hash_string( s.c_str() );
        }
    };
}

typedef struct {
} Group;
typedef ext::hash_map< std::string, Group > NameToGroupMap;

typedef struct {
    std::string privateKey;
} Keypair;
typedef ext::hash_map< std::string, Keypair > NameToKeypairMap;

typedef struct {
    std::string imageID;
    std::string privateDNSName;
    std::string publicDNSName;
    std::string instanceType;
    std::string instanceState;
    std::string keyName;

    ext::hash_map< std::string, const Group * > groups;
} Instance;
typedef ext::hash_map< std::string, Instance > InstanceIDToInstanceMap;

typedef struct {
    NameToKeypairMap keypairs;
    NameToGroupMap groups;
    InstanceIDToInstanceMap instances;
} User;
typedef ext::hash_map< std::string, User > AccessKeyIDToUserMap;

// Global.  Eww.
AccessKeyIDToUserMap users;

void registerTestUsers() {
    users[ "1" ] = User();
    users[ "2" ] = User();
}

// The compiler seems unwilling or unable to infer return types; GregT
// speculated that this might be because templated functions are in their
// own namespace, but getObject<>() doesn't infer the return type, either.
template< class V, class T, class K > V getObject( const T & map, const K & key, bool & found ) {
    class T::const_iterator ci = map.find( key );
    if( map.end() == ci ) {
        found = false;
        return V();
    }
    found = true;
    return ci->second;
}

bool handleRunInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleRunInstances()\n" );
    return false;
}

bool handleTerminateInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleTerminateInstances()\n" );

    bool found = false;
    std::string userID = getObject< std::string >( avm, "AWSAccessKeyId", found );
    if( (!found) || userID.empty() ) {
        fprintf( stderr, "DEBUG: failed to find AWSAccessKeyId in query.\n" );
        reply = "Required parameter AWSAccessKeyId missing or empty.\n";
        return false;
    }

    User user = getObject< User >( users, userID, found );
    if( ! found ) {
        fprintf( stderr, "Failed to find user identified by '%s'.\n", userID.c_str() );
        reply = "Required parameter ASWAccessKeyId invalid.\n";
        return false;
    }

    std::string instanceID = getObject< std::string >( avm, "InstanceId.1", found );
    if( ! found || instanceID.empty() ) {
        fprintf( stderr, "DEBUG: failed to find instanceID in query.\n" );
        reply = "Required parameter InstanceId.1 missing or empty.\n";
        return false;
    }

    Instance instance = getObject< Instance >( user.instances, instanceID, found );
    if( ! found ) {
        std::ostringstream error;
        error << "Instance ID '" << instanceID << "' does not exist." << std::endl;
        fprintf( stderr, "%s", error.str().c_str() );
        reply = error.str();
        return false;
    }

    // FIXME...
    return false;
}

bool handleDescribeInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDescribeInstances()\n" );
    return false;
}

bool handleCreateKeyPair( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleCreateKeyPair()\n" );
    return false;
}

bool handleDeleteKeyPair( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDeleteKeyPair()\n" );
    return false;
}

bool handleDescribeKeyPairs( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDescribeKeyPairs()\n" );
    return false;
}

// Global.  Eww.
ActionToHandlerMap simulatorActions;

void registerAllHandlers() {
    simulatorActions[ "RunInstances" ] = & handleRunInstances;
    simulatorActions[ "TerminateInstances" ] = & handleTerminateInstances;
    simulatorActions[ "DescribeInstances" ] = & handleDescribeInstances;
    simulatorActions[ "CreateKeyPair" ] = & handleCreateKeyPair;
    simulatorActions[ "DeleteKeyPair" ] = & handleDeleteKeyPair;
    simulatorActions[ "DescribeKeyPairs" ] = & handleDescribeKeyPairs;
}

// m/^Host: <host>\r\n/
bool extractHost( const std::string & request, std::string & host ) {
    std::string::size_type i = request.find( "\r\nHost: " );
    if( std::string::npos == i ) {
        fprintf( stderr, "Malformed request '%s': contains no Host header; failing.\n", request.c_str() );
        return false;
    }

    std::string::size_type j = request.find( "\r\n", i + 2 );
    if( std::string::npos == j ) {
        fprintf( stderr, "Malformed request '%s': Host field not CR/LF terminated; failing.\n", request.c_str() );
        return false;
    }

    host = request.substr( i + 8, j - (i + 8)  );
    return true;
}

// m/^GET <URL> HTTP/
bool extractURL( const std::string & request, std::string & URL ) {
    if( request.find( "GET " ) != 0 ) {
        fprintf( stderr, "Malformed request '%s': did not begin with 'GET '; failing.\n", request.c_str() );
        return false;
    }

    URL = request.substr( 4, request.find( "HTTP" ) - 5 );
    return true;
}

/*
 * The most fragile part of the EC2 GAHP is the query signing, so
 * we'd like to validate it.  See the comments in amazonCommands.cpp
 * for more details.
 *
 * This function is presently a stub because I haven't solved the
 * problem of key distribution between the tester and the simulator.
 */
bool validateSignature( std::string & method,
                        const std::string & host,
                        const std::string & URL,
                        const AttributeValueMap & queryParameters ) {
    return true;
}

std::string constructReply( const std::string & statusLine, const std::string & response ) {
    std::ostringstream reply;

    // The ec2_gahp doesn't ever look at the headers.
    reply << statusLine << "\r\n";
    reply << "Content-Length: " << response.size() << "\r\n";
    reply << "\r\n";
    reply << response;
    reply << "\r\n";

    return reply.str();
}

std::string handleRequest( const std::string & request ) {
    std::string URL;
    if( ! extractURL( request, URL ) ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "" );
    }

    std::string host;
    if( ! extractHost( request, host ) ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "" );
    }
    std::transform( host.begin(), host.end(), host.begin(), & tolower );

    // fprintf( stderr, "DEBUG: found 'http://%s%s'\n", host.c_str(), URL.c_str() );

    AttributeValueMap queryParameters;
    std::string::size_type i = URL.find( "?" );
    while( i < URL.size() ) {
        // Properly encoded URLs will only have ampersands between
        // the key-value pairs, and equals between keys and values.
        std::string::size_type equalsIdx = URL.find( "=", i + 1 );
        if( std::string::npos == equalsIdx ) {
            std::ostringstream error;
            error << "Malformed URL '" << URL << "': attribute without value; failing" << std::endl;
            fprintf( stderr, error.str().c_str() );
            return constructReply( "HTTP/1.1 400 Bad Request", error.str() );
        }
        std::string::size_type ampersandIdx = URL.find( "&", i + 1 );
        if( std::string::npos == ampersandIdx ) {
            ampersandIdx = URL.size();
        }

        std::string key = URL.substr( i + 1, equalsIdx - (i + 1) );
        std::string value = URL.substr( equalsIdx + 1, ampersandIdx - (equalsIdx + 1 ) );
        // fprintf( stderr, "DEBUG: key = '%s', value = '%s'\n", key.c_str(), value.c_str() );
        queryParameters[ key ] = value;

        i = ampersandIdx;
    }

    std::string method = "GET";
    if( ! validateSignature( method, host, URL, queryParameters ) ) {
        return constructReply( "HTTP/1.1 401 Unauthorized", "Failed signature validation." );
    }

    std::string action = queryParameters[ "Action" ];
    if( action.empty() ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "No action specified." );
    }

    std::string response;
    ActionToHandlerMap::const_iterator ci = simulatorActions.find( action );
    if( simulatorActions.end() == ci ) {
        std::ostringstream error;
        error << "Action '" << action << "' not found." << std::endl;
        fprintf( stderr, error.str().c_str() );
        return constructReply( "HTTP/1.1 404 Not Found", error.str() );
    }

    if( (*(ci->second))( queryParameters, response ) ) {
        return constructReply( "HTTP/1.1 200 OK", response );
    } else {
        return constructReply( "HTTP/1.1 406 Not Acceptable", response );
    }
}

void handleConnection( int sockfd ) {
    ssize_t bytesRead;
    char buffer[1024+1];
    std::string request;

    while( 1 ) {
        bytesRead = read( sockfd, (void *) buffer, 1024 );

        if( bytesRead == -1 ) {
            if( errno == EINTR ) {
                fprintf( stderr, "read() interrupted, retrying.\n" );
                continue;
            }
            fprintf( stderr, "read() failed (%d): '%s'\n", errno, strerror( errno ) );
            return;
        }

        if( bytesRead == 0 ) {
            close( sockfd );
            return;
        }

        buffer[bytesRead] = '\0';
        request += buffer;
        // fprintf( stderr, "DEBUG: request is now '%s'.\n", request.c_str() );

        // A given HTTP request is terminated by a blank line.
        std::string::size_type index = request.find( "\r\n\r\n" );
        while( index != std::string::npos ) {
            std::string firstRequest = request.substr( 0, index + 4 );
            request = request.substr( index + 4 );
            // if( ! request.empty() ) { fprintf( stderr, "DEBUG: request remainder '%s'\n", request.c_str() ); }

            // fprintf( stderr, "DEBUG: handling request '%s'\n", firstRequest.c_str() );
            std::string reply = handleRequest( firstRequest );
            if( ! reply.empty() ) {
                // fprintf( stderr, "DEBUG: writing reply '%s'\n", reply.c_str() );
                ssize_t totalBytesWritten = 0;
                ssize_t bytesToWrite = reply.size();
                const char * outBuf = reply.c_str();
                while( totalBytesWritten != bytesToWrite ) {
                    ssize_t bytesWritten = write( sockfd,
                        outBuf + totalBytesWritten,
                        bytesToWrite - totalBytesWritten );
                    if( bytesWritten == -1 ) {
                        fprintf( stderr, "write() failed (%d), '%s'; aborting reply.\n", errno, strerror( errno ) );
                        close( sockfd );
                        return;
                    }
                    totalBytesWritten += bytesWritten;
                }
            }

            index = request.find( "\r\n\r\n" );
        }
    }
}

// FIXME: sigterm handler to dump diagnostics and gracefully exit.  See
// the condor_amazon simulator.
int main( int argc, char ** argv ) {

    int listenSocket = socket( PF_INET, SOCK_STREAM, 0 );
    if( listenSocket == -1 ) {
        fprintf( stderr, "socket() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 1 );
    }

    struct sockaddr_in listenAddr;
    listenAddr.sin_family = AF_INET;
    listenAddr.sin_port = htons( 21737 );
    listenAddr.sin_addr.s_addr = INADDR_ANY;
    int rv = bind( listenSocket, (struct sockaddr *)(& listenAddr), sizeof( listenAddr ) );
    if( rv != 0 ) {
        fprintf( stderr, "bind() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 2 );
    }

    rv = listen( listenSocket, 0 );
    if( rv != 0 ) {
        fprintf( stderr, "listen() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 3 );
    }

    registerAllHandlers();
    registerTestUsers();

    while( 1 ) {
        struct sockaddr_in remoteAddr;
        socklen_t raSize = sizeof( remoteAddr );
        int remoteSocket = accept( listenSocket, (struct sockaddr *)(& remoteAddr), & raSize );
        if( remoteSocket == -1 ) {
            fprintf( stderr, "accept() failed(%d): '%s'; aborting.\n", errno, strerror( errno ) );
            exit( 4 );
        }

        handleConnection( remoteSocket );
    }

    return 0;
} // end main()
<commit_msg>(#1821) Tracking commit.<commit_after>#include <stdio.h>
#include <stdlib.h>

#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>

#include <string>
#include <map>
#include <sstream>

#include <ext/hash_map>
namespace ext = __gnu_cxx;

typedef std::map< std::string, std::string > AttributeValueMap;
typedef bool (*ActionHandler)( AttributeValueMap & avm, std::string & reply );
typedef std::map< std::string, ActionHandler > ActionToHandlerMap;

/*
 * The GAHP uses the following functions from the Query API:
 *
 *      RunInstances
 *      TerminateInstances
 *      DescribeInstances
 *      CreateKeyPair
 *      DeleteKeyPair
 *      DescribeKeyPairs
 */

/*
 * Inexplicably, this isn't one of the standard specializations.
 * Even less explicably, you can't use namespace aliases to open a namespace.
 *
 * However, by supplying this specialization, all of the ext::hash_maps using
 * std::string as a key work without further ado.
 */

namespace __gnu_cxx {
    template<> struct hash< std::string > {
        size_t operator()( const std::string & s ) const {
            return __stl_hash_string( s.c_str() );
        }
    };
}

typedef struct {
} Group;
typedef ext::hash_map< std::string, Group > NameToGroupMap;

typedef struct {
    std::string privateKey;
} Keypair;
typedef ext::hash_map< std::string, Keypair > NameToKeypairMap;

typedef struct {
    std::string imageID;
    std::string privateDNSName;
    std::string publicDNSName;
    std::string instanceType;
    std::string instanceState;
    std::string keyName;

    ext::hash_map< std::string, const Group * > groups;
} Instance;
typedef ext::hash_map< std::string, Instance > InstanceIDToInstanceMap;

typedef struct {
    NameToKeypairMap keypairs;
    NameToGroupMap groups;
    InstanceIDToInstanceMap instances;
} User;
typedef ext::hash_map< std::string, User > AccessKeyIDToUserMap;

// Global.  Eww.
AccessKeyIDToUserMap users;

void registerTestUsers() {
    users[ "1" ] = User();
    users[ "2" ] = User();
}

// The compiler seems unwilling or unable to infer return types; GregT
// speculated that this might be because templated functions are in their
// own namespace, but getObject<>() doesn't infer the return type, either.
template< class V, class T, class K > V getObject( const T & map, const K & key, bool & found ) {
    class T::const_iterator ci = map.find( key );
    if( map.end() == ci ) {
        found = false;
        return V();
    }
    found = true;
    return ci->second;
}

bool validateAndAcquireUser( AttributeValueMap & avm, std::string & userID, User & user, std::string & reply ) {
    bool found = false;

    userID = getObject< std::string >( avm, "AWSAccessKeyId", found );
    if( (!found) || userID.empty() ) {
        fprintf( stderr, "DEBUG: failed to find AWSAccessKeyId in query.\n" );
        reply = "Required parameter AWSAccessKeyId missing or empty.\n";
        return false;
    }

    user = getObject< User >( users, userID, found );
    if( ! found ) {
        fprintf( stderr, "Failed to find user identified by '%s'.\n", userID.c_str() );
        reply = "Required parameter ASWAccessKeyId invalid.\n";
        return false;
    }

    return true;
}

bool handleRunInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleRunInstances()\n" );

    std::string userID;
    User user;
    bool found = validateAndAcquireUser( avm, userID, user, reply );
    if( ! found ) { return false; }

    // Validate the ImageId, MinCount, and MaxCount parameters, as well
    // as the optional parameters KeyName, InstanceType, SecurityGroup*,
    // and UserData.

    // We presently assume all imageIDs are valid.
    std::string imageID = getObject< std::string >( avm, "ImageId", found );
    if( (! found) || imageID.empty() ) {
        fprintf( stderr, "Failed to find imageID in query.\n" );
        reply = "Required parameter ImageId missing or empty.\n";
        return false;
    }

    std::string minCount = getObject< std::string >( avm, "MinCount", found );
    if( (! found) || minCount.empty() ) {
        fprintf( stderr, "Failed to find minCount in query.\n" );
        reply = "Required parameter MinCount missing or empty.\n";
        return false;
    }

    std::string maxCount = getObject< std::string >( avm, "MaxCount", found );
    if( (! found) || maxCount.empty() ) {
        fprintf( stderr, "Failed to find maxCount in query.\n" );
        reply = "Required parameter MaxCount missing or empty.\n";
        return false;
    }

    // FIXME: Verify that maxCount >= minCount.

    std::string keyName = getObject< std::string >( avm, "KeyName", found );
    if( ! keyName.empty() ) {
        // FIXME: Verify that this keypair exists.
    }

    // We presently assume all instanceTypes are valid.
    std::string instanceType = getObject< std::string >( avm, "InstanceType", found );

    std::string userData = getObject< std::string >( avm, "UserData", found );
    if( ! userData.empty() ) {
        // FIXME: Verify that the user data is Base64-encoded.
    }

    std::vector< std::string > securityGroupNames;
    for( int i = 1; ; ++i ) {
        std::ostringstream sgParameterName;
        sgParameterName << "SecurityGroup." << i;
        std::string sgName = getObject< std::string >( avm, sgParameterName.str(), found );
        if( ! found ) { break; }
        if( sgName.empty() ) {
            std::ostringstream error;
            error << "Optional parameter " << sgName << " must not be empty." << std::endl;
            reply = error.str();
            fprintf( stderr, "%s", reply.c_str() );
            return false;
        }

        // FIXME: Verify that the group sgName exists.
    }

    // FIXME: create the corresponding Instance.

    return true;
}

bool handleTerminateInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleTerminateInstances()\n" );

    std::string userID;
    User user;
    bool found = validateAndAcquireUser( avm, userID, user, reply );
    if( ! found ) { return false; }

    std::string instanceID = getObject< std::string >( avm, "InstanceId.1", found );
    if( (! found) || instanceID.empty() ) {
        fprintf( stderr, "DEBUG: failed to find instanceID in query.\n" );
        reply = "Required parameter InstanceId.1 missing or empty.\n";
        return false;
    }

    Instance instance = getObject< Instance >( user.instances, instanceID, found );
    if( ! found ) {
        std::ostringstream error;
        error << "Instance ID '" << instanceID << "' does not exist." << std::endl;
        reply = error.str();
        fprintf( stderr, "%s", reply.c_str() );
        return false;
    }

    reply = "// FIXME: spam out some XML.\n";
    return true;
}

bool handleDescribeInstances( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDescribeInstances()\n" );
    return false;
}

bool handleCreateKeyPair( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleCreateKeyPair()\n" );
    return false;
}

bool handleDeleteKeyPair( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDeleteKeyPair()\n" );
    return false;
}

bool handleDescribeKeyPairs( AttributeValueMap & avm, std::string & reply ) {
    fprintf( stderr, "handleDescribeKeyPairs()\n" );
    return false;
}

// Global.  Eww.
ActionToHandlerMap simulatorActions;

void registerAllHandlers() {
    simulatorActions[ "RunInstances" ] = & handleRunInstances;
    simulatorActions[ "TerminateInstances" ] = & handleTerminateInstances;
    simulatorActions[ "DescribeInstances" ] = & handleDescribeInstances;
    simulatorActions[ "CreateKeyPair" ] = & handleCreateKeyPair;
    simulatorActions[ "DeleteKeyPair" ] = & handleDeleteKeyPair;
    simulatorActions[ "DescribeKeyPairs" ] = & handleDescribeKeyPairs;
}

// m/^Host: <host>\r\n/
bool extractHost( const std::string & request, std::string & host ) {
    std::string::size_type i = request.find( "\r\nHost: " );
    if( std::string::npos == i ) {
        fprintf( stderr, "Malformed request '%s': contains no Host header; failing.\n", request.c_str() );
        return false;
    }

    std::string::size_type j = request.find( "\r\n", i + 2 );
    if( std::string::npos == j ) {
        fprintf( stderr, "Malformed request '%s': Host field not CR/LF terminated; failing.\n", request.c_str() );
        return false;
    }

    host = request.substr( i + 8, j - (i + 8)  );
    return true;
}

// m/^GET <URL> HTTP/
bool extractURL( const std::string & request, std::string & URL ) {
    if( request.find( "GET " ) != 0 ) {
        fprintf( stderr, "Malformed request '%s': did not begin with 'GET '; failing.\n", request.c_str() );
        return false;
    }

    URL = request.substr( 4, request.find( "HTTP" ) - 5 );
    return true;
}

/*
 * The most fragile part of the EC2 GAHP is the query signing, so
 * we'd like to validate it.  See the comments in amazonCommands.cpp
 * for more details.
 *
 * This function is presently a stub because I haven't solved the
 * problem of key distribution between the tester and the simulator.
 *
 * Validates parameters:
 *      Signature,
 *      SignatureVersion
 *      SignatureMethod
 *      Timestamp
 *      Version
 *
 */
bool validateSignature( std::string & method,
                        const std::string & host,
                        const std::string & URL,
                        const AttributeValueMap & queryParameters ) {
    return true;
}

std::string constructReply( const std::string & statusLine, const std::string & response ) {
    std::ostringstream reply;

    // The ec2_gahp doesn't ever look at the headers.
    reply << statusLine << "\r\n";
    reply << "Content-Length: " << response.size() << "\r\n";
    reply << "\r\n";
    reply << response;
    reply << "\r\n";

    return reply.str();
}

std::string handleRequest( const std::string & request ) {
    std::string URL;
    if( ! extractURL( request, URL ) ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "" );
    }

    std::string host;
    if( ! extractHost( request, host ) ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "" );
    }
    std::transform( host.begin(), host.end(), host.begin(), & tolower );

    // fprintf( stderr, "DEBUG: found 'http://%s%s'\n", host.c_str(), URL.c_str() );

    AttributeValueMap queryParameters;
    std::string::size_type i = URL.find( "?" );
    while( i < URL.size() ) {
        // Properly encoded URLs will only have ampersands between
        // the key-value pairs, and equals between keys and values.
        std::string::size_type equalsIdx = URL.find( "=", i + 1 );
        if( std::string::npos == equalsIdx ) {
            std::ostringstream error;
            error << "Malformed URL '" << URL << "': attribute without value; failing" << std::endl;
            fprintf( stderr, error.str().c_str() );
            return constructReply( "HTTP/1.1 400 Bad Request", error.str() );
        }
        std::string::size_type ampersandIdx = URL.find( "&", i + 1 );
        if( std::string::npos == ampersandIdx ) {
            ampersandIdx = URL.size();
        }

        std::string key = URL.substr( i + 1, equalsIdx - (i + 1) );
        std::string value = URL.substr( equalsIdx + 1, ampersandIdx - (equalsIdx + 1 ) );
        // fprintf( stderr, "DEBUG: key = '%s', value = '%s'\n", key.c_str(), value.c_str() );
        queryParameters[ key ] = value;

        i = ampersandIdx;
    }

    std::string method = "GET";
    if( ! validateSignature( method, host, URL, queryParameters ) ) {
        return constructReply( "HTTP/1.1 401 Unauthorized", "Failed signature validation." );
    }

    std::string action = queryParameters[ "Action" ];
    if( action.empty() ) {
        return constructReply( "HTTP/1.1 400 Bad Request", "No action specified." );
    }

    std::string response;
    ActionToHandlerMap::const_iterator ci = simulatorActions.find( action );
    if( simulatorActions.end() == ci ) {
        std::ostringstream error;
        error << "Action '" << action << "' not found." << std::endl;
        fprintf( stderr, error.str().c_str() );
        return constructReply( "HTTP/1.1 404 Not Found", error.str() );
    }

    if( (*(ci->second))( queryParameters, response ) ) {
        return constructReply( "HTTP/1.1 200 OK", response );
    } else {
        return constructReply( "HTTP/1.1 406 Not Acceptable", response );
    }
}

void handleConnection( int sockfd ) {
    ssize_t bytesRead;
    char buffer[1024+1];
    std::string request;

    while( 1 ) {
        bytesRead = read( sockfd, (void *) buffer, 1024 );

        if( bytesRead == -1 ) {
            if( errno == EINTR ) {
                fprintf( stderr, "read() interrupted, retrying.\n" );
                continue;
            }
            fprintf( stderr, "read() failed (%d): '%s'\n", errno, strerror( errno ) );
            return;
        }

        if( bytesRead == 0 ) {
            close( sockfd );
            return;
        }

        buffer[bytesRead] = '\0';
        request += buffer;
        // fprintf( stderr, "DEBUG: request is now '%s'.\n", request.c_str() );

        // A given HTTP request is terminated by a blank line.
        std::string::size_type index = request.find( "\r\n\r\n" );
        while( index != std::string::npos ) {
            std::string firstRequest = request.substr( 0, index + 4 );
            request = request.substr( index + 4 );
            // if( ! request.empty() ) { fprintf( stderr, "DEBUG: request remainder '%s'\n", request.c_str() ); }

            // fprintf( stderr, "DEBUG: handling request '%s'\n", firstRequest.c_str() );
            std::string reply = handleRequest( firstRequest );
            if( ! reply.empty() ) {
                // fprintf( stderr, "DEBUG: writing reply '%s'\n", reply.c_str() );
                ssize_t totalBytesWritten = 0;
                ssize_t bytesToWrite = reply.size();
                const char * outBuf = reply.c_str();
                while( totalBytesWritten != bytesToWrite ) {
                    ssize_t bytesWritten = write( sockfd,
                        outBuf + totalBytesWritten,
                        bytesToWrite - totalBytesWritten );
                    if( bytesWritten == -1 ) {
                        fprintf( stderr, "write() failed (%d), '%s'; aborting reply.\n", errno, strerror( errno ) );
                        close( sockfd );
                        return;
                    }
                    totalBytesWritten += bytesWritten;
                }
            }

            index = request.find( "\r\n\r\n" );
        }
    }
}

// FIXME: sigterm handler to dump diagnostics and gracefully exit.  See
// the condor_amazon simulator.
int main( int argc, char ** argv ) {

    int listenSocket = socket( PF_INET, SOCK_STREAM, 0 );
    if( listenSocket == -1 ) {
        fprintf( stderr, "socket() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 1 );
    }

    struct sockaddr_in listenAddr;
    listenAddr.sin_family = AF_INET;
    listenAddr.sin_port = htons( 21737 );
    listenAddr.sin_addr.s_addr = INADDR_ANY;
    int rv = bind( listenSocket, (struct sockaddr *)(& listenAddr), sizeof( listenAddr ) );
    if( rv != 0 ) {
        fprintf( stderr, "bind() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 2 );
    }

    rv = listen( listenSocket, 0 );
    if( rv != 0 ) {
        fprintf( stderr, "listen() failed (%d): '%s'; aborting.\n", errno, strerror( errno ) );
        exit( 3 );
    }

    registerAllHandlers();
    registerTestUsers();

    while( 1 ) {
        struct sockaddr_in remoteAddr;
        socklen_t raSize = sizeof( remoteAddr );
        int remoteSocket = accept( listenSocket, (struct sockaddr *)(& remoteAddr), & raSize );
        if( remoteSocket == -1 ) {
            fprintf( stderr, "accept() failed(%d): '%s'; aborting.\n", errno, strerror( errno ) );
            exit( 4 );
        }

        handleConnection( remoteSocket );
    }

    return 0;
} // end main()
<|endoftext|>


<commit_before><commit_msg>fix conversion again<commit_after><|endoftext|>