<commit_before>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
/*
 * @file        ProtocolAdmin.cpp
 * @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
 * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
 * @version     1.0
 * @brief       This file implements protocol class for administration
 */

#include <memory>

#include <exceptions/InvalidProtocolException.h>
#include <log/log.h>
#include <protocol/ProtocolFrame.h>
#include <protocol/ProtocolFrameSerializer.h>
#include <request/InsertOrUpdateBucketRequest.h>
#include <request/RemoveBucketRequest.h>
#include <request/RequestContext.h>
#include <request/SetPoliciesRequest.h>
#include <response/CodeResponse.h>

#include "ProtocolAdmin.h"

namespace Cynara {

ProtocolAdmin::ProtocolAdmin() {
}

ProtocolAdmin::~ProtocolAdmin() {
}

ProtocolPtr ProtocolAdmin::clone(void) {
    return std::make_shared<ProtocolAdmin>();
}

RequestPtr ProtocolAdmin::deserializeInsertOrUpdateBucketRequest(ProtocolFrameHeader &frame) {
    PolicyBucketId policyBucketId;
    PolicyType policyType;
    PolicyResult::PolicyMetadata policyMetaData;

    ProtocolDeserialization::deserialize(frame, policyBucketId);
    ProtocolDeserialization::deserialize(frame, policyType);
    ProtocolDeserialization::deserialize(frame, policyMetaData);

    LOGD("Deserialized InsertOrUpdateBucketRequest: bucketId <%s>, "
         "result.type [%u], result.meta <%s>", policyBucketId.c_str(),
         static_cast<unsigned int>(policyType), policyMetaData.c_str());

    return std::make_shared<InsertOrUpdateBucketRequest>(policyBucketId,
            PolicyResult(policyType, policyMetaData), frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::deserializeRemoveBucketRequest(ProtocolFrameHeader &frame) {
    PolicyBucketId policyBucketId;

    ProtocolDeserialization::deserialize(frame, policyBucketId);

    LOGD("Deserialized RemoveBucketRequest: bucketId <%s>", policyBucketId.c_str());

    return std::make_shared<RemoveBucketRequest>(policyBucketId, frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::deserializeSetPoliciesRequest(ProtocolFrameHeader &frame) {
    ProtocolFrameFieldsCount toBeInsertedOrUpdatedCount, toBeRemovedCount;
    ProtocolFrameFieldsCount policyCount;
    PolicyKeyFeature::ValueType clientId, user, privilege;
    PolicyType policyType;
    PolicyResult::PolicyMetadata metadata;
    std::map<PolicyBucketId, std::vector<Policy>> toBeInsertedOrUpdatedPolicies;
    std::map<PolicyBucketId, std::vector<PolicyKey>> toBeRemovedPolicies;

    ProtocolDeserialization::deserialize(frame, toBeInsertedOrUpdatedCount);
    for (ProtocolFrameFieldsCount b = 0; b < toBeInsertedOrUpdatedCount; ++b) {
        PolicyBucketId policyBucketId;
        ProtocolDeserialization::deserialize(frame, policyBucketId);
        ProtocolDeserialization::deserialize(frame, policyCount);
        for (ProtocolFrameFieldsCount p = 0; p < policyCount; ++p) {
            // PolicyKey
            ProtocolDeserialization::deserialize(frame, clientId);
            ProtocolDeserialization::deserialize(frame, user);
            ProtocolDeserialization::deserialize(frame, privilege);
            // PolicyResult
            ProtocolDeserialization::deserialize(frame, policyType);
            ProtocolDeserialization::deserialize(frame, metadata);

            toBeInsertedOrUpdatedPolicies[policyBucketId].push_back(
                    Policy(PolicyKey(clientId, user, privilege),
                    PolicyResult(policyType, metadata)));
        }
    }

    ProtocolDeserialization::deserialize(frame, toBeRemovedCount);
    for (ProtocolFrameFieldsCount b = 0; b < toBeRemovedCount; ++b) {
        PolicyBucketId policyBucketId;
        ProtocolDeserialization::deserialize(frame, policyBucketId);
        ProtocolDeserialization::deserialize(frame, policyCount);
        for (ProtocolFrameFieldsCount p = 0; p < policyCount; ++p) {
            // PolicyKey
            ProtocolDeserialization::deserialize(frame, clientId);
            ProtocolDeserialization::deserialize(frame, user);
            ProtocolDeserialization::deserialize(frame, privilege);

            toBeRemovedPolicies[policyBucketId].push_back(PolicyKey(clientId, user, privilege));
        }
    }

    LOGD("Deserialized SetPoliciesRequestPtr: insertOrUpdate count [%u], remove count [%u]",
         static_cast<unsigned int>(toBeInsertedOrUpdatedCount),
         static_cast<unsigned int>(toBeRemovedCount));

    return std::make_shared<SetPoliciesRequest>(toBeInsertedOrUpdatedPolicies,
                                                toBeRemovedPolicies, frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::extractRequestFromBuffer(BinaryQueue &bufferQueue) {
    ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue);

    if (m_frameHeader.isFrameComplete()) {
        ProtocolOpCode opCode;

        m_frameHeader.resetState();
        ProtocolDeserialization::deserialize(m_frameHeader, opCode);
        LOGD("Deserialized opCode [%u]", static_cast<unsigned int>(opCode));
        switch (opCode) {
        case OpInsertOrUpdateBucket:
            return deserializeInsertOrUpdateBucketRequest(m_frameHeader);
        case OpRemoveBucket:
            return deserializeRemoveBucketRequest(m_frameHeader);
        case OpSetPolicies:
            return deserializeSetPoliciesRequest(m_frameHeader);
        default:
            throw InvalidProtocolException(InvalidProtocolException::WrongOpCode);
            break;
        }
    }

    return nullptr;
}

ResponsePtr ProtocolAdmin::deserializeCodeResponse(ProtocolFrameHeader &frame) {
    ProtocolResponseCode responseCode;
    ProtocolDeserialization::deserialize(frame, responseCode);

    LOGD("Deserialized CodeResponse: code [%u], ", static_cast<unsigned int>(responseCode));

    return std::make_shared<CodeResponse>(static_cast<CodeResponse::Code>(responseCode),
                                          frame.sequenceNumber());
}

ResponsePtr ProtocolAdmin::extractResponseFromBuffer(BinaryQueue &bufferQueue) {
    ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue);

    if (m_frameHeader.isFrameComplete()) {
        ProtocolOpCode opCode;

        m_frameHeader.resetState();
        ProtocolDeserialization::deserialize(m_frameHeader, opCode);
        LOGD("Deserialized opCode [%u]", static_cast<unsigned int>(opCode));
        switch (opCode) {
        case OpCodeResponse:
            return deserializeCodeResponse(m_frameHeader);
        default:
            throw InvalidProtocolException(InvalidProtocolException::WrongOpCode);
            break;
        }
    }

    return nullptr;
}

void ProtocolAdmin::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) {
    LOGD("Serializing InsertOrUpdateBucketRequest: sequenceNumber [%u], bucketId <%s>, "
         "result.type [%u], result.meta <%s>",
         static_cast<unsigned int>(request->sequenceNumber()),
         request->bucketId().c_str(),
         static_cast<unsigned int>(request->result().policyType()),
         request->result().metadata().c_str());

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpInsertOrUpdateBucket);
    ProtocolSerialization::serialize(*frame, request->bucketId());
    ProtocolSerialization::serialize(*frame, request->result().policyType());
    ProtocolSerialization::serialize(*frame, request->result().metadata());

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, RemoveBucketRequestPtr request) {
    LOGD("Serializing RemoveBucketRequest: sequenceNumber [%u], bucketId <%s>",
         static_cast<unsigned int>(request->sequenceNumber()), request->bucketId().c_str());

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpRemoveBucket);
    ProtocolSerialization::serialize(*frame, request->bucketId());

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, SetPoliciesRequestPtr request) {
    LOGD("Serializing SetPoliciesRequestPtr: sequenceNumber [%u], insertOrUpdate count [%zu]",
         "remove count [%zu]", static_cast<unsigned int>(request->sequenceNumber()),
         request->policiesToBeInsertedOrUpdated().size(),
         request->policiesToBeRemoved().size());

    ProtocolFramePtr frame =
            ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpSetPolicies);

    ProtocolSerialization::serialize(*frame,
            static_cast<ProtocolFrameFieldsCount>(request->policiesToBeInsertedOrUpdated().size()));
    for (auto policyBucket : request->policiesToBeInsertedOrUpdated()) {
        ProtocolSerialization::serialize(*frame, policyBucket.first);
        ProtocolSerialization::serialize(*frame,
                    static_cast<ProtocolFrameFieldsCount>(policyBucket.second.size()));
        for (auto policy : policyBucket.second) {
            // PolicyKey
            ProtocolSerialization::serialize(*frame, policy.key().client().value());
            ProtocolSerialization::serialize(*frame, policy.key().user().value());
            ProtocolSerialization::serialize(*frame, policy.key().privilege().value());
            // PolicyResult
            ProtocolSerialization::serialize(*frame, policy.result().policyType());
            ProtocolSerialization::serialize(*frame, policy.result().metadata());
        }
    }

    ProtocolSerialization::serialize(*frame,
            static_cast<ProtocolFrameFieldsCount>(request->policiesToBeRemoved().size()));
    for (auto policyBucket : request->policiesToBeRemoved()) {
        ProtocolSerialization::serialize(*frame, policyBucket.first);
        ProtocolSerialization::serialize(*frame,
                    static_cast<ProtocolFrameFieldsCount>(policyBucket.second.size()));
        for (auto policyKey : policyBucket.second) {
            // PolicyKey
            ProtocolSerialization::serialize(*frame, policyKey.client().value());
            ProtocolSerialization::serialize(*frame, policyKey.user().value());
            ProtocolSerialization::serialize(*frame, policyKey.privilege().value());
        }
    }

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, CodeResponsePtr response) {
    LOGD("Serializing CodeResponse: sequenceNumber [%u], code [%u]",
         static_cast<unsigned int>(response->sequenceNumber()),
         static_cast<unsigned int>(response->m_code));

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(
            response->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpCodeResponse);
    ProtocolSerialization::serialize(*frame, static_cast<ProtocolResponseCode>(response->m_code));

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

} // namespace Cynara
<commit_msg>Fix format string concatenating in log message<commit_after>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
/*
 * @file        ProtocolAdmin.cpp
 * @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
 * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
 * @version     1.0
 * @brief       This file implements protocol class for administration
 */

#include <memory>

#include <exceptions/InvalidProtocolException.h>
#include <log/log.h>
#include <protocol/ProtocolFrame.h>
#include <protocol/ProtocolFrameSerializer.h>
#include <request/InsertOrUpdateBucketRequest.h>
#include <request/RemoveBucketRequest.h>
#include <request/RequestContext.h>
#include <request/SetPoliciesRequest.h>
#include <response/CodeResponse.h>

#include "ProtocolAdmin.h"

namespace Cynara {

ProtocolAdmin::ProtocolAdmin() {
}

ProtocolAdmin::~ProtocolAdmin() {
}

ProtocolPtr ProtocolAdmin::clone(void) {
    return std::make_shared<ProtocolAdmin>();
}

RequestPtr ProtocolAdmin::deserializeInsertOrUpdateBucketRequest(ProtocolFrameHeader &frame) {
    PolicyBucketId policyBucketId;
    PolicyType policyType;
    PolicyResult::PolicyMetadata policyMetaData;

    ProtocolDeserialization::deserialize(frame, policyBucketId);
    ProtocolDeserialization::deserialize(frame, policyType);
    ProtocolDeserialization::deserialize(frame, policyMetaData);

    LOGD("Deserialized InsertOrUpdateBucketRequest: bucketId <%s>, "
         "result.type [%u], result.meta <%s>", policyBucketId.c_str(),
         static_cast<unsigned int>(policyType), policyMetaData.c_str());

    return std::make_shared<InsertOrUpdateBucketRequest>(policyBucketId,
            PolicyResult(policyType, policyMetaData), frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::deserializeRemoveBucketRequest(ProtocolFrameHeader &frame) {
    PolicyBucketId policyBucketId;

    ProtocolDeserialization::deserialize(frame, policyBucketId);

    LOGD("Deserialized RemoveBucketRequest: bucketId <%s>", policyBucketId.c_str());

    return std::make_shared<RemoveBucketRequest>(policyBucketId, frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::deserializeSetPoliciesRequest(ProtocolFrameHeader &frame) {
    ProtocolFrameFieldsCount toBeInsertedOrUpdatedCount, toBeRemovedCount;
    ProtocolFrameFieldsCount policyCount;
    PolicyKeyFeature::ValueType clientId, user, privilege;
    PolicyType policyType;
    PolicyResult::PolicyMetadata metadata;
    std::map<PolicyBucketId, std::vector<Policy>> toBeInsertedOrUpdatedPolicies;
    std::map<PolicyBucketId, std::vector<PolicyKey>> toBeRemovedPolicies;

    ProtocolDeserialization::deserialize(frame, toBeInsertedOrUpdatedCount);
    for (ProtocolFrameFieldsCount b = 0; b < toBeInsertedOrUpdatedCount; ++b) {
        PolicyBucketId policyBucketId;
        ProtocolDeserialization::deserialize(frame, policyBucketId);
        ProtocolDeserialization::deserialize(frame, policyCount);
        for (ProtocolFrameFieldsCount p = 0; p < policyCount; ++p) {
            // PolicyKey
            ProtocolDeserialization::deserialize(frame, clientId);
            ProtocolDeserialization::deserialize(frame, user);
            ProtocolDeserialization::deserialize(frame, privilege);
            // PolicyResult
            ProtocolDeserialization::deserialize(frame, policyType);
            ProtocolDeserialization::deserialize(frame, metadata);

            toBeInsertedOrUpdatedPolicies[policyBucketId].push_back(
                    Policy(PolicyKey(clientId, user, privilege),
                    PolicyResult(policyType, metadata)));
        }
    }

    ProtocolDeserialization::deserialize(frame, toBeRemovedCount);
    for (ProtocolFrameFieldsCount b = 0; b < toBeRemovedCount; ++b) {
        PolicyBucketId policyBucketId;
        ProtocolDeserialization::deserialize(frame, policyBucketId);
        ProtocolDeserialization::deserialize(frame, policyCount);
        for (ProtocolFrameFieldsCount p = 0; p < policyCount; ++p) {
            // PolicyKey
            ProtocolDeserialization::deserialize(frame, clientId);
            ProtocolDeserialization::deserialize(frame, user);
            ProtocolDeserialization::deserialize(frame, privilege);

            toBeRemovedPolicies[policyBucketId].push_back(PolicyKey(clientId, user, privilege));
        }
    }

    LOGD("Deserialized SetPoliciesRequestPtr: insertOrUpdate count [%u], remove count [%u]",
         static_cast<unsigned int>(toBeInsertedOrUpdatedCount),
         static_cast<unsigned int>(toBeRemovedCount));

    return std::make_shared<SetPoliciesRequest>(toBeInsertedOrUpdatedPolicies,
                                                toBeRemovedPolicies, frame.sequenceNumber());
}

RequestPtr ProtocolAdmin::extractRequestFromBuffer(BinaryQueue &bufferQueue) {
    ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue);

    if (m_frameHeader.isFrameComplete()) {
        ProtocolOpCode opCode;

        m_frameHeader.resetState();
        ProtocolDeserialization::deserialize(m_frameHeader, opCode);
        LOGD("Deserialized opCode [%u]", static_cast<unsigned int>(opCode));
        switch (opCode) {
        case OpInsertOrUpdateBucket:
            return deserializeInsertOrUpdateBucketRequest(m_frameHeader);
        case OpRemoveBucket:
            return deserializeRemoveBucketRequest(m_frameHeader);
        case OpSetPolicies:
            return deserializeSetPoliciesRequest(m_frameHeader);
        default:
            throw InvalidProtocolException(InvalidProtocolException::WrongOpCode);
            break;
        }
    }

    return nullptr;
}

ResponsePtr ProtocolAdmin::deserializeCodeResponse(ProtocolFrameHeader &frame) {
    ProtocolResponseCode responseCode;
    ProtocolDeserialization::deserialize(frame, responseCode);

    LOGD("Deserialized CodeResponse: code [%u], ", static_cast<unsigned int>(responseCode));

    return std::make_shared<CodeResponse>(static_cast<CodeResponse::Code>(responseCode),
                                          frame.sequenceNumber());
}

ResponsePtr ProtocolAdmin::extractResponseFromBuffer(BinaryQueue &bufferQueue) {
    ProtocolFrameSerializer::deserializeHeader(m_frameHeader, bufferQueue);

    if (m_frameHeader.isFrameComplete()) {
        ProtocolOpCode opCode;

        m_frameHeader.resetState();
        ProtocolDeserialization::deserialize(m_frameHeader, opCode);
        LOGD("Deserialized opCode [%u]", static_cast<unsigned int>(opCode));
        switch (opCode) {
        case OpCodeResponse:
            return deserializeCodeResponse(m_frameHeader);
        default:
            throw InvalidProtocolException(InvalidProtocolException::WrongOpCode);
            break;
        }
    }

    return nullptr;
}

void ProtocolAdmin::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) {
    LOGD("Serializing InsertOrUpdateBucketRequest: sequenceNumber [%u], bucketId <%s>, "
         "result.type [%u], result.meta <%s>",
         static_cast<unsigned int>(request->sequenceNumber()),
         request->bucketId().c_str(),
         static_cast<unsigned int>(request->result().policyType()),
         request->result().metadata().c_str());

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpInsertOrUpdateBucket);
    ProtocolSerialization::serialize(*frame, request->bucketId());
    ProtocolSerialization::serialize(*frame, request->result().policyType());
    ProtocolSerialization::serialize(*frame, request->result().metadata());

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, RemoveBucketRequestPtr request) {
    LOGD("Serializing RemoveBucketRequest: sequenceNumber [%u], bucketId <%s>",
         static_cast<unsigned int>(request->sequenceNumber()), request->bucketId().c_str());

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpRemoveBucket);
    ProtocolSerialization::serialize(*frame, request->bucketId());

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, SetPoliciesRequestPtr request) {
    LOGD("Serializing SetPoliciesRequestPtr: sequenceNumber [%u], insertOrUpdate count [%zu], "
         "remove count [%zu]", static_cast<unsigned int>(request->sequenceNumber()),
         request->policiesToBeInsertedOrUpdated().size(),
         request->policiesToBeRemoved().size());

    ProtocolFramePtr frame =
            ProtocolFrameSerializer::startSerialization(request->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpSetPolicies);

    ProtocolSerialization::serialize(*frame,
            static_cast<ProtocolFrameFieldsCount>(request->policiesToBeInsertedOrUpdated().size()));
    for (auto policyBucket : request->policiesToBeInsertedOrUpdated()) {
        ProtocolSerialization::serialize(*frame, policyBucket.first);
        ProtocolSerialization::serialize(*frame,
                    static_cast<ProtocolFrameFieldsCount>(policyBucket.second.size()));
        for (auto policy : policyBucket.second) {
            // PolicyKey
            ProtocolSerialization::serialize(*frame, policy.key().client().value());
            ProtocolSerialization::serialize(*frame, policy.key().user().value());
            ProtocolSerialization::serialize(*frame, policy.key().privilege().value());
            // PolicyResult
            ProtocolSerialization::serialize(*frame, policy.result().policyType());
            ProtocolSerialization::serialize(*frame, policy.result().metadata());
        }
    }

    ProtocolSerialization::serialize(*frame,
            static_cast<ProtocolFrameFieldsCount>(request->policiesToBeRemoved().size()));
    for (auto policyBucket : request->policiesToBeRemoved()) {
        ProtocolSerialization::serialize(*frame, policyBucket.first);
        ProtocolSerialization::serialize(*frame,
                    static_cast<ProtocolFrameFieldsCount>(policyBucket.second.size()));
        for (auto policyKey : policyBucket.second) {
            // PolicyKey
            ProtocolSerialization::serialize(*frame, policyKey.client().value());
            ProtocolSerialization::serialize(*frame, policyKey.user().value());
            ProtocolSerialization::serialize(*frame, policyKey.privilege().value());
        }
    }

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

void ProtocolAdmin::execute(RequestContextPtr context, CodeResponsePtr response) {
    LOGD("Serializing CodeResponse: sequenceNumber [%u], code [%u]",
         static_cast<unsigned int>(response->sequenceNumber()),
         static_cast<unsigned int>(response->m_code));

    ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(
            response->sequenceNumber());

    ProtocolSerialization::serialize(*frame, OpCodeResponse);
    ProtocolSerialization::serialize(*frame, static_cast<ProtocolResponseCode>(response->m_code));

    ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue());
}

} // namespace Cynara
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*****************************************************************************/
#include "ProgressBehavior.h"

#include "pqApplicationCore.h"
#include "pqProgressManager.h"

#include <QProgressDialog>

namespace tomviz {

ProgressBehavior::ProgressBehavior(QWidget* parentWindow)
  : Superclass(parentWindow), ProgressDialog(nullptr)
{
  pqProgressManager* progressManager =
    pqApplicationCore::instance()->getProgressManager();
  this->connect(progressManager, SIGNAL(enableProgress(bool)),
                SLOT(enableProgress(bool)));
  this->connect(progressManager, SIGNAL(progress(const QString&, int)),
                SLOT(progress(const QString, int)));
}

ProgressBehavior::~ProgressBehavior()
{
  this->ProgressDialog->deleteLater();
}

void ProgressBehavior::initialize()
{
  if (this->ProgressDialog) {
    return;
  }

  this->ProgressDialog = new QProgressDialog(
    "In progress...", "Cancel", 0, 100, qobject_cast<QWidget*>(this->parent()));
  this->ProgressDialog->setAutoClose(true);
  this->ProgressDialog->setAutoReset(false);
  this->ProgressDialog->setMinimumDuration(0); // 0 second.
}

void ProgressBehavior::enableProgress(bool enable)
{
  this->initialize();
  Q_ASSERT(this->ProgressDialog);

  if (enable) {
    this->ProgressDialog->setValue(0);
  } else {
    this->ProgressDialog->reset();
  }
}

void ProgressBehavior::progress(const QString& message, int progressAmount)
{
  this->initialize();
  Q_ASSERT(this->ProgressDialog);

  this->ProgressDialog->setLabelText(message);
  this->ProgressDialog->setValue(progressAmount);
}
}
<commit_msg>Fix warning on application exit.<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*****************************************************************************/
#include "ProgressBehavior.h"

#include "pqApplicationCore.h"
#include "pqProgressManager.h"

#include <QProgressDialog>

namespace tomviz {

ProgressBehavior::ProgressBehavior(QWidget* parentWindow)
  : Superclass(parentWindow), ProgressDialog(nullptr)
{
  pqProgressManager* progressManager =
    pqApplicationCore::instance()->getProgressManager();
  this->connect(progressManager, SIGNAL(enableProgress(bool)),
                SLOT(enableProgress(bool)));
  this->connect(progressManager, SIGNAL(progress(const QString&, int)),
                SLOT(progress(const QString, int)));
}

ProgressBehavior::~ProgressBehavior()
{
  if (this->ProgressDialog) {
    this->ProgressDialog->deleteLater();
  }
}

void ProgressBehavior::initialize()
{
  if (this->ProgressDialog) {
    return;
  }

  this->ProgressDialog = new QProgressDialog(
    "In progress...", "Cancel", 0, 100, qobject_cast<QWidget*>(this->parent()));
  this->ProgressDialog->setAutoClose(true);
  this->ProgressDialog->setAutoReset(false);
  this->ProgressDialog->setMinimumDuration(0); // 0 second.
}

void ProgressBehavior::enableProgress(bool enable)
{
  this->initialize();
  Q_ASSERT(this->ProgressDialog);

  if (enable) {
    this->ProgressDialog->setValue(0);
  } else {
    this->ProgressDialog->reset();
  }
}

void ProgressBehavior::progress(const QString& message, int progressAmount)
{
  this->initialize();
  Q_ASSERT(this->ProgressDialog);

  this->ProgressDialog->setLabelText(message);
  this->ProgressDialog->setValue(progressAmount);
}
}
<|endoftext|>


<commit_before>// Catch
#include <catch.hpp>

// C++ Standard Library
#include <cstdlib>
#include <cmath>

// Armadillo
#include <armadillo>

// HOP
#include <hop>

TEST_CASE("Random rotation matrix", "") {
  SECTION("2-dimensional rotation") {
    arma::Col<double>::fixed<10000> angles;
    for (std::size_t n = 0; n < angles.n_elem; ++n) {
      arma::Col<double>::fixed<2> rotatedUnitVector = hop::getRandomRotationMatrix(2) * arma::Col<double>::fixed<2>({-2, 1});
      angles.at(n) = std::atan2(rotatedUnitVector.at(1), rotatedUnitVector.at(0));
    }

    arma::Col<arma::uword> histogram = arma::hist(angles);
    CHECK(0.05 > static_cast<double>(histogram.max() - histogram.min()) / angles.n_elem);
  }

  SECTION("3-dimensional rotation") {
    arma::Col<double>::fixed<10000> rollAngles;
    arma::Col<double>::fixed<10000> pitchAngles;
    arma::Col<double>::fixed<10000> yawAngles;
    for (std::size_t n = 0; n < rollAngles.n_elem; ++n) {
      arma::Col<double>::fixed<3> rotatedUnitVector = hop::getRandomRotationMatrix(3) * arma::Col<double>::fixed<3>({-2, 1, 3});
      rollAngles.at(n) = std::atan2(rotatedUnitVector.at(1), rotatedUnitVector.at(0));
      pitchAngles.at(n) = std::atan2(rotatedUnitVector.at(2), rotatedUnitVector.at(1));
      yawAngles.at(n) = std::atan2(rotatedUnitVector.at(0), rotatedUnitVector.at(2));
    }

    arma::Col<arma::uword> histogram;

    histogram = arma::hist(rollAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / rollAngles.n_elem);

    histogram = arma::hist(pitchAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / pitchAngles.n_elem);

    histogram = arma::hist(yawAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / yawAngles.n_elem);
  }
}

TEST_CASE("Random permutation", "") {
  SECTION("Full permutation") {
    arma::Mat<arma::uword>::fixed<10, 10000> permutations;
    for (std::size_t n = 0; n < permutations.n_cols; ++n) {
      permutations.col(n) = hop::getRandomPermutation(permutations.n_rows);
    }

    arma::Col<arma::uword> centers(permutations.n_rows);
    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      centers.at(n) = n;
    }

    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      arma::Row<arma::uword> histogram = arma::hist(permutations.row(n), centers);
      CHECK(0.05 > static_cast<double>(histogram.max() - histogram.min()) / permutations.n_cols);
    }
  }

  SECTION("Partial permutation") {
    arma::Mat<arma::uword>::fixed<10, 40000> permutations;
    for (std::size_t n = 0; n < permutations.n_cols; ++n) {
      permutations.col(n) = hop::getRandomPermutation(permutations.n_rows + 1, permutations.n_rows);
    }

    arma::Col<arma::uword> centers(permutations.n_rows);
    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      centers.at(n) = n;
    }

    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      arma::Row<arma::uword> histogram = arma::hist(permutations.row(n), centers);
      CHECK(0.1 > static_cast<double>(histogram.max() - histogram.min()) / permutations.n_cols);
    }
  }
}

<commit_msg>devel: Made fixed field explicit<commit_after>// Catch
#include <catch.hpp>

// C++ Standard Library
#include <cstdlib>
#include <cmath>

// Armadillo
#include <armadillo>

// HOP
#include <hop>

TEST_CASE("Random rotation matrix", "") {
  SECTION("2-dimensional rotation") {
    arma::Col<double>::fixed<10000> angles;
    for (std::size_t n = 0; n < angles.n_elem; ++n) {
      arma::Col<double>::fixed<2> rotatedUnitVector = hop::getRandomRotationMatrix(2) * arma::Col<double>::fixed<2>({-2, 1});
      angles.at(n) = std::atan2(rotatedUnitVector.at(1), rotatedUnitVector.at(0));
    }

    arma::Col<unsigned int> histogram = arma::hist(angles);
    CHECK(0.05 > static_cast<double>(histogram.max() - histogram.min()) / angles.n_elem);
  }

  SECTION("3-dimensional rotation") {
    arma::Col<double>::fixed<10000> rollAngles;
    arma::Col<double>::fixed<10000> pitchAngles;
    arma::Col<double>::fixed<10000> yawAngles;
    for (std::size_t n = 0; n < rollAngles.n_elem; ++n) {
      arma::Col<double>::fixed<3> rotatedUnitVector = hop::getRandomRotationMatrix(3) * arma::Col<double>::fixed<3>({-2, 1, 3});
      rollAngles.at(n) = std::atan2(rotatedUnitVector.at(1), rotatedUnitVector.at(0));
      pitchAngles.at(n) = std::atan2(rotatedUnitVector.at(2), rotatedUnitVector.at(1));
      yawAngles.at(n) = std::atan2(rotatedUnitVector.at(0), rotatedUnitVector.at(2));
    }

    arma::Col<unsigned int> histogram;

    histogram = arma::hist(rollAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / rollAngles.n_elem);

    histogram = arma::hist(pitchAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / pitchAngles.n_elem);

    histogram = arma::hist(yawAngles);
    CHECK(0.02 > static_cast<double>(histogram.max() - histogram.min()) / yawAngles.n_elem);
  }
}

TEST_CASE("Random permutation", "") {
  SECTION("Full permutation") {
    arma::Mat<unsigned int>::fixed<10, 10000> permutations;
    for (std::size_t n = 0; n < permutations.n_cols; ++n) {
      permutations.col(n) = hop::getRandomPermutation(static_cast<unsigned int>(permutations.n_rows));
    }

    arma::Col<unsigned int> centers(permutations.n_rows);
    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      centers.at(n) = n;
    }

    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      arma::Row<unsigned int> histogram = arma::hist(permutations.row(n), centers);
      CHECK(0.05 > static_cast<double>(histogram.max() - histogram.min()) / permutations.n_cols);
    }
  }

  SECTION("Partial permutation") {
    arma::Mat<unsigned int>::fixed<10, 40000> permutations;
    for (std::size_t n = 0; n < permutations.n_cols; ++n) {
      permutations.col(n) = hop::getRandomPermutation(static_cast<unsigned int>(permutations.n_rows + 1), static_cast<unsigned int>(permutations.n_rows));
    }

    arma::Col<unsigned int> centers(permutations.n_rows);
    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      centers.at(n) = n;
    }

    for (std::size_t n = 0; n < permutations.n_rows; ++n) {
      arma::Row<unsigned int> histogram = arma::hist(permutations.row(n), centers);
      CHECK(0.1 > static_cast<double>(histogram.max() - histogram.min()) / permutations.n_cols);
    }
  }
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2016 John Connor
 * Copyright (c) 2016-2017 The Vcash developers
 *
 * This file is part of vcash.
 *
 * vcash is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef COIN_RPC_JSON_PARSER_HPP
#define COIN_RPC_JSON_PARSER_HPP

#include <string>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/json_parser_read.hpp>
#include <boost/property_tree/detail/json_parser_write.hpp>
#include <boost/property_tree/detail/json_parser_error.hpp>

namespace coin {

    /**
     * Implements a JSON-RPC parser.
     */
    class rpc_json_parser
    {
        public:

            template <typename T>
            struct translator
            {
                typedef T internal_type;
                typedef T external_type;

                boost::optional<T> get_value(const T & v)
                {
                    return v.substr(1, v.size() - 2) ;
                }

                boost::optional<T> put_value(const T & v)
                {
                    return '"' + v + '"';
                }
            };

            template<class Ptree>
            static void write_json(
                std::basic_ostream<typename Ptree::key_type::value_type> &
                stream, const Ptree & pt, bool pretty = true
                )
            {
                write_json_internal(
                    stream, pt, std::string(), pretty
                );
            }

        private:

            // ...

        protected:

            template<class Ch>
            static std::basic_string<Ch> create_escapes(
                const std::basic_string<Ch> & s
                )
            {
                std::basic_string<Ch> result;

                auto b = s.begin();
                auto e = s.end();

                while (b != e)
                {
                    if (
                        *b == 0x20 || *b == 0x21 ||
                        (*b >= 0x23 && *b <= 0x2E) ||
                        (*b >= 0x30 && *b <= 0x5B) ||
                        (*b >= 0x5D && *b <= 0xFF)
                        )
                    {
                        result += *b;
                    }
                    else if (*b == Ch('\b'))
                    {
                        result += Ch('\\'), result += Ch('b');
                    }
                    else if (*b == Ch('\f'))
                    {
                        result += Ch('\\'), result += Ch('f');
                    }
                    else if (*b == Ch('\n'))
                    {
                        result += Ch('\\'), result += Ch('n');
                    }
                    else if (*b == Ch('\r'))
                    {
                        result += Ch('\\'), result += Ch('r');
                    }
                    else if (*b == Ch('/'))
                    {
                        result += Ch('\\'), result += Ch('/');
                    }
                    else if (*b == Ch('"'))
                    {
                        result+= Ch('"');
                    }
                    else if (*b == Ch('\\'))
                    {
                        result += Ch('\\'), result += Ch('\\');
                    }
                    else
                    {
                        const char * hexdigits = "0123456789ABCDEF";

                        typedef typename boost::make_unsigned<Ch>::type UCh;

                        unsigned long u =
                            (std::min)(static_cast<unsigned long>(
                            static_cast<UCh>(*b)), 0xFFFFul
                        );

                        auto d1 = u / 4096; u -= d1 * 4096;
                        auto d2 = u / 256; u -= d2 * 256;
                        auto d3 = u / 16; u -= d3 * 16;
                        auto d4 = u;

                        result += Ch('\\'); result += Ch('u');
                        result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
                        result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
                    }
                    ++b;
                }
                return result;
            }

            template<class Ptree>
            static void write_json_helper(
                std::basic_ostream<typename Ptree::key_type::value_type> &
                stream, const Ptree & pt, int indent, bool pretty
                )
            {
                typedef typename Ptree::key_type::value_type Ch;
                typedef typename std::basic_string<Ch> Str;

                if (pt.empty())
                {
                    auto data = create_escapes(pt.template get_value<Str>());

                    stream << data;

                }
                else if (pt.count(Str()) == pt.size())
                {
                    stream << Ch('[');

                    if (pretty)
                    {
                        stream << Ch('\n');
                    }

                    auto it = pt.begin();

                    for (; it != pt.end(); ++it)
                    {
                        if (pretty)
                        {
                            stream << Str(4 * (indent + 1), Ch(' '));
                        }

                        write_json_helper(
                            stream, it->second, indent + 1, pretty
                        );

                        if (boost::next(it) != pt.end())
                        {
                            stream << Ch(',');
                        }

                        if (pretty)
                        {
                            stream << Ch('\n');
                        }
                    }
                    if (pretty) stream << Str(4 * indent, Ch(' '));
                    {
                        stream << Ch(']');
                    }

                }
                else
                {
                    stream << Ch('{');

                    if (pretty)
                    {
                        stream << Ch('\n');
                    }

                    typename Ptree::const_iterator it = pt.begin();

                    for (; it != pt.end(); ++it)
                    {
                        if (pretty)
                        {
                            stream << Str(4 * (indent + 1), Ch(' '));
                        }

                        stream << Ch('"') <<
                            create_escapes(it->first) << Ch('"') << Ch(':')
                        ;

                        if (pretty)
                        {
                            if (it->second.empty())
                            {
                                stream << Ch(' ');
                            }
                            else
                            {
                                stream <<
                                    Ch('\n') << Str(4 * (indent + 1), Ch(' '))
                                ;
                            }
                        }

                        write_json_helper(
                            stream, it->second, indent + 1, pretty
                        );

                        if (boost::next(it) != pt.end())
                        {
                            stream << Ch(',');
                        }

                        if (pretty)
                        {
                            stream << Ch('\n');
                        }
                    }

                    if (pretty) stream << Str(4 * indent, Ch(' '));
                    {
                        stream << Ch('}');
                    }
                }

            }

            template<class Ptree>
            static bool verify_json(const Ptree & pt, int depth)
            {
                typedef typename Ptree::key_type::value_type Ch;
                typedef typename std::basic_string<Ch> Str;

                if (depth == 0 && !pt.template get_value<Str>().empty())
                {
                    return false;
                }

                if (!pt.template get_value<Str>().empty() && !pt.empty())
                {
                    return false;
                }

                typename Ptree::const_iterator it = pt.begin();

                for (; it != pt.end(); ++it)
                {
                    if (!verify_json(it->second, depth + 1))
                    {
                        return false;
                    }
                }

                return true;

            }

            template<class Ptree>
            static void write_json_internal(
                std::basic_ostream<typename Ptree::key_type::value_type> & stream,
                const Ptree & pt, const std::string & filename, bool pretty
                )
            {
                if (verify_json(pt, 0) == false)
                {
                    BOOST_PROPERTY_TREE_THROW(
                        boost::property_tree::json_parser::json_parser_error(
                        "ptree contains data that cannot be represented "
                        "in JSON format", filename, 0)
                    );
                }

                write_json_helper(stream, pt, 0, pretty);
                stream << std::endl;

                if (stream.good() == false)
                {
                    BOOST_PROPERTY_TREE_THROW(
                        boost::property_tree::json_parser::json_parser_error(
                        "write error", filename, 0)
                    );
                }
            }
    };

} // namespace coin

#endif // COIN_RPC_JSON_PARSER_HPP
<commit_msg>Boost version check for property_tree paths<commit_after>/*
 * Copyright (c) 2013-2016 John Connor
 * Copyright (c) 2016-2017 The Vcash developers
 *
 * This file is part of vcash.
 *
 * vcash is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef COIN_RPC_JSON_PARSER_HPP
#define COIN_RPC_JSON_PARSER_HPP

#include <string>

#include <boost/version.hpp>
#include <boost/property_tree/ptree.hpp>
#if BOOST_VERSION <= 105800
#include <boost/property_tree/detail/json_parser_read.hpp>
#include <boost/property_tree/detail/json_parser_write.hpp>
#include <boost/property_tree/detail/json_parser_error.hpp>
#elif BOOST_VERSION <= 106000
#include <boost/property_tree/detail/json_parser/read.hpp>
#include <boost/property_tree/detail/json_parser_write.hpp>
#include <boost/property_tree/detail/json_parser_error.hpp>
#else
#include <boost/property_tree/json_parser/detail/read.hpp>
#include <boost/property_tree/json_parser/detail/write.hpp>
#include <boost/property_tree/json_parser/error.hpp>
#endif

namespace coin {

    /**
     * Implements a JSON-RPC parser.
     */
    class rpc_json_parser
    {
        public:

            template <typename T>
            struct translator
            {
                typedef T internal_type;
                typedef T external_type;

                boost::optional<T> get_value(const T & v)
                {
                    return v.substr(1, v.size() - 2) ;
                }

                boost::optional<T> put_value(const T & v)
                {
                    return '"' + v + '"';
                }
            };

            template<class Ptree>
            static void write_json(
                std::basic_ostream<typename Ptree::key_type::value_type> &
                stream, const Ptree & pt, bool pretty = true
                )
            {
                write_json_internal(
                    stream, pt, std::string(), pretty
                );
            }

        private:

            // ...

        protected:

            template<class Ch>
            static std::basic_string<Ch> create_escapes(
                const std::basic_string<Ch> & s
                )
            {
                std::basic_string<Ch> result;

                auto b = s.begin();
                auto e = s.end();

                while (b != e)
                {
                    if (
                        *b == 0x20 || *b == 0x21 ||
                        (*b >= 0x23 && *b <= 0x2E) ||
                        (*b >= 0x30 && *b <= 0x5B) ||
                        (*b >= 0x5D && *b <= 0xFF)
                        )
                    {
                        result += *b;
                    }
                    else if (*b == Ch('\b'))
                    {
                        result += Ch('\\'), result += Ch('b');
                    }
                    else if (*b == Ch('\f'))
                    {
                        result += Ch('\\'), result += Ch('f');
                    }
                    else if (*b == Ch('\n'))
                    {
                        result += Ch('\\'), result += Ch('n');
                    }
                    else if (*b == Ch('\r'))
                    {
                        result += Ch('\\'), result += Ch('r');
                    }
                    else if (*b == Ch('/'))
                    {
                        result += Ch('\\'), result += Ch('/');
                    }
                    else if (*b == Ch('"'))
                    {
                        result+= Ch('"');
                    }
                    else if (*b == Ch('\\'))
                    {
                        result += Ch('\\'), result += Ch('\\');
                    }
                    else
                    {
                        const char * hexdigits = "0123456789ABCDEF";

                        typedef typename boost::make_unsigned<Ch>::type UCh;

                        unsigned long u =
                            (std::min)(static_cast<unsigned long>(
                            static_cast<UCh>(*b)), 0xFFFFul
                        );

                        auto d1 = u / 4096; u -= d1 * 4096;
                        auto d2 = u / 256; u -= d2 * 256;
                        auto d3 = u / 16; u -= d3 * 16;
                        auto d4 = u;

                        result += Ch('\\'); result += Ch('u');
                        result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
                        result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
                    }
                    ++b;
                }
                return result;
            }

            template<class Ptree>
            static void write_json_helper(
                std::basic_ostream<typename Ptree::key_type::value_type> &
                stream, const Ptree & pt, int indent, bool pretty
                )
            {
                typedef typename Ptree::key_type::value_type Ch;
                typedef typename std::basic_string<Ch> Str;

                if (pt.empty())
                {
                    auto data = create_escapes(pt.template get_value<Str>());

                    stream << data;

                }
                else if (pt.count(Str()) == pt.size())
                {
                    stream << Ch('[');

                    if (pretty)
                    {
                        stream << Ch('\n');
                    }

                    auto it = pt.begin();

                    for (; it != pt.end(); ++it)
                    {
                        if (pretty)
                        {
                            stream << Str(4 * (indent + 1), Ch(' '));
                        }

                        write_json_helper(
                            stream, it->second, indent + 1, pretty
                        );

                        if (boost::next(it) != pt.end())
                        {
                            stream << Ch(',');
                        }

                        if (pretty)
                        {
                            stream << Ch('\n');
                        }
                    }
                    if (pretty) stream << Str(4 * indent, Ch(' '));
                    {
                        stream << Ch(']');
                    }

                }
                else
                {
                    stream << Ch('{');

                    if (pretty)
                    {
                        stream << Ch('\n');
                    }

                    typename Ptree::const_iterator it = pt.begin();

                    for (; it != pt.end(); ++it)
                    {
                        if (pretty)
                        {
                            stream << Str(4 * (indent + 1), Ch(' '));
                        }

                        stream << Ch('"') <<
                            create_escapes(it->first) << Ch('"') << Ch(':')
                        ;

                        if (pretty)
                        {
                            if (it->second.empty())
                            {
                                stream << Ch(' ');
                            }
                            else
                            {
                                stream <<
                                    Ch('\n') << Str(4 * (indent + 1), Ch(' '))
                                ;
                            }
                        }

                        write_json_helper(
                            stream, it->second, indent + 1, pretty
                        );

                        if (boost::next(it) != pt.end())
                        {
                            stream << Ch(',');
                        }

                        if (pretty)
                        {
                            stream << Ch('\n');
                        }
                    }

                    if (pretty) stream << Str(4 * indent, Ch(' '));
                    {
                        stream << Ch('}');
                    }
                }

            }

            template<class Ptree>
            static bool verify_json(const Ptree & pt, int depth)
            {
                typedef typename Ptree::key_type::value_type Ch;
                typedef typename std::basic_string<Ch> Str;

                if (depth == 0 && !pt.template get_value<Str>().empty())
                {
                    return false;
                }

                if (!pt.template get_value<Str>().empty() && !pt.empty())
                {
                    return false;
                }

                typename Ptree::const_iterator it = pt.begin();

                for (; it != pt.end(); ++it)
                {
                    if (!verify_json(it->second, depth + 1))
                    {
                        return false;
                    }
                }

                return true;

            }

            template<class Ptree>
            static void write_json_internal(
                std::basic_ostream<typename Ptree::key_type::value_type> & stream,
                const Ptree & pt, const std::string & filename, bool pretty
                )
            {
                if (verify_json(pt, 0) == false)
                {
                    BOOST_PROPERTY_TREE_THROW(
                        boost::property_tree::json_parser::json_parser_error(
                        "ptree contains data that cannot be represented "
                        "in JSON format", filename, 0)
                    );
                }

                write_json_helper(stream, pt, 0, pretty);
                stream << std::endl;

                if (stream.good() == false)
                {
                    BOOST_PROPERTY_TREE_THROW(
                        boost::property_tree::json_parser::json_parser_error(
                        "write error", filename, 0)
                    );
                }
            }
    };

} // namespace coin

#endif // COIN_RPC_JSON_PARSER_HPP
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2010, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_snutils.h"
#include "condor_debug.h"

#include "stl_string_utils.h"

void assign(std::string& dst, const MyString& src) {
    dst = src.Value();
}
void assign(MyString& dst, const std::string& src) {
    dst = src.c_str();
}

bool operator==(const MyString& L, const std::string& R) { return R == L.Value(); }
bool operator==(const std::string& L, const MyString& R) { return L == R.Value(); }
bool operator!=(const MyString& L, const std::string& R) { return R != L.Value(); }
bool operator!=(const std::string& L, const MyString& R) { return L != R.Value(); }
bool operator<(const MyString& L, const std::string& R) { return R > L.Value(); }
bool operator<(const std::string& L, const MyString& R) { return L < R.Value(); }
bool operator>(const MyString& L, const std::string& R) { return R < L.Value(); }
bool operator>(const std::string& L, const MyString& R) { return L > R.Value(); }
bool operator<=(const MyString& L, const std::string& R) { return R >= L.Value(); }
bool operator<=(const std::string& L, const MyString& R) { return L <= R.Value(); }
bool operator>=(const MyString& L, const std::string& R) { return R <= L.Value(); }
bool operator>=(const std::string& L, const MyString& R) { return L >= R.Value(); }

int sprintf(std::string& s, const char* format, va_list pargs) {
    char fixbuf[STL_STRING_UTILS_FIXBUF];
    const int fixlen = sizeof(fixbuf)/sizeof(fixbuf[0]);
	int n;
	va_list  args;

    // Attempt to write to fixed buffer.  condor_snutils.{h,cpp}
    // provides an implementation of vsnprintf() in windows, so this
    // logic works cross platform
#if !defined(va_copy)
	n = vsnprintf(fixbuf, fixlen, format, pargs);
#else
	va_copy(args, pargs);
	n = vsnprintf(fixbuf, fixlen, format, args);
	va_end(args);
#endif

    // In this case, fixed buffer was sufficient so we're done.
    // Return number of chars written.
    if (n < fixlen) {
        s = fixbuf;
        return n;
    }

    // Otherwise, the fixed buffer was not large enough, but return from
    // vsnprintf() tells us how much memory we need now.
    n += 1;
    char* varbuf = NULL;
    // Handle 'new' behavior mode of returning NULL or throwing exception
    try {
        varbuf = new char[n];
    } catch (...) {
        varbuf = NULL;
    }
    if (NULL == varbuf) EXCEPT("Failed to allocate char buffer of %d chars", n);

    // re-print, using buffer of sufficient size
#if !defined(va_copy)
	int nn = vsnprintf(varbuf, n, format, pargs);
#else
	va_copy(args, pargs);
	int nn = vsnprintf(varbuf, n, format, args);
	va_end(args);
#endif

    // Sanity check.  This ought not to happen.  Ever.
    if (nn >= n) EXCEPT("Insufficient buffer size (%d) for printing %d chars", n, nn);

    // safe to do string assignment
    s = varbuf;

    // clean up our allocated buffer
    delete[] varbuf;

    // return number of chars written
    return nn;
}

int sprintf(std::string& s, const char* format, ...) {
    va_list args;
    va_start(args, format);
    int r = sprintf(s, format, args);
    va_end(args);
    return r;
}

int sprintf(MyString& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    // this gets me the sprintf-standard return value (# chars printed)
    int r = sprintf(t, format, args);
    va_end(args);
    assign(s, t);
    return r;
}

int sprintf_cat(std::string& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    int r = sprintf(t, format, args);
    va_end(args);
    s += t;
    return r;
}

int sprintf_cat(MyString& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    int r = sprintf(t, format, args);
    va_end(args);
    s += t.c_str();
    return r;
}

bool chomp(std::string &str)
{
	bool chomped = false;
	if( str.empty() ) {
		return chomped;
	}
	if( str[str.length()-1] == '\n' ) {
		str.erase(str.length()-1);
		chomped = true;
		if( ( str.length() > 0 ) && ( str[str.length()-1] == '\r' ) ) {
			str.erase(str.length()-1);
		}
	}
	return chomped;
}

void trim( std::string &str )
{
	if( str.empty() ) {
		return;
	}
	unsigned	begin = 0;
	while ( begin < str.length() && isspace(str[begin]) ) {
		++begin;
	}

	int			end = str.length() - 1;
	while ( end >= 0 && isspace(str[end]) ) {
		--end;
	}

	if ( begin != 0 || end != (int)(str.length()) - 1 ) {
		str = str.substr(begin, (end - begin) + 1);
	}
}

#ifndef _tolower
#define _tolower(c) ((c) + 'a' - 'A')
#endif

#ifndef _toupper
#define _toupper(c) ((c) + 'A' - 'a')
#endif

void upper_case( std::string &str )
{
	for ( int i = 0; str[i]; i++ ) {
		if ( str[i] >= 'a' && str[i] <= 'z' ) {
			str[i] = _toupper( str[i] );
		}
	}
}

void lower_case( std::string &str )
{
	for ( int i = 0; str[i]; i++ ) {
		if ( str[i] >= 'A' && str[i] <= 'Z' ) {
			str[i] = _tolower( str[i] );
		}
	}
}

static char *tokenBuf = NULL;
static char *nextToken = NULL;

void Tokenize(const MyString &str)
{
	Tokenize( str.Value() );
}

void Tokenize(const std::string &str)
{
	Tokenize( str.c_str() );
}

void Tokenize(const char *str)
{
	free( tokenBuf );
	tokenBuf = NULL;
	nextToken = NULL;
	if ( str ) {
		tokenBuf = strdup( str );
		if ( strlen( tokenBuf ) > 0 ) {
			nextToken = tokenBuf;
		}
	}
}

const char *GetNextToken(const char *delim, bool skipBlankTokens)
{
	const char *result = nextToken;

	if ( !delim || strlen(delim) == 0 ) {
		result = NULL;
	}

	if ( result != NULL ) {
		while ( *nextToken != '\0' && index(delim, *nextToken) == NULL ) {
			nextToken++;
		}

		if ( *nextToken != '\0' ) {
			*nextToken = '\0';
			nextToken++;
		} else {
			nextToken = NULL;
		}
	}

	if ( skipBlankTokens && result && strlen(result) == 0 ) {
		result = GetNextToken(delim, skipBlankTokens);
	}

	return result;
}

void join(std::vector< std::string > &v, char const *delim, std::string &result)
{
	std::vector<std::string>::iterator it;
	for(it = v.begin();
		it != v.end();
		it++)
	{
		if( result.size() ) {
			result += delim;
		}
		result += (*it);
	}
}
<commit_msg>fix potential bugs found by prefast in condor_utils. change snprintf to vsnprintf in stl_string_utils<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2010, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_snutils.h"
#include "condor_debug.h"

#include "stl_string_utils.h"

void assign(std::string& dst, const MyString& src) {
    dst = src.Value();
}
void assign(MyString& dst, const std::string& src) {
    dst = src.c_str();
}

bool operator==(const MyString& L, const std::string& R) { return R == L.Value(); }
bool operator==(const std::string& L, const MyString& R) { return L == R.Value(); }
bool operator!=(const MyString& L, const std::string& R) { return R != L.Value(); }
bool operator!=(const std::string& L, const MyString& R) { return L != R.Value(); }
bool operator<(const MyString& L, const std::string& R) { return R > L.Value(); }
bool operator<(const std::string& L, const MyString& R) { return L < R.Value(); }
bool operator>(const MyString& L, const std::string& R) { return R < L.Value(); }
bool operator>(const std::string& L, const MyString& R) { return L > R.Value(); }
bool operator<=(const MyString& L, const std::string& R) { return R >= L.Value(); }
bool operator<=(const std::string& L, const MyString& R) { return L <= R.Value(); }
bool operator>=(const MyString& L, const std::string& R) { return R <= L.Value(); }
bool operator>=(const std::string& L, const MyString& R) { return L >= R.Value(); }

int vsprintf(std::string& s, const char* format, va_list pargs) {
    char fixbuf[STL_STRING_UTILS_FIXBUF];
    const int fixlen = sizeof(fixbuf)/sizeof(fixbuf[0]);
	int n;
	va_list  args;

    // Attempt to write to fixed buffer.  condor_snutils.{h,cpp}
    // provides an implementation of vsnprintf() in windows, so this
    // logic works cross platform
#if !defined(va_copy)
	n = vsnprintf(fixbuf, fixlen, format, pargs);
#else
	va_copy(args, pargs);
	n = vsnprintf(fixbuf, fixlen, format, args);
	va_end(args);
#endif

    // In this case, fixed buffer was sufficient so we're done.
    // Return number of chars written.
    if (n < fixlen) {
        s = fixbuf;
        return n;
    }

    // Otherwise, the fixed buffer was not large enough, but return from
    // vsnprintf() tells us how much memory we need now.
    n += 1;
    char* varbuf = NULL;
    // Handle 'new' behavior mode of returning NULL or throwing exception
    try {
        varbuf = new char[n];
    } catch (...) {
        varbuf = NULL;
    }
    if (NULL == varbuf) EXCEPT("Failed to allocate char buffer of %d chars", n);

    // re-print, using buffer of sufficient size
#if !defined(va_copy)
	int nn = vsnprintf(varbuf, n, format, pargs);
#else
	va_copy(args, pargs);
	int nn = vsnprintf(varbuf, n, format, args);
	va_end(args);
#endif

    // Sanity check.  This ought not to happen.  Ever.
    if (nn >= n) EXCEPT("Insufficient buffer size (%d) for printing %d chars", n, nn);

    // safe to do string assignment
    s = varbuf;

    // clean up our allocated buffer
    delete[] varbuf;

    // return number of chars written
    return nn;
}

int sprintf(std::string& s, const char* format, ...) {
    va_list args;
    va_start(args, format);
    int r = vsprintf(s, format, args);
    va_end(args);
    return r;
}

int sprintf(MyString& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    // this gets me the sprintf-standard return value (# chars printed)
    int r = vsprintf(t, format, args);
    va_end(args);
    assign(s, t);
    return r;
}

int sprintf_cat(std::string& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    int r = vsprintf(t, format, args);
    va_end(args);
    s += t;
    return r;
}

int sprintf_cat(MyString& s, const char* format, ...) {
    va_list args;
    std::string t;
    va_start(args, format);
    int r = vsprintf(t, format, args);
    va_end(args);
    s += t.c_str();
    return r;
}

bool chomp(std::string &str)
{
	bool chomped = false;
	if( str.empty() ) {
		return chomped;
	}
	if( str[str.length()-1] == '\n' ) {
		str.erase(str.length()-1);
		chomped = true;
		if( ( str.length() > 0 ) && ( str[str.length()-1] == '\r' ) ) {
			str.erase(str.length()-1);
		}
	}
	return chomped;
}

void trim( std::string &str )
{
	if( str.empty() ) {
		return;
	}
	unsigned	begin = 0;
	while ( begin < str.length() && isspace(str[begin]) ) {
		++begin;
	}

	int			end = str.length() - 1;
	while ( end >= 0 && isspace(str[end]) ) {
		--end;
	}

	if ( begin != 0 || end != (int)(str.length()) - 1 ) {
		str = str.substr(begin, (end - begin) + 1);
	}
}

#ifndef _tolower
#define _tolower(c) ((c) + 'a' - 'A')
#endif

#ifndef _toupper
#define _toupper(c) ((c) + 'A' - 'a')
#endif

void upper_case( std::string &str )
{
	for ( int i = 0; str[i]; i++ ) {
		if ( str[i] >= 'a' && str[i] <= 'z' ) {
			str[i] = _toupper( str[i] );
		}
	}
}

void lower_case( std::string &str )
{
	for ( int i = 0; str[i]; i++ ) {
		if ( str[i] >= 'A' && str[i] <= 'Z' ) {
			str[i] = _tolower( str[i] );
		}
	}
}

static char *tokenBuf = NULL;
static char *nextToken = NULL;

void Tokenize(const MyString &str)
{
	Tokenize( str.Value() );
}

void Tokenize(const std::string &str)
{
	Tokenize( str.c_str() );
}

void Tokenize(const char *str)
{
	free( tokenBuf );
	tokenBuf = NULL;
	nextToken = NULL;
	if ( str ) {
		tokenBuf = strdup( str );
		if ( strlen( tokenBuf ) > 0 ) {
			nextToken = tokenBuf;
		}
	}
}

const char *GetNextToken(const char *delim, bool skipBlankTokens)
{
	const char *result = nextToken;

	if ( !delim || strlen(delim) == 0 ) {
		result = NULL;
	}

	if ( result != NULL ) {
		while ( *nextToken != '\0' && index(delim, *nextToken) == NULL ) {
			nextToken++;
		}

		if ( *nextToken != '\0' ) {
			*nextToken = '\0';
			nextToken++;
		} else {
			nextToken = NULL;
		}
	}

	if ( skipBlankTokens && result && strlen(result) == 0 ) {
		result = GetNextToken(delim, skipBlankTokens);
	}

	return result;
}

void join(std::vector< std::string > &v, char const *delim, std::string &result)
{
	std::vector<std::string>::iterator it;
	for(it = v.begin();
		it != v.end();
		it++)
	{
		if( result.size() ) {
			result += delim;
		}
		result += (*it);
	}
}
<|endoftext|>


<commit_before>#include <pthread.h>
#include <signal.h>
#include <arpa/inet.h>

#include <cstdio>
#include <sstream>
#include <vector>
#include <map>

#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "loom/config.h"
#include "loom/Utils.h"

using namespace std;
using namespace llvm;

// TODO: find a way to display more description on action
static cl::opt<string> ControllerAction(cl::Positional,
                                        cl::desc("<action>"),
                                        cl::Required);
static cl::list<string> Args(cl::ConsumeAfter, cl::desc("<arguments>..."));

// protect <CtrlClientSock> and <Daemons>
static pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
static int CtrlClientSock = -1;
static map<pid_t, int> Daemons;

// needn't be protected, because it is only used by HandleControllerClient.
static vector<string> FilterFileNames(MaxNumFilters);

int HandleDaemon(int ClientSock, pid_t PID) {
  pthread_mutex_lock(&Mutex);
  Daemons[PID] = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Response[MaxBufferSize];
  while (ReceiveMessage(ClientSock, Response) == 0) {
    pthread_mutex_lock(&Mutex);
    if (CtrlClientSock == -1) {
      errs() << "Loom controller client is not started yet\n";
      pthread_mutex_unlock(&Mutex);
      continue;
    }
    int Sock = CtrlClientSock;
    pthread_mutex_unlock(&Mutex);

    // Forward the response to the controller client.
    // TODO: The controller client may receive multiple responses from a
    // multiprocess program. We could have better handle this situation by
    // sending OK only when all processes have successfully installed the
    // filter, and deleting the filter if any process fails.
    SendMessage(Sock, Response);
  }

  // Remove <ClientSock> from <Daemons>.
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I) {
    if (I->second == ClientSock) {
      Daemons.erase(I);
      break;
    }
  }
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void HandleAddFilter(const string &FilterFileName) {
  if (find(FilterFileNames.begin(), FilterFileNames.end(), FilterFileName) !=
      FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "this filter is already installed");
    return;
  }

  // find the first unused ID
  vector<string>::iterator Pos = find(FilterFileNames.begin(),
                                      FilterFileNames.end(),
                                      "");
  if (Pos == FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "too many filters");
    return;
  }
  *Pos = FilterFileName;

  ostringstream OS;
  OS << "add " << (Pos - FilterFileNames.begin()) << " " << FilterFileName;
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I)
    SendMessage(I->second, OS.str().c_str());
  pthread_mutex_unlock(&Mutex);
}

void HandleDeleteFilter(unsigned FilterID) {
  if (FilterID >= MaxNumFilters) {
    SendMessage(CtrlClientSock, "invalid ID");
    return;
  }
  if (FilterFileNames[FilterID] == "") {
    SendMessage(CtrlClientSock, "this ID does not exist");
    return;
  }
  FilterFileNames[FilterID] = "";

  ostringstream OS;
  OS << "del " << FilterID;
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I)
    SendMessage(I->second, OS.str().c_str());
  pthread_mutex_unlock(&Mutex);
}

void HandleListFilters() {
  ostringstream OS;
  bool First = true;
  for (size_t i = 0; i < FilterFileNames.size(); ++i) {
    if (FilterFileNames[i] != "") {
      if (First)
        First = false;
      else
        OS << "\n";
      OS << i << "\t" << FilterFileNames[i];
    }
  }
  SendMessage(CtrlClientSock, OS.str().c_str());
}

int HandleControllerClient(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  if (CtrlClientSock != -1) {
    errs() << "another Loom controller client is running\n";
    pthread_mutex_unlock(&Mutex);
    return -1;
  }
  CtrlClientSock = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Cmd[MaxBufferSize];
  // benign race when reading <CtrlClientSock>
  while (ReceiveMessage(CtrlClientSock, Cmd) == 0) {
    istringstream IS(Cmd);
    string Op;
    if (!(IS >> Op)) {
      SendMessage(CtrlClientSock, "wrong format");
      continue;
    }
    if (Op == "add") {
      string FilterFileName;
      if (!(IS >> FilterFileName)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleAddFilter(FilterFileName);
    } else if (Op == "del") {
      unsigned FilterID;
      if (!(IS >> FilterID)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleDeleteFilter(FilterID);
    } else if (Op == "ls") {
      HandleListFilters();
    } else {
      SendMessage(CtrlClientSock, "unknown command");
    }
  }

  // Reset <CtrlClientSock> to allow another controller.
  pthread_mutex_lock(&Mutex);
  CtrlClientSock = -1;
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void *HandleClient(void *Arg) {
  int ClientSock = (intptr_t)Arg;

  // Identify the client.
  char Buffer[MaxBufferSize];
  if (ReceiveMessage(ClientSock, Buffer) == -1) {
    close(ClientSock);
    return (void *)-1;
  }

  int Ret = 0;
  if (strncmp(Buffer, "iam loom_daemon", strlen("iam loom_daemon")) == 0) {
    outs() << "which is a Loom daemon\n";
    pid_t PID;
    if (sscanf(Buffer, "iam loom_daemon %d", &PID) != 1)
      Ret = -1;
    else
      Ret = HandleDaemon(ClientSock, PID);
  } else if (strcmp(Buffer, "iam loom_ctl") == 0) {
    outs() << "which is a Loom controller client\n";
    Ret = HandleControllerClient(ClientSock);
  } else {
    outs() << "which is an unknown client. ";
    outs() << "close the connection immediately\n";
  }

  close(ClientSock);
  return (void *)Ret;
}

int RunControllerServer() {
  // Ignore SIGPIPE.
  signal(SIGPIPE, SIG_IGN);

  int AcceptSock = socket(AF_INET, SOCK_STREAM, 0);
  if (AcceptSock == -1) {
    perror("socket");
    return -1;
  }
  int TrueVal = 1;
  if (setsockopt(AcceptSock, SOL_SOCKET,
                 SO_REUSEADDR, &TrueVal, sizeof(int)) == -1) {
    perror("setsockopt");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof(ServerAddr));
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  ServerAddr.sin_addr.s_addr = INADDR_ANY;
  if (bind(AcceptSock,
           (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) == -1) {
    perror("bind");
    return -1;
  }

  if (listen(AcceptSock, 5) == -1) {
    perror("listen");
    return -1;
  }

  outs() << "Loom controller started. ";
  outs() << "Press Ctrl+C to exit...\n";
  struct sockaddr_in ClientAddr;
  socklen_t ClientAddrLen = sizeof(ClientAddr);
  while (true) {
    int ClientSock = accept(AcceptSock,
                            (struct sockaddr *)&ClientAddr, &ClientAddrLen);
    if (ClientSock == -1) {
      perror("accept");
      return -1;
    }

    outs() << "connected by " << inet_ntoa(ClientAddr.sin_addr) << ":" <<
        ntohs(ClientAddr.sin_port) << ", ";
    pthread_t child;
    if (pthread_create(&child, NULL, HandleClient, (void *)ClientSock) != 0) {
      perror("pthread_create");
      return -1;
    }
  }

  return 0;
}

int CommandAddFilter(int CtrlServerSock, const string &FilterFileName) {
  ostringstream OS;
  OS << "add ";
  // Convert to full path whenever possible, so that the user can use relative
  // path.
  if (char *FullPath = realpath(FilterFileName.c_str(), NULL)) {
    OS << FullPath;
    free(FullPath);
  } else {
    OS << FilterFileName;
  }
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandDeleteFilter(int CtrlServerSock, unsigned FilterID) {
  ostringstream OS;
  OS << "del " << FilterID;
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandListFilters(int CtrlServerSock) {
  return SendMessage(CtrlServerSock, "ls");
}

int RunControllerClient() {
  int CtrlServerSock = socket(AF_INET, SOCK_STREAM, 0);
  if (CtrlServerSock == -1) {
    perror("socket");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof ServerAddr);
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_addr.s_addr = inet_addr(CONTROLLER_IP);
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  if (connect(CtrlServerSock,
              (struct sockaddr *)&ServerAddr, sizeof ServerAddr) == -1) {
    perror("failed to connect to the controller server");
    return -1;
  }

  if (SendMessage(CtrlServerSock, "iam loom_ctl") == -1) {
    close(CtrlServerSock);
    return -1;
  }

  int Ret = 0;
  if (ControllerAction == "add") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandAddFilter(CtrlServerSock, Args[0]);
    }
  } else if (ControllerAction == "delete") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      // TODO: check Args[0] is a number
      Ret = CommandDeleteFilter(CtrlServerSock, atoi(Args[0].c_str()));
    }
  } else if (ControllerAction == "ls") {
    if (Args.size() != 0) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandListFilters(CtrlServerSock);
    }
  } else {
    assert(false);
  }

  // Don't bother receiving the response if sending already failed.
  if (Ret == 0) {
    char Response[MaxBufferSize] = {'\0'};
    Ret = ReceiveMessage(CtrlServerSock, Response);
    if (Ret == 0) {
      outs() << Response << "\n";
    }
  }

  close(CtrlServerSock);
  return Ret;
}

int main(int argc, char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, "Loom controller");
  if (ControllerAction == "server") {
    if (RunControllerServer() == -1)
      return 1;
  } else if (ControllerAction == "add" ||
             ControllerAction == "delete" ||
             ControllerAction == "ls") {
    if (RunControllerClient() == -1)
      return 1;
  } else {
    errs() << "Not implemented yet\n";
  }
  return 0;
}
<commit_msg>Added a ps command<commit_after>#include <pthread.h>
#include <signal.h>
#include <arpa/inet.h>

#include <cstdio>
#include <sstream>
#include <vector>
#include <map>

#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "loom/config.h"
#include "loom/Utils.h"

using namespace std;
using namespace llvm;

// TODO: find a way to display more description on action
static cl::opt<string> ControllerAction(cl::Positional,
                                        cl::desc("<action>"),
                                        cl::Required);
static cl::list<string> Args(cl::ConsumeAfter, cl::desc("<arguments>..."));

// protect <CtrlClientSock> and <Daemons>
static pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
static int CtrlClientSock = -1;
static map<pid_t, int> Daemons;

// needn't be protected, because it is only used by HandleControllerClient.
static vector<string> FilterFileNames(MaxNumFilters);

int HandleDaemon(int ClientSock, pid_t PID) {
  pthread_mutex_lock(&Mutex);
  Daemons[PID] = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Response[MaxBufferSize];
  while (ReceiveMessage(ClientSock, Response) == 0) {
    pthread_mutex_lock(&Mutex);
    if (CtrlClientSock == -1) {
      errs() << "Loom controller client is not started yet\n";
      pthread_mutex_unlock(&Mutex);
      continue;
    }
    int Sock = CtrlClientSock;
    pthread_mutex_unlock(&Mutex);

    // Forward the response to the controller client.
    // TODO: The controller client may receive multiple responses from a
    // multiprocess program. We could have better handle this situation by
    // sending OK only when all processes have successfully installed the
    // filter, and deleting the filter if any process fails.
    SendMessage(Sock, Response);
  }

  // Remove <ClientSock> from <Daemons>.
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I) {
    if (I->second == ClientSock) {
      Daemons.erase(I);
      break;
    }
  }
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void HandleAddFilter(const string &FilterFileName) {
  if (find(FilterFileNames.begin(), FilterFileNames.end(), FilterFileName) !=
      FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "this filter is already installed");
    return;
  }

  // find the first unused ID
  vector<string>::iterator Pos = find(FilterFileNames.begin(),
                                      FilterFileNames.end(),
                                      "");
  if (Pos == FilterFileNames.end()) {
    SendMessage(CtrlClientSock, "too many filters");
    return;
  }
  *Pos = FilterFileName;

  ostringstream OS;
  OS << "add " << (Pos - FilterFileNames.begin()) << " " << FilterFileName;
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I)
    SendMessage(I->second, OS.str().c_str());
  pthread_mutex_unlock(&Mutex);
}

void HandleDeleteFilter(unsigned FilterID) {
  if (FilterID >= MaxNumFilters) {
    SendMessage(CtrlClientSock, "invalid ID");
    return;
  }
  if (FilterFileNames[FilterID] == "") {
    SendMessage(CtrlClientSock, "this ID does not exist");
    return;
  }
  FilterFileNames[FilterID] = "";

  ostringstream OS;
  OS << "del " << FilterID;
  pthread_mutex_lock(&Mutex);
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I)
    SendMessage(I->second, OS.str().c_str());
  pthread_mutex_unlock(&Mutex);
}

void HandleListFilters() {
  ostringstream OS;
  OS << "ID\tfile";
  for (size_t i = 0; i < FilterFileNames.size(); ++i) {
    if (FilterFileNames[i] != "") {
      OS << "\n" << i << "\t" << FilterFileNames[i];
    }
  }
  SendMessage(CtrlClientSock, OS.str().c_str());
}

void HandleListDaemons() {
  ostringstream OS;
  OS << "PID\tsocket";
  for (map<pid_t, int>::iterator I = Daemons.begin(); I != Daemons.end(); ++I) {
    OS << "\n" << I->first << "\t" << I->second;
  }
  SendMessage(CtrlClientSock, OS.str().c_str());
}

int HandleControllerClient(int ClientSock) {
  pthread_mutex_lock(&Mutex);
  if (CtrlClientSock != -1) {
    errs() << "another Loom controller client is running\n";
    pthread_mutex_unlock(&Mutex);
    return -1;
  }
  CtrlClientSock = ClientSock;
  pthread_mutex_unlock(&Mutex);

  char Cmd[MaxBufferSize];
  // benign race when reading <CtrlClientSock>
  while (ReceiveMessage(CtrlClientSock, Cmd) == 0) {
    istringstream IS(Cmd);
    string Op;
    if (!(IS >> Op)) {
      SendMessage(CtrlClientSock, "wrong format");
      continue;
    }
    if (Op == "add") {
      string FilterFileName;
      if (!(IS >> FilterFileName)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleAddFilter(FilterFileName);
    } else if (Op == "del") {
      unsigned FilterID;
      if (!(IS >> FilterID)) {
        SendMessage(CtrlClientSock, "wrong format");
        continue;
      }
      HandleDeleteFilter(FilterID);
    } else if (Op == "ls") {
      HandleListFilters();
    } else if (Op == "ps") {
      HandleListDaemons();
    } else {
      SendMessage(CtrlClientSock, "unknown command");
    }
  }

  // Reset <CtrlClientSock> to allow another controller.
  pthread_mutex_lock(&Mutex);
  CtrlClientSock = -1;
  pthread_mutex_unlock(&Mutex);

  return 0;
}

void *HandleClient(void *Arg) {
  int ClientSock = (intptr_t)Arg;

  // Identify the client.
  char Buffer[MaxBufferSize];
  if (ReceiveMessage(ClientSock, Buffer) == -1) {
    close(ClientSock);
    return (void *)-1;
  }

  int Ret = 0;
  if (strncmp(Buffer, "iam loom_daemon", strlen("iam loom_daemon")) == 0) {
    outs() << "which is a Loom daemon\n";
    pid_t PID;
    if (sscanf(Buffer, "iam loom_daemon %d", &PID) != 1)
      Ret = -1;
    else
      Ret = HandleDaemon(ClientSock, PID);
  } else if (strcmp(Buffer, "iam loom_ctl") == 0) {
    outs() << "which is a Loom controller client\n";
    Ret = HandleControllerClient(ClientSock);
  } else {
    outs() << "which is an unknown client. ";
    outs() << "close the connection immediately\n";
  }

  close(ClientSock);
  return (void *)Ret;
}

int RunControllerServer() {
  // Ignore SIGPIPE.
  signal(SIGPIPE, SIG_IGN);

  int AcceptSock = socket(AF_INET, SOCK_STREAM, 0);
  if (AcceptSock == -1) {
    perror("socket");
    return -1;
  }
  int TrueVal = 1;
  if (setsockopt(AcceptSock, SOL_SOCKET,
                 SO_REUSEADDR, &TrueVal, sizeof(int)) == -1) {
    perror("setsockopt");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof(ServerAddr));
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  ServerAddr.sin_addr.s_addr = INADDR_ANY;
  if (bind(AcceptSock,
           (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) == -1) {
    perror("bind");
    return -1;
  }

  if (listen(AcceptSock, 5) == -1) {
    perror("listen");
    return -1;
  }

  outs() << "Loom controller started. ";
  outs() << "Press Ctrl+C to exit...\n";
  struct sockaddr_in ClientAddr;
  socklen_t ClientAddrLen = sizeof(ClientAddr);
  while (true) {
    int ClientSock = accept(AcceptSock,
                            (struct sockaddr *)&ClientAddr, &ClientAddrLen);
    if (ClientSock == -1) {
      perror("accept");
      return -1;
    }

    outs() << "connected by " << inet_ntoa(ClientAddr.sin_addr) << ":" <<
        ntohs(ClientAddr.sin_port) << ", ";
    pthread_t child;
    if (pthread_create(&child, NULL, HandleClient, (void *)ClientSock) != 0) {
      perror("pthread_create");
      return -1;
    }
  }

  return 0;
}

int CommandAddFilter(int CtrlServerSock, const string &FilterFileName) {
  ostringstream OS;
  OS << "add ";
  // Convert to full path whenever possible, so that the user can use relative
  // path.
  if (char *FullPath = realpath(FilterFileName.c_str(), NULL)) {
    OS << FullPath;
    free(FullPath);
  } else {
    OS << FilterFileName;
  }
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandDeleteFilter(int CtrlServerSock, unsigned FilterID) {
  ostringstream OS;
  OS << "del " << FilterID;
  return SendMessage(CtrlServerSock, OS.str().c_str());
}

int CommandListFilters(int CtrlServerSock) {
  return SendMessage(CtrlServerSock, "ls");
}

int CommandListDaemons(int CtrlServerSock) {
  return SendMessage(CtrlServerSock, "ps");
}

int RunControllerClient() {
  int CtrlServerSock = socket(AF_INET, SOCK_STREAM, 0);
  if (CtrlServerSock == -1) {
    perror("socket");
    return -1;
  }

  struct sockaddr_in ServerAddr;
  bzero(&ServerAddr, sizeof ServerAddr);
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_addr.s_addr = inet_addr(CONTROLLER_IP);
  ServerAddr.sin_port = htons(CONTROLLER_PORT);
  if (connect(CtrlServerSock,
              (struct sockaddr *)&ServerAddr, sizeof ServerAddr) == -1) {
    perror("failed to connect to the controller server");
    return -1;
  }

  if (SendMessage(CtrlServerSock, "iam loom_ctl") == -1) {
    close(CtrlServerSock);
    return -1;
  }

  // TODO: extra it to a function
  int Ret = 0;
  if (ControllerAction == "add") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandAddFilter(CtrlServerSock, Args[0]);
    }
  } else if (ControllerAction == "delete") {
    if (Args.size() != 1) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      // TODO: check Args[0] is a number
      Ret = CommandDeleteFilter(CtrlServerSock, atoi(Args[0].c_str()));
    }
  } else if (ControllerAction == "ls") {
    if (Args.size() != 0) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandListFilters(CtrlServerSock);
    }
  } else if (ControllerAction == "ps") {
    if (Args.size() != 0) {
      errs() << "wrong format\n";
      Ret = -1;
    } else {
      Ret = CommandListDaemons(CtrlServerSock);
    }
  } else {
    assert(false);
  }

  // Don't bother receiving the response if sending already failed.
  if (Ret == 0) {
    char Response[MaxBufferSize] = {'\0'};
    Ret = ReceiveMessage(CtrlServerSock, Response);
    if (Ret == 0) {
      outs() << Response << "\n";
    }
  }

  close(CtrlServerSock);
  return Ret;
}

int main(int argc, char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, "Loom controller");
  if (ControllerAction == "server") {
    if (RunControllerServer() == -1)
      return 1;
  } else if (ControllerAction == "add" ||
             ControllerAction == "delete" ||
             ControllerAction == "ls" ||
             ControllerAction == "ps") {
    if (RunControllerClient() == -1)
      return 1;
  } else {
    errs() << "Not implemented yet\n";
  }
  return 0;
}
<|endoftext|>