<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include "libjoynrclustercontroller/mqtt/MosquittoConnection.h"

#include "joynr/ClusterControllerSettings.h"
#include "joynr/MessagingSettings.h"
#include "joynr/exceptions/JoynrException.h"

namespace joynr
{

MosquittoConnection::MosquittoConnection(const MessagingSettings& messagingSettings,
                                         const ClusterControllerSettings& ccSettings,
                                         const std::string& clientId)
        : mosquittopp(clientId.c_str(), false),
          messagingSettings(messagingSettings),
          host(messagingSettings.getBrokerUrl().getBrokerChannelsBaseUrl().getHost()),
          port(messagingSettings.getBrokerUrl().getBrokerChannelsBaseUrl().getPort()),
          channelId(),
          subscribeChannelMid(),
          topic(),
          additionalTopics(),
          additionalTopicsMutex(),
          isConnected(false),
          isRunning(false),
          isChannelIdRegistered(false),
          subscribedToChannelTopic(false),
          readyToSend(false),
          onMessageReceived(),
          onReadyToSendChangedMutex(),
          onReadyToSendChanged()
{
    JOYNR_LOG_INFO(logger(), "Init mosquitto connection using MQTT client ID: {}", clientId);
    mosqpp::lib_init();

    if (ccSettings.isMqttTlsEnabled()) {
        const std::string mqttCertificateAuthorityPemFilename =
                ccSettings.getMqttCertificateAuthorityPemFilename();
        const std::string mqttCertificateAuthorityCertificateFolderPath =
                ccSettings.getMqttCertificateAuthorityCertificateFolderPath();

        const char* mqttCertificateAuthorityPemFilename_cstr = nullptr;
        if (!mqttCertificateAuthorityPemFilename.empty()) {
            mqttCertificateAuthorityPemFilename_cstr = mqttCertificateAuthorityPemFilename.c_str();
        }

        const char* mqttCertificateAuthorityCertificateFolderPath_cstr = nullptr;
        if (!mqttCertificateAuthorityCertificateFolderPath.empty()) {
            mqttCertificateAuthorityCertificateFolderPath_cstr =
                    mqttCertificateAuthorityCertificateFolderPath.c_str();
        }

        int rc = tls_set(mqttCertificateAuthorityPemFilename_cstr,
                         mqttCertificateAuthorityCertificateFolderPath_cstr,
                         ccSettings.getMqttCertificatePemFilename().c_str(),
                         ccSettings.getMqttPrivateKeyPemFilename().c_str());

        if (rc != MOSQ_ERR_SUCCESS) {
            const std::string errorString(getErrorString(rc));
            mosqpp::lib_cleanup();
            JOYNR_LOG_FATAL(
                    logger(), "fatal failure to initialize TLS connection - {}", errorString);
        }
    } else {
        JOYNR_LOG_DEBUG(logger(), "MQTT connection not encrypted");
    }
}

MosquittoConnection::~MosquittoConnection()
{
    stop();
    stopLoop(true);

    mosqpp::lib_cleanup();
}

std::string MosquittoConnection::getErrorString(int rc)
{
    // Do not use mosq::strerror() in case of MOSQ_ERR_ERRNO
    // since it calls the MT-unsafe API strerror()
    if (rc != MOSQ_ERR_ERRNO) {
        return std::string(mosqpp::strerror(rc));
    }

    // MT-safe workaround
    char buf[256];
    buf[0] = '\0';
    int storedErrno = errno;
    // POSIX compliant check for conversion errors,
    // see 'man strerror_r'
    errno = 0;
    strerror_r(storedErrno, buf, sizeof(buf));
    if (errno) {
        return "failed to convert errno";
    }

    return std::string(buf);
}

void MosquittoConnection::on_disconnect(int rc)
{
    const std::string errorString(getErrorString(rc));
    setReadyToSend(false);
    if (!isConnected) {
        // In case we didn't connect yet
        JOYNR_LOG_ERROR(
                logger(), "Not yet connected to tcp://{}:{}, error: {}", host, port, errorString);
        return;
    }

    // There was indeed a disconnect...set connect to false
    isConnected = false;

    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Disconnected from tcp://{}:{}", host, port);
        stopLoop();
    } else {
        JOYNR_LOG_ERROR(logger(),
                        "Unexpectedly disconnected from tcp://{}:{}, error: {}",
                        host,
                        port,
                        errorString);
        reconnect();
    }
}

void MosquittoConnection::on_log(int level, const char* str)
{
    if (level == MOSQ_LOG_ERR) {
        JOYNR_LOG_ERROR(logger(), "Mosquitto Log: {}", str);
    } else if (level == MOSQ_LOG_WARNING) {
        JOYNR_LOG_WARN(logger(), "Mosquitto Log: {}", str);
    } else if (level == MOSQ_LOG_INFO) {
        JOYNR_LOG_INFO(logger(), "Mosquitto Log: {}", str);
    } else {
        // MOSQ_LOG_NOTICE || MOSQ_LOG_DEBUG || any other log level
        JOYNR_LOG_DEBUG(logger(), "Mosquitto Log: {}", str);
    }
}

std::uint16_t MosquittoConnection::getMqttQos() const
{
    return mqttQos;
}

std::string MosquittoConnection::getMqttPrio() const
{
    static const std::string value("low");
    return value;
}

bool MosquittoConnection::isMqttRetain() const
{
    return mqttRetain;
}

void MosquittoConnection::start()
{
    JOYNR_LOG_TRACE(
            logger(), "Start called with isRunning: {}, isConnected: {}", isRunning, isConnected);

    JOYNR_LOG_INFO(logger(), "Try to connect to tcp://{}:{}", host, port);
    connect_async(host.c_str(), port, messagingSettings.getMqttKeepAliveTimeSeconds().count());

    reconnect_delay_set(messagingSettings.getMqttReconnectDelayTimeSeconds().count(),
                        messagingSettings.getMqttReconnectMaxDelayTimeSeconds().count(),
                        messagingSettings.getMqttExponentialBackoffEnabled());

    startLoop();
}

void MosquittoConnection::startLoop()
{
    int rc = loop_start();
    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Mosquitto loop started");
        isRunning = true;
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(logger(),
                        "Mosquitto loop start failed: error: {} ({})",
                        std::to_string(rc),
                        errorString);
    }
}

void MosquittoConnection::stop()
{
    if (isConnected) {
        int rc = disconnect();

        if (rc == MOSQ_ERR_SUCCESS) {
            JOYNR_LOG_INFO(logger(), "Mosquitto Connection disconnected");
        } else {
            const std::string errorString(getErrorString(rc));
            JOYNR_LOG_ERROR(logger(),
                            "Mosquitto disconnect failed: error: {} ({})",
                            std::to_string(rc),
                            errorString);
            stopLoop(true);
        }
    } else if (isRunning) {
        stopLoop(true);
    }
    setReadyToSend(false);
}

void MosquittoConnection::stopLoop(bool force)
{
    int rc = loop_stop(force);

    if (rc == MOSQ_ERR_SUCCESS) {
        isRunning = false;
        JOYNR_LOG_INFO(logger(), "Mosquitto loop stopped");
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(logger(),
                        "Mosquitto loop stop failed: error: {} ({})",
                        std::to_string(rc),
                        errorString);
    }
}

void MosquittoConnection::on_connect(int rc)
{
    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Mosquitto Connection established");
        isConnected = true;

        createSubscriptions();
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(
                logger(), "Mosquitto Connection Error: {} ({})", std::to_string(rc), errorString);
    }
}

void MosquittoConnection::createSubscriptions()
{
    while (!isChannelIdRegistered && isRunning) {
        std::this_thread::sleep_for(std::chrono::milliseconds(25));
    }
    try {
        subscribeToTopicInternal(topic, true);
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        for (const std::string& additionalTopic : additionalTopics) {
            subscribeToTopicInternal(additionalTopic);
        }
    } catch (const exceptions::JoynrRuntimeException& error) {
        JOYNR_LOG_ERROR(logger(), "Error subscribing to Mqtt topic, error: ", error.getMessage());
    }
}

void MosquittoConnection::subscribeToTopicInternal(const std::string& topic,
                                                   const bool isChannelTopic)
{
    int* mid = nullptr;
    if (isChannelTopic) {
        mid = &subscribeChannelMid;
    }
    int rc = subscribe(mid, topic.c_str(), getMqttQos());
    switch (rc) {
    case (MOSQ_ERR_SUCCESS):
        JOYNR_LOG_INFO(logger(), "Subscribed to {}", topic);
        break;
    case (MOSQ_ERR_NO_CONN): {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_DEBUG(logger(),
                        "Subscription to {} failed: error: {} ({}). "
                        "Subscription will be restored on connect.",
                        topic,
                        std::to_string(rc),
                        errorString);
        break;
    }
    default: {
        // MOSQ_ERR_INVAL, MOSQ_ERR_NOMEM
        const std::string errorString(getErrorString(rc));
        std::string errorMsg = "Subscription to " + topic + " failed: error: " +
                               std::to_string(rc) + " (" + errorString + ")";
        throw exceptions::JoynrRuntimeException(errorMsg);
    }
    }
}

void MosquittoConnection::subscribeToTopic(const std::string& topic)
{
    if (!isChannelIdRegistered) {
        std::string errorMsg = "No channelId registered, cannot subscribe to topic " + topic;
        throw exceptions::JoynrRuntimeException(errorMsg);
    }

    {
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        if (additionalTopics.find(topic) != additionalTopics.end()) {
            JOYNR_LOG_DEBUG(logger(), "Already subscribed to topic {}", topic);
            return;
        }

        subscribeToTopicInternal(topic);

        additionalTopics.insert(topic);
    }
}

void MosquittoConnection::unsubscribeFromTopic(const std::string& topic)
{
    if (isChannelIdRegistered) {
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        if (additionalTopics.find(topic) == additionalTopics.end()) {
            JOYNR_LOG_DEBUG(logger(), "Unsubscribe called for non existing topic {}", topic);
            return;
        }
        additionalTopics.erase(topic);
        if (isConnected && isRunning) {
            int rc = unsubscribe(nullptr, topic.c_str());
            if (rc == MOSQ_ERR_SUCCESS) {
                JOYNR_LOG_INFO(logger(), "Unsubscribed from {}", topic);
            } else {
                // MOSQ_ERR_INVAL || MOSQ_ERR_NOMEM || MOSQ_ERR_NO_CONN
                const std::string errorString(getErrorString(rc));
                JOYNR_LOG_ERROR(logger(),
                                "Unsubscribe from {} failed: error: {} ({})",
                                topic,
                                std::to_string(rc),
                                errorString);
            }
        }
    }
}

void MosquittoConnection::publishMessage(
        const std::string& topic,
        const int qosLevel,
        const std::function<void(const exceptions::JoynrRuntimeException&)>& onFailure,
        uint32_t payloadlen = 0,
        const void* payload = nullptr)
{
    JOYNR_LOG_DEBUG(logger(), "Publish message of length {} to {}", payloadlen, topic);

    int mid;
    int rc = publish(&mid, topic.c_str(), payloadlen, payload, qosLevel, isMqttRetain());
    if (!(rc == MOSQ_ERR_SUCCESS)) {
        const std::string errorString(getErrorString(rc));
        if (rc == MOSQ_ERR_INVAL || rc == MOSQ_ERR_PAYLOAD_SIZE) {
            onFailure(exceptions::JoynrMessageNotSentException(
                    "message could not be sent: mid (mqtt message id): " + std::to_string(mid) +
                    ", error: " + std::to_string(rc) + " (" + errorString + ")"));
            return;
        }
        // MOSQ_ERR_NOMEM || MOSQ_ERR_NO_CONN || MOSQ_ERR_PROTOCOL ||| unexpected errors
        onFailure(exceptions::JoynrDelayMessageException(
                "error sending message: mid (mqtt message id): " + std::to_string(mid) +
                ", error: " + std::to_string(rc) + " (" + errorString + ")"));
        return;
    }
    JOYNR_LOG_TRACE(logger(), "published message with mqtt message id {}", std::to_string(mid));
}

void MosquittoConnection::registerChannelId(const std::string& channelId)
{
    this->channelId = channelId;
    topic = channelId + "/" + getMqttPrio() + "/" + "#";
    isChannelIdRegistered = true;
}

void MosquittoConnection::registerReceiveCallback(
        std::function<void(smrf::ByteVector&&)> onMessageReceived)
{
    this->onMessageReceived = onMessageReceived;
}

void MosquittoConnection::registerReadyToSendChangedCallback(
        std::function<void(bool)> onReadyToSendChanged)
{
    std::lock_guard<std::mutex> lock(onReadyToSendChangedMutex);
    this->onReadyToSendChanged = std::move(onReadyToSendChanged);
}

bool MosquittoConnection::isSubscribedToChannelTopic() const
{
    return subscribedToChannelTopic;
}

bool MosquittoConnection::isReadyToSend() const
{
    return readyToSend;
}

void MosquittoConnection::on_subscribe(int mid, int qos_count, const int* granted_qos)
{
    JOYNR_LOG_DEBUG(logger(), "Subscribed (mid: {} with granted QOS {}", mid, granted_qos[0]);

    for (int i = 1; i < qos_count; i++) {
        JOYNR_LOG_DEBUG(logger(), "QOS: {} granted {}", i, granted_qos[i]);
    }

    if (mid == subscribeChannelMid) {
        subscribedToChannelTopic = true;
        setReadyToSend(isConnected);
    }
}

void MosquittoConnection::on_message(const mosquitto_message* message)
{
    if (!onMessageReceived) {
        JOYNR_LOG_ERROR(logger(),
                        "Discarding received message, since onMessageReceived callback is empty.");
        return;
    }

    if (!message || message->payloadlen <= 0) {
        JOYNR_LOG_ERROR(
                logger(),
                "Discarding received message: invalid message or non-positive payload's length.");
        return;
    }

    std::uint8_t* data = static_cast<std::uint8_t*>(message->payload);

    // convert address of data into integral type
    std::uintptr_t integralAddress = reinterpret_cast<std::uintptr_t>(data);
    const bool overflow =
            joynr::util::isAdditionOnPointerSafe(integralAddress, message->payloadlen);
    if (overflow) {
        JOYNR_LOG_ERROR(logger(), "Discarding received message, since there is an overflow.");
        return;
    }

    smrf::ByteVector rawMessage(data, data + message->payloadlen);
    onMessageReceived(std::move(rawMessage));
}

void MosquittoConnection::on_publish(int mid)
{
    JOYNR_LOG_TRACE(logger(), "published message with mid {}", std::to_string(mid));
}

void MosquittoConnection::setReadyToSend(bool readyToSend)
{
    if (this->readyToSend != readyToSend) {
        this->readyToSend = readyToSend;

        std::lock_guard<std::mutex> lock(onReadyToSendChangedMutex);
        if (onReadyToSendChanged) {
            onReadyToSendChanged(readyToSend);
        }
    }
}

} // namespace joynr
<commit_msg>[C++] MosquittoConnection::getErrorString() uses joynr::util::getErrorString()<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include "libjoynrclustercontroller/mqtt/MosquittoConnection.h"

#include "joynr/ClusterControllerSettings.h"
#include "joynr/MessagingSettings.h"
#include "joynr/Util.h"
#include "joynr/exceptions/JoynrException.h"

namespace joynr
{

MosquittoConnection::MosquittoConnection(const MessagingSettings& messagingSettings,
                                         const ClusterControllerSettings& ccSettings,
                                         const std::string& clientId)
        : mosquittopp(clientId.c_str(), false),
          messagingSettings(messagingSettings),
          host(messagingSettings.getBrokerUrl().getBrokerChannelsBaseUrl().getHost()),
          port(messagingSettings.getBrokerUrl().getBrokerChannelsBaseUrl().getPort()),
          channelId(),
          subscribeChannelMid(),
          topic(),
          additionalTopics(),
          additionalTopicsMutex(),
          isConnected(false),
          isRunning(false),
          isChannelIdRegistered(false),
          subscribedToChannelTopic(false),
          readyToSend(false),
          onMessageReceived(),
          onReadyToSendChangedMutex(),
          onReadyToSendChanged()
{
    JOYNR_LOG_INFO(logger(), "Init mosquitto connection using MQTT client ID: {}", clientId);
    mosqpp::lib_init();

    if (ccSettings.isMqttTlsEnabled()) {
        const std::string mqttCertificateAuthorityPemFilename =
                ccSettings.getMqttCertificateAuthorityPemFilename();
        const std::string mqttCertificateAuthorityCertificateFolderPath =
                ccSettings.getMqttCertificateAuthorityCertificateFolderPath();

        const char* mqttCertificateAuthorityPemFilename_cstr = nullptr;
        if (!mqttCertificateAuthorityPemFilename.empty()) {
            mqttCertificateAuthorityPemFilename_cstr = mqttCertificateAuthorityPemFilename.c_str();
        }

        const char* mqttCertificateAuthorityCertificateFolderPath_cstr = nullptr;
        if (!mqttCertificateAuthorityCertificateFolderPath.empty()) {
            mqttCertificateAuthorityCertificateFolderPath_cstr =
                    mqttCertificateAuthorityCertificateFolderPath.c_str();
        }

        int rc = tls_set(mqttCertificateAuthorityPemFilename_cstr,
                         mqttCertificateAuthorityCertificateFolderPath_cstr,
                         ccSettings.getMqttCertificatePemFilename().c_str(),
                         ccSettings.getMqttPrivateKeyPemFilename().c_str());

        if (rc != MOSQ_ERR_SUCCESS) {
            const std::string errorString(getErrorString(rc));
            mosqpp::lib_cleanup();
            JOYNR_LOG_FATAL(
                    logger(), "fatal failure to initialize TLS connection - {}", errorString);
        }
    } else {
        JOYNR_LOG_DEBUG(logger(), "MQTT connection not encrypted");
    }
}

MosquittoConnection::~MosquittoConnection()
{
    stop();
    stopLoop(true);

    mosqpp::lib_cleanup();
}

std::string MosquittoConnection::getErrorString(int rc)
{
    // Do not use mosq::strerror() in case of MOSQ_ERR_ERRNO
    // since it calls the MT-unsafe API strerror()
    if (rc != MOSQ_ERR_ERRNO) {
        return std::string(mosqpp::strerror(rc));
    }

    const int storedErrno = errno;
    return joynr::util::getErrorString(storedErrno);
}

void MosquittoConnection::on_disconnect(int rc)
{
    const std::string errorString(getErrorString(rc));
    setReadyToSend(false);
    if (!isConnected) {
        // In case we didn't connect yet
        JOYNR_LOG_ERROR(
                logger(), "Not yet connected to tcp://{}:{}, error: {}", host, port, errorString);
        return;
    }

    // There was indeed a disconnect...set connect to false
    isConnected = false;

    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Disconnected from tcp://{}:{}", host, port);
        stopLoop();
    } else {
        JOYNR_LOG_ERROR(logger(),
                        "Unexpectedly disconnected from tcp://{}:{}, error: {}",
                        host,
                        port,
                        errorString);
        reconnect();
    }
}

void MosquittoConnection::on_log(int level, const char* str)
{
    if (level == MOSQ_LOG_ERR) {
        JOYNR_LOG_ERROR(logger(), "Mosquitto Log: {}", str);
    } else if (level == MOSQ_LOG_WARNING) {
        JOYNR_LOG_WARN(logger(), "Mosquitto Log: {}", str);
    } else if (level == MOSQ_LOG_INFO) {
        JOYNR_LOG_INFO(logger(), "Mosquitto Log: {}", str);
    } else {
        // MOSQ_LOG_NOTICE || MOSQ_LOG_DEBUG || any other log level
        JOYNR_LOG_DEBUG(logger(), "Mosquitto Log: {}", str);
    }
}

std::uint16_t MosquittoConnection::getMqttQos() const
{
    return mqttQos;
}

std::string MosquittoConnection::getMqttPrio() const
{
    static const std::string value("low");
    return value;
}

bool MosquittoConnection::isMqttRetain() const
{
    return mqttRetain;
}

void MosquittoConnection::start()
{
    JOYNR_LOG_TRACE(
            logger(), "Start called with isRunning: {}, isConnected: {}", isRunning, isConnected);

    JOYNR_LOG_INFO(logger(), "Try to connect to tcp://{}:{}", host, port);
    connect_async(host.c_str(), port, messagingSettings.getMqttKeepAliveTimeSeconds().count());

    reconnect_delay_set(messagingSettings.getMqttReconnectDelayTimeSeconds().count(),
                        messagingSettings.getMqttReconnectMaxDelayTimeSeconds().count(),
                        messagingSettings.getMqttExponentialBackoffEnabled());

    startLoop();
}

void MosquittoConnection::startLoop()
{
    int rc = loop_start();
    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Mosquitto loop started");
        isRunning = true;
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(logger(),
                        "Mosquitto loop start failed: error: {} ({})",
                        std::to_string(rc),
                        errorString);
    }
}

void MosquittoConnection::stop()
{
    if (isConnected) {
        int rc = disconnect();

        if (rc == MOSQ_ERR_SUCCESS) {
            JOYNR_LOG_INFO(logger(), "Mosquitto Connection disconnected");
        } else {
            const std::string errorString(getErrorString(rc));
            JOYNR_LOG_ERROR(logger(),
                            "Mosquitto disconnect failed: error: {} ({})",
                            std::to_string(rc),
                            errorString);
            stopLoop(true);
        }
    } else if (isRunning) {
        stopLoop(true);
    }
    setReadyToSend(false);
}

void MosquittoConnection::stopLoop(bool force)
{
    int rc = loop_stop(force);

    if (rc == MOSQ_ERR_SUCCESS) {
        isRunning = false;
        JOYNR_LOG_INFO(logger(), "Mosquitto loop stopped");
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(logger(),
                        "Mosquitto loop stop failed: error: {} ({})",
                        std::to_string(rc),
                        errorString);
    }
}

void MosquittoConnection::on_connect(int rc)
{
    if (rc == MOSQ_ERR_SUCCESS) {
        JOYNR_LOG_INFO(logger(), "Mosquitto Connection established");
        isConnected = true;

        createSubscriptions();
    } else {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_ERROR(
                logger(), "Mosquitto Connection Error: {} ({})", std::to_string(rc), errorString);
    }
}

void MosquittoConnection::createSubscriptions()
{
    while (!isChannelIdRegistered && isRunning) {
        std::this_thread::sleep_for(std::chrono::milliseconds(25));
    }
    try {
        subscribeToTopicInternal(topic, true);
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        for (const std::string& additionalTopic : additionalTopics) {
            subscribeToTopicInternal(additionalTopic);
        }
    } catch (const exceptions::JoynrRuntimeException& error) {
        JOYNR_LOG_ERROR(logger(), "Error subscribing to Mqtt topic, error: ", error.getMessage());
    }
}

void MosquittoConnection::subscribeToTopicInternal(const std::string& topic,
                                                   const bool isChannelTopic)
{
    int* mid = nullptr;
    if (isChannelTopic) {
        mid = &subscribeChannelMid;
    }
    int rc = subscribe(mid, topic.c_str(), getMqttQos());
    switch (rc) {
    case (MOSQ_ERR_SUCCESS):
        JOYNR_LOG_INFO(logger(), "Subscribed to {}", topic);
        break;
    case (MOSQ_ERR_NO_CONN): {
        const std::string errorString(getErrorString(rc));
        JOYNR_LOG_DEBUG(logger(),
                        "Subscription to {} failed: error: {} ({}). "
                        "Subscription will be restored on connect.",
                        topic,
                        std::to_string(rc),
                        errorString);
        break;
    }
    default: {
        // MOSQ_ERR_INVAL, MOSQ_ERR_NOMEM
        const std::string errorString(getErrorString(rc));
        std::string errorMsg = "Subscription to " + topic + " failed: error: " +
                               std::to_string(rc) + " (" + errorString + ")";
        throw exceptions::JoynrRuntimeException(errorMsg);
    }
    }
}

void MosquittoConnection::subscribeToTopic(const std::string& topic)
{
    if (!isChannelIdRegistered) {
        std::string errorMsg = "No channelId registered, cannot subscribe to topic " + topic;
        throw exceptions::JoynrRuntimeException(errorMsg);
    }

    {
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        if (additionalTopics.find(topic) != additionalTopics.end()) {
            JOYNR_LOG_DEBUG(logger(), "Already subscribed to topic {}", topic);
            return;
        }

        subscribeToTopicInternal(topic);

        additionalTopics.insert(topic);
    }
}

void MosquittoConnection::unsubscribeFromTopic(const std::string& topic)
{
    if (isChannelIdRegistered) {
        std::lock_guard<std::recursive_mutex> lock(additionalTopicsMutex);
        if (additionalTopics.find(topic) == additionalTopics.end()) {
            JOYNR_LOG_DEBUG(logger(), "Unsubscribe called for non existing topic {}", topic);
            return;
        }
        additionalTopics.erase(topic);
        if (isConnected && isRunning) {
            int rc = unsubscribe(nullptr, topic.c_str());
            if (rc == MOSQ_ERR_SUCCESS) {
                JOYNR_LOG_INFO(logger(), "Unsubscribed from {}", topic);
            } else {
                // MOSQ_ERR_INVAL || MOSQ_ERR_NOMEM || MOSQ_ERR_NO_CONN
                const std::string errorString(getErrorString(rc));
                JOYNR_LOG_ERROR(logger(),
                                "Unsubscribe from {} failed: error: {} ({})",
                                topic,
                                std::to_string(rc),
                                errorString);
            }
        }
    }
}

void MosquittoConnection::publishMessage(
        const std::string& topic,
        const int qosLevel,
        const std::function<void(const exceptions::JoynrRuntimeException&)>& onFailure,
        uint32_t payloadlen = 0,
        const void* payload = nullptr)
{
    JOYNR_LOG_DEBUG(logger(), "Publish message of length {} to {}", payloadlen, topic);

    int mid;
    int rc = publish(&mid, topic.c_str(), payloadlen, payload, qosLevel, isMqttRetain());
    if (!(rc == MOSQ_ERR_SUCCESS)) {
        const std::string errorString(getErrorString(rc));
        if (rc == MOSQ_ERR_INVAL || rc == MOSQ_ERR_PAYLOAD_SIZE) {
            onFailure(exceptions::JoynrMessageNotSentException(
                    "message could not be sent: mid (mqtt message id): " + std::to_string(mid) +
                    ", error: " + std::to_string(rc) + " (" + errorString + ")"));
            return;
        }
        // MOSQ_ERR_NOMEM || MOSQ_ERR_NO_CONN || MOSQ_ERR_PROTOCOL ||| unexpected errors
        onFailure(exceptions::JoynrDelayMessageException(
                "error sending message: mid (mqtt message id): " + std::to_string(mid) +
                ", error: " + std::to_string(rc) + " (" + errorString + ")"));
        return;
    }
    JOYNR_LOG_TRACE(logger(), "published message with mqtt message id {}", std::to_string(mid));
}

void MosquittoConnection::registerChannelId(const std::string& channelId)
{
    this->channelId = channelId;
    topic = channelId + "/" + getMqttPrio() + "/" + "#";
    isChannelIdRegistered = true;
}

void MosquittoConnection::registerReceiveCallback(
        std::function<void(smrf::ByteVector&&)> onMessageReceived)
{
    this->onMessageReceived = onMessageReceived;
}

void MosquittoConnection::registerReadyToSendChangedCallback(
        std::function<void(bool)> onReadyToSendChanged)
{
    std::lock_guard<std::mutex> lock(onReadyToSendChangedMutex);
    this->onReadyToSendChanged = std::move(onReadyToSendChanged);
}

bool MosquittoConnection::isSubscribedToChannelTopic() const
{
    return subscribedToChannelTopic;
}

bool MosquittoConnection::isReadyToSend() const
{
    return readyToSend;
}

void MosquittoConnection::on_subscribe(int mid, int qos_count, const int* granted_qos)
{
    JOYNR_LOG_DEBUG(logger(), "Subscribed (mid: {} with granted QOS {}", mid, granted_qos[0]);

    for (int i = 1; i < qos_count; i++) {
        JOYNR_LOG_DEBUG(logger(), "QOS: {} granted {}", i, granted_qos[i]);
    }

    if (mid == subscribeChannelMid) {
        subscribedToChannelTopic = true;
        setReadyToSend(isConnected);
    }
}

void MosquittoConnection::on_message(const mosquitto_message* message)
{
    if (!onMessageReceived) {
        JOYNR_LOG_ERROR(logger(),
                        "Discarding received message, since onMessageReceived callback is empty.");
        return;
    }

    if (!message || message->payloadlen <= 0) {
        JOYNR_LOG_ERROR(
                logger(),
                "Discarding received message: invalid message or non-positive payload's length.");
        return;
    }

    std::uint8_t* data = static_cast<std::uint8_t*>(message->payload);

    // convert address of data into integral type
    std::uintptr_t integralAddress = reinterpret_cast<std::uintptr_t>(data);
    const bool overflow =
            joynr::util::isAdditionOnPointerSafe(integralAddress, message->payloadlen);
    if (overflow) {
        JOYNR_LOG_ERROR(logger(), "Discarding received message, since there is an overflow.");
        return;
    }

    smrf::ByteVector rawMessage(data, data + message->payloadlen);
    onMessageReceived(std::move(rawMessage));
}

void MosquittoConnection::on_publish(int mid)
{
    JOYNR_LOG_TRACE(logger(), "published message with mid {}", std::to_string(mid));
}

void MosquittoConnection::setReadyToSend(bool readyToSend)
{
    if (this->readyToSend != readyToSend) {
        this->readyToSend = readyToSend;

        std::lock_guard<std::mutex> lock(onReadyToSendChangedMutex);
        if (onReadyToSendChanged) {
            onReadyToSendChanged(readyToSend);
        }
    }
}

} // namespace joynr
<|endoftext|>


<commit_before>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/select.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::atTCPNetworkInterface(short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;
   char *               address;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      address = (char *) connectingName.sin_addr.s_addr;
      sprintf(client_addrs[num_client_sockets].address, "%d.%d.%d.%d",
              address[0], address[1], address[2], address[3]);
      client_addrs[num_client_sockets].port = connectingName.sin_port;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

ClientAddr atTCPNetworkInterface::getClientInfo(int clientID)
{
   // Return the information for this client ID
   return client_addrs[clientID];
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;
   fd_set               readFds;
   fd_set               writeFds;
   struct timeval       timeout;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
         {
            // We are non-blocking so we could be failing to connect
            // or we could just need more time (EINPROGRESS) so
            // use select() to give it some time and then check again
            if (errno == EINPROGRESS)
            {
               notify(AT_INFO, "Waiting for connection.\n");
               FD_ZERO(&readFds);
               FD_SET(socket_value, &readFds);
               FD_ZERO(&writeFds);
               FD_SET(socket_value, &writeFds);
               timeout.tv_sec = 1;
               timeout.tv_usec = 0;
               if (select(socket_value+1, &readFds,
                          &writeFds, NULL, &timeout) < 1)
               {
                  // We didn't connect so close the socket
                  keepTrying = 0;
                  close(socket_value);
                  socket_value = -1;
               }
               else
               {
                  // We actually did connect!
                  keepTrying = 0;
               }
            }
            else
            {
               // Just give up
               notify(AT_INFO, "Failed to connect to server.  Giving up.\n");
               keepTrying = 0;
               close(socket_value);
               socket_value = -1;
            }
         }
         else
         {
            // We didn't connect so close the socket
            close(socket_value);
            socket_value = -1;

            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<commit_msg><commit_after>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/select.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::atTCPNetworkInterface(short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   if (socket_value != -1)
      close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;
   char *               address;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      address = (char *) &connectingName.sin_addr.s_addr;
      sprintf(client_addrs[num_client_sockets].address, "%hhu.%hhu.%hhu.%hhu",
              address[0], address[1], address[2], address[3]);
      client_addrs[num_client_sockets].port = connectingName.sin_port;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

ClientAddr atTCPNetworkInterface::getClientInfo(int clientID)
{
   // Return the information for this client ID
   return client_addrs[clientID];
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;
   fd_set               readFds;
   fd_set               writeFds;
   struct timeval       timeout;
   int                  errorCode;
   socklen_t            errorLength;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
         {
            // We are non-blocking so we could be failing to connect
            // or we could just need more time (EINPROGRESS) so
            // use select() to give it some time and then check again
            if (errno == EINPROGRESS)
            {
               notify(AT_INFO, "Waiting for connection.\n");
               FD_ZERO(&readFds);
               FD_SET(socket_value, &readFds);
               FD_ZERO(&writeFds);
               FD_SET(socket_value, &writeFds);
               timeout.tv_sec = 1;
               timeout.tv_usec = 0;
               if (select(socket_value+1, &readFds,
                          &writeFds, NULL, &timeout) < 1)
               {
                  // We didn't connect so close the socket
                  notify(AT_INFO, "Failed to connect to server.  Giving up.\n");
                  keepTrying = 0;
                  close(socket_value);
                  socket_value = -1;
               }
               else
               {
                  // Check for error on the socket to see if we connected
                  // successfully or not
                  errorLength = sizeof(int);
                  getsockopt(socket_value, SOL_SOCKET, SO_ERROR, &errorCode,
                             &errorLength);

                  // Check the error status
                  if (errorCode == 0)
                  {
                     // We actually did connect!
                     notify(AT_INFO, "Connected!\n");
                     keepTrying = 0;
                  }
                  else
                  {
                     // Failed to connect, so give up
                     notify(AT_INFO,
                            "Failed to connect to server.  Giving up.\n");
                     keepTrying = 0;
                     close(socket_value);
                     socket_value = -1;
                  }
               }
            }
            else
            {
               // Just give up
               notify(AT_INFO, "Failed to connect to server.  Giving up.\n");
               keepTrying = 0;
               close(socket_value);
               socket_value = -1;
            }
         }
         else
         {
            // We didn't connect so close the socket
            close(socket_value);
            socket_value = -1;

            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

#include <max_clique/cco_max_clique.hh>
#include <max_clique/cco_base.hh>
#include <max_clique/print_incumbent.hh>

#include <graph/template_voodoo.hh>
#include <graph/merge_cliques.hh>

#include <algorithm>
#include <thread>
#include <mutex>

using namespace parasols;

namespace
{
    template <CCOPermutations perm_, CCOInference inference_, CCOMerge merge_, unsigned size_, typename VertexType_>
    struct CCO : CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >
    {
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::CCOBase;

        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::original_graph;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::graph;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::params;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::expand;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::order;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::colour_class_order;

        MaxCliqueResult result;

        std::list<std::set<int> > previouses;

        auto run() -> MaxCliqueResult
        {
            result.size = params.initial_bound;

            std::vector<unsigned> c;
            c.reserve(graph.size());

            FixedBitSet<size_> p; // potential additions
            p.resize(graph.size());
            p.set_all();

            std::vector<int> positions;
            positions.reserve(graph.size());
            positions.push_back(0);

            // initial colouring
            std::array<VertexType_, size_ * bits_per_word> initial_p_order;
            std::array<VertexType_, size_ * bits_per_word> initial_colours;
            colour_class_order(SelectColourClassOrderOverload<perm_>(), p, initial_p_order, initial_colours);
            result.initial_colour_bound = initial_colours[graph.size() - 1];

            // go!
            expand(c, p, initial_p_order, initial_colours, positions);

            // hack for enumerate
            if (params.enumerate)
                result.size = result.members.size();

            return result;
        }

        auto increment_nodes() -> void
        {
            ++result.nodes;
        }

        auto recurse(
                std::vector<unsigned> & c,                       // current candidate clique
                FixedBitSet<size_> & p,
                const std::array<VertexType_, size_ * bits_per_word> & p_order,
                const std::array<VertexType_, size_ * bits_per_word> & colours,
                std::vector<int> & position
                ) -> bool
        {
            expand(c, p, p_order, colours, position);
            return true;
        }

        auto potential_new_best(
                const std::vector<unsigned> & c,
                const std::vector<int> & position) -> void
        {
            switch (merge_) {
                case CCOMerge::None:
                    if (c.size() > result.size) {
                        if (params.enumerate) {
                            ++result.result_count;
                            result.size = c.size() - 1;
                        }
                        else
                            result.size = c.size();

                        result.members.clear();
                        for (auto & v : c)
                            result.members.insert(order[v]);

                        print_incumbent(params, c.size(), position);
                    }
                    break;

                case CCOMerge::Previous:
                    {
                        std::set<int> new_members;
                        for (auto & v : c)
                            new_members.insert(order[v]);

                        auto merged = merge_cliques(original_graph, result.members, new_members);
                        if (merged.size() > result.size) {
                            result.members = merged;
                            result.size = result.members.size();
                            print_incumbent(params, result.size, position);
                        }
                    }
                    break;

                case CCOMerge::All:
                    {
                        std::set<int> new_members;
                        for (auto & v : c)
                            new_members.insert(order[v]);

                        for (auto & p : previouses) {
                            auto merged = merge_cliques(original_graph, p, new_members);

                            if (merged.size() > result.size) {
                                result.members = merged;
                                result.size = result.members.size();
                                previouses.push_back(result.members);
                                print_incumbent(params, result.size, position);
                            }
                        }

                        previouses.push_back(result.members);
                        print_position(params, "previouses is now " + std::to_string(previouses.size()), position);
                    }
                    break;
            }
        }

        auto get_best_anywhere_value() -> unsigned
        {
            return result.size;
        }

        auto get_skip(unsigned, int &, bool &) -> void
        {
        }
    };
}

template <CCOPermutations perm_, CCOInference inference_, CCOMerge merge_>
auto parasols::cco_max_clique(const Graph & graph, const MaxCliqueParams & params) -> MaxCliqueResult
{
    return select_graph_size<ApplyPermInferenceMerge<CCO, perm_, inference_, merge_>::template Type, MaxCliqueResult>(
            AllGraphSizes(), graph, params);
}

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
<commit_msg>Fix merge all<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

#include <max_clique/cco_max_clique.hh>
#include <max_clique/cco_base.hh>
#include <max_clique/print_incumbent.hh>

#include <graph/template_voodoo.hh>
#include <graph/merge_cliques.hh>

#include <algorithm>
#include <thread>
#include <mutex>

using namespace parasols;

namespace
{
    template <CCOPermutations perm_, CCOInference inference_, CCOMerge merge_, unsigned size_, typename VertexType_>
    struct CCO : CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >
    {
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::CCOBase;

        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::original_graph;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::graph;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::params;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::expand;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::order;
        using CCOBase<perm_, inference_, merge_, size_, VertexType_, CCO<perm_, inference_, merge_, size_, VertexType_> >::colour_class_order;

        MaxCliqueResult result;

        std::list<std::set<int> > previouses;

        auto run() -> MaxCliqueResult
        {
            result.size = params.initial_bound;

            std::vector<unsigned> c;
            c.reserve(graph.size());

            FixedBitSet<size_> p; // potential additions
            p.resize(graph.size());
            p.set_all();

            std::vector<int> positions;
            positions.reserve(graph.size());
            positions.push_back(0);

            // initial colouring
            std::array<VertexType_, size_ * bits_per_word> initial_p_order;
            std::array<VertexType_, size_ * bits_per_word> initial_colours;
            colour_class_order(SelectColourClassOrderOverload<perm_>(), p, initial_p_order, initial_colours);
            result.initial_colour_bound = initial_colours[graph.size() - 1];

            // go!
            expand(c, p, initial_p_order, initial_colours, positions);

            // hack for enumerate
            if (params.enumerate)
                result.size = result.members.size();

            return result;
        }

        auto increment_nodes() -> void
        {
            ++result.nodes;
        }

        auto recurse(
                std::vector<unsigned> & c,                       // current candidate clique
                FixedBitSet<size_> & p,
                const std::array<VertexType_, size_ * bits_per_word> & p_order,
                const std::array<VertexType_, size_ * bits_per_word> & colours,
                std::vector<int> & position
                ) -> bool
        {
            expand(c, p, p_order, colours, position);
            return true;
        }

        auto potential_new_best(
                const std::vector<unsigned> & c,
                const std::vector<int> & position) -> void
        {
            switch (merge_) {
                case CCOMerge::None:
                    if (c.size() > result.size) {
                        if (params.enumerate) {
                            ++result.result_count;
                            result.size = c.size() - 1;
                        }
                        else
                            result.size = c.size();

                        result.members.clear();
                        for (auto & v : c)
                            result.members.insert(order[v]);

                        print_incumbent(params, c.size(), position);
                    }
                    break;

                case CCOMerge::Previous:
                    {
                        std::set<int> new_members;
                        for (auto & v : c)
                            new_members.insert(order[v]);

                        auto merged = merge_cliques(original_graph, result.members, new_members);
                        if (merged.size() > result.size) {
                            result.members = merged;
                            result.size = result.members.size();
                            print_incumbent(params, result.size, position);
                        }
                    }
                    break;

                case CCOMerge::All:
                    {
                        std::set<int> new_members;
                        for (auto & v : c)
                            new_members.insert(order[v]);

                        if (previouses.empty()) {
                            result.members = new_members;
                            result.size = result.members.size();
                            previouses.push_back(result.members);
                            print_incumbent(params, result.size, position);
                        }
                        else
                            for (auto & p : previouses) {
                                auto merged = merge_cliques(original_graph, p, new_members);

                                if (merged.size() > result.size) {
                                    result.members = merged;
                                    result.size = result.members.size();
                                    previouses.push_back(result.members);
                                    print_incumbent(params, result.size, position);
                                }
                            }

                        previouses.push_back(result.members);
                        print_position(params, "previouses is now " + std::to_string(previouses.size()), position);
                    }
                    break;
            }
        }

        auto get_best_anywhere_value() -> unsigned
        {
            return result.size;
        }

        auto get_skip(unsigned, int &, bool &) -> void
        {
        }
    };
}

template <CCOPermutations perm_, CCOInference inference_, CCOMerge merge_>
auto parasols::cco_max_clique(const Graph & graph, const MaxCliqueParams & params) -> MaxCliqueResult
{
    return select_graph_size<ApplyPermInferenceMerge<CCO, perm_, inference_, merge_>::template Type, MaxCliqueResult>(
            AllGraphSizes(), graph, params);
}

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::Previous>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::None, CCOMerge::All>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::GlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;

template auto parasols::cco_max_clique<CCOPermutations::None, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Defer1, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
template auto parasols::cco_max_clique<CCOPermutations::Sort, CCOInference::LazyGlobalDomination, CCOMerge::None>(const Graph &, const MaxCliqueParams &) -> MaxCliqueResult;
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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 "cpu_instructions/x86/cleanup_instruction_set_properties.h"

#include <unordered_map>
#include "strings/string.h"

#include "cpu_instructions/base/cleanup_instruction_set.h"
#include "glog/logging.h"
#include "util/gtl/map_util.h"

namespace cpu_instructions {
namespace x86 {
namespace {

using ::cpu_instructions::util::OkStatus;
using ::cpu_instructions::util::Status;

const std::unordered_map<string, string>& GetMissingCpuFlags() {
  static const std::unordered_map<string, string>* const kMissingFlags =
      new std::unordered_map<string, string>({
          {"CLFLUSH", "CLFSH"}, {"CLFLUSHOPT", "CLFLUSHOPT"},
      });
  return *kMissingFlags;
}

}  // namespace

Status AddMissingCpuFlags(InstructionSetProto* instruction_set) {
  CHECK(instruction_set != nullptr);
  for (auto& instruction : *instruction_set->mutable_instructions()) {
    const string* const feature_name = FindOrNull(
        GetMissingCpuFlags(), instruction.vendor_syntax().mnemonic());
    if (feature_name) {
      // Be warned if they fix it someday. If this triggers, just remove the
      // rule.
      CHECK_NE(*feature_name, instruction.feature_name())
          << instruction.vendor_syntax().mnemonic();
      instruction.set_feature_name(*feature_name);
    }
  }
  return OkStatus();
}
REGISTER_INSTRUCTION_SET_TRANSFORM(AddMissingCpuFlags, 1000);

namespace {

// Returns the list of protection modes for priviledged instructions.
const std::unordered_map<string, int>& GetProtectionModes() {
  static const std::unordered_map<string, int>* const kProtectionModes =
      new std::unordered_map<string, int>({
          // -----------------------
          // Restricted operations.
          {"CLAC", 0},
          {"CLI", 0},
          {"CLTS", 0},
          {"HLT", 0},
          {"INVD", 0},
          {"INVPCID", 0},
          {"LGDT", 0},
          {"LIDT", 0},
          {"LLDT", 0},
          {"LMSW", 0},
          {"LTR", 0},
          {"MWAIT", 0},
          // The instruction is not marked as priviledged in its doc, but SWAPGR
          // later states that "The IA32_KERNEL_GS_BASE MSR itself is only
          // accessible using RDMSR/WRMSR instructions. Those instructions are
          // only accessible at privilege level 0."
          {"RDMSR", 0},
          {"STAC", 0},
          {"STD", 0},  // Not 100% sure, it looks like the SDM is wrong.
          {"STI", 0},
          {"SWAPGR", 0},
          {"SWAPGS", 0},
          {"WBINVD", 0},
          {"WRMSR", 0},
          {"XRSTORS", 0},
          {"XRSTORS64", 0},
          // -----------------------
          // Input/output.
          // For now assume the worst case: IOPL == 0.
          {"IN", 0},
          {"INS", 0},
          {"INSB", 0},
          {"INSW", 0},
          {"INSD", 0},
          {"OUT", 0},
          {"OUTS", 0},
          {"OUTSB", 0},
          {"OUTSD", 0},
          {"OUTSW", 0},
          // -----------------------
          // SMM mode.
          // For now assume that everything that needs to execute in SMM mode
          // requires CPL 0.
          {"RSM", 0},
      });
  return *kProtectionModes;
}

}  // namespace

Status AddProtectionModes(InstructionSetProto* instruction_set) {
  CHECK(instruction_set != nullptr);
  for (auto& instruction : *instruction_set->mutable_instructions()) {
    const int* mode = FindOrNull(GetProtectionModes(),
                                 instruction.vendor_syntax().mnemonic());
    if (mode) {
      instruction.set_protection_mode(*mode);
    }
  }
  return OkStatus();
}
REGISTER_INSTRUCTION_SET_TRANSFORM(AddProtectionModes, 1000);

}  // namespace x86
}  // namespace cpu_instructions
<commit_msg>RDPMC can run at CPL0.<commit_after>// Copyright 2016 Google Inc.
//
// 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 "cpu_instructions/x86/cleanup_instruction_set_properties.h"

#include <unordered_map>
#include "strings/string.h"

#include "cpu_instructions/base/cleanup_instruction_set.h"
#include "glog/logging.h"
#include "util/gtl/map_util.h"

namespace cpu_instructions {
namespace x86 {
namespace {

using ::cpu_instructions::util::OkStatus;
using ::cpu_instructions::util::Status;

const std::unordered_map<string, string>& GetMissingCpuFlags() {
  static const std::unordered_map<string, string>* const kMissingFlags =
      new std::unordered_map<string, string>({
          {"CLFLUSH", "CLFSH"}, {"CLFLUSHOPT", "CLFLUSHOPT"},
      });
  return *kMissingFlags;
}

}  // namespace

Status AddMissingCpuFlags(InstructionSetProto* instruction_set) {
  CHECK(instruction_set != nullptr);
  for (auto& instruction : *instruction_set->mutable_instructions()) {
    const string* const feature_name = FindOrNull(
        GetMissingCpuFlags(), instruction.vendor_syntax().mnemonic());
    if (feature_name) {
      // Be warned if they fix it someday. If this triggers, just remove the
      // rule.
      CHECK_NE(*feature_name, instruction.feature_name())
          << instruction.vendor_syntax().mnemonic();
      instruction.set_feature_name(*feature_name);
    }
  }
  return OkStatus();
}
REGISTER_INSTRUCTION_SET_TRANSFORM(AddMissingCpuFlags, 1000);

namespace {

// Returns the list of protection modes for priviledged instructions.
const std::unordered_map<string, int>& GetProtectionModes() {
  static const std::unordered_map<string, int>* const kProtectionModes =
      new std::unordered_map<string, int>({
          // -----------------------
          // Restricted operations.
          {"CLAC", 0},
          {"CLI", 0},
          {"CLTS", 0},
          {"HLT", 0},
          {"INVD", 0},
          {"INVPCID", 0},
          {"LGDT", 0},
          {"LIDT", 0},
          {"LLDT", 0},
          {"LMSW", 0},
          {"LTR", 0},
          {"MWAIT", 0},
          // The instruction is not marked as priviledged in its doc, but SWAPGR
          // later states that "The IA32_KERNEL_GS_BASE MSR itself is only
          // accessible using RDMSR/WRMSR instructions. Those instructions are
          // only accessible at privilege level 0."
          {"RDMSR", 0},
          {"RDPMC", 0},
          {"STAC", 0},
          {"STD", 0},  // Not 100% sure, it looks like the SDM is wrong.
          {"STI", 0},
          {"SWAPGR", 0},
          {"SWAPGS", 0},
          {"WBINVD", 0},
          {"WRMSR", 0},
          {"XRSTORS", 0},
          {"XRSTORS64", 0},
          // -----------------------
          // Input/output.
          // For now assume the worst case: IOPL == 0.
          {"IN", 0},
          {"INS", 0},
          {"INSB", 0},
          {"INSW", 0},
          {"INSD", 0},
          {"OUT", 0},
          {"OUTS", 0},
          {"OUTSB", 0},
          {"OUTSD", 0},
          {"OUTSW", 0},
          // -----------------------
          // SMM mode.
          // For now assume that everything that needs to execute in SMM mode
          // requires CPL 0.
          {"RSM", 0},
      });
  return *kProtectionModes;
}

}  // namespace

Status AddProtectionModes(InstructionSetProto* instruction_set) {
  CHECK(instruction_set != nullptr);
  for (auto& instruction : *instruction_set->mutable_instructions()) {
    const int* mode = FindOrNull(GetProtectionModes(),
                                 instruction.vendor_syntax().mnemonic());
    if (mode) {
      instruction.set_protection_mode(*mode);
    }
  }
  return OkStatus();
}
REGISTER_INSTRUCTION_SET_TRANSFORM(AddProtectionModes, 1000);

}  // namespace x86
}  // namespace cpu_instructions
<|endoftext|>


<commit_before>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // We didn't connect so close the socket
         close(socket_value);
         socket_value = -1;

         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
            keepTrying = 0;
         else
         {
            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<commit_msg>Fixed missing constructor.<commit_after>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::atTCPNetworkInterface(short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // We didn't connect so close the socket
         close(socket_value);
         socket_value = -1;

         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
            keepTrying = 0;
         else
         {
            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<|endoftext|>


<commit_before>#include <iostream>

int main(void) {
    int apple = 9;

    auto lambda_capture_value = [apple] () { return apple; };
    auto lambda_capture_reference = [&apple] () { return apple; };
    apple = 0;

    std::cout << "apple = " << apple
        << ", lambda_capture_value return value = " << lambda_capture_value()
        << ", lambda_capture_reference return value = " << lambda_capture_reference()
        << std::endl;

    return 0;
}
<commit_msg>cpp update<commit_after>#include <iostream>

int main(void) {
    int apple = 9;

    auto lambda_capture_value = [apple] () { return apple; };
    auto lambda_capture_reference = [&apple] () { return apple; };
    auto lambda_auto_capture_value = [=] () { return apple; }
    auto lambda_auto_capture_reference = [&] () { return apple; }
    apple = 0;

    std::cout << "apple = " << apple
        << ", lambda_capture_value return value = " << lambda_capture_value()
        << ", lambda_capture_reference return value = " << lambda_capture_reference()
        << ", lambda_auto_capture_value return value = " << lambda_auto_capture_value()
        << ", lambda_auto_capture_reference return value = " << lambda_auto_capture_reference()
        << std::endl;

    return 0;
}
<|endoftext|>