<commit_before>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_ENGINE_HPP_INCLUDED
#define METHCLA_ENGINE_HPP_INCLUDED

#include <methcla/engine.h>

#include <future>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

#include <boost/optional.hpp>
#include <boost/serialization/strong_typedef.hpp>
#include <boost/utility.hpp>

#include <oscpp/client.hpp>
#include <oscpp/server.hpp>
#include <oscpp/print.hpp>

namespace Methcla
{
    inline static void dumpRequest(std::ostream& out, const OSC::Server::Packet& packet)
    {
        out << "Request (send): " << packet << std::endl;
    }

    inline static std::exception_ptr responseToException(const OSC::Server::Packet& packet)
    {
        if (packet.isMessage()) {
            OSC::Server::Message msg(packet);
            if (msg == "/error") {
                auto args(msg.args());
                args.drop(); // request id
                const char* error = args.string();
                return std::make_exception_ptr(std::runtime_error(error));
            } else {
                return std::exception_ptr();
            }
        } else {
            return std::make_exception_ptr(std::invalid_argument("Response is not a message"));
        }
    }

    BOOST_STRONG_TYPEDEF(int32_t, SynthId);
    BOOST_STRONG_TYPEDEF(int32_t, AudioBusId);

    namespace impl
    {
        struct Result : boost::noncopyable
        {
            Result()
                : m_cond(false)
            { }

            inline void notify()
            {
                m_cond = true;
                m_cond_var.notify_one();
            }

            inline void wait()
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                while (!m_cond) {
                    m_cond_var.wait(lock);
                }
                if (m_exc) {
                    std::rethrow_exception(m_exc);
                }
            }

            void set_exception(std::exception_ptr exc)
            {
                BOOST_ASSERT(m_cond);
                std::lock_guard<std::mutex> lock(m_mutex);
                m_exc = exc;
                notify();
            }

            std::mutex m_mutex;
            std::condition_variable m_cond_var;
            bool m_cond;
            std::exception_ptr m_exc;
        };
    };

    template <class T> class Result : impl::Result
    {
    public:
        void set(std::exception_ptr exc)
        {
            set_exception(exc);
        }

        void set(const T& value)
        {
            BOOST_ASSERT(!m_cond);
            std::lock_guard<std::mutex> lock(m_mutex);
            m_value = value;
            notify();
        }

        const T& get()
        {
            wait();
            return m_value;
        }

    private:
        T m_value;
    };

    template <> class Result<void> : impl::Result
    {
    public:
        void set(std::exception_ptr exc)
        {
            set_exception(exc);
        }

        void set()
        {
            BOOST_ASSERT(!m_cond);
            std::lock_guard<std::mutex> lock(m_mutex);
            notify();
        }

        void get()
        {
            wait();
        }
    };

    template <typename T> bool checkResponse(const OSC::Server::Packet& response, Result<T>& result)
    {
        auto error = responseToException(response);
        if (error) {
            result.set(error);
            return false;
        }
        return true;
    }

    class Value
    {
    public:
        enum Type
        {
            kInt,
            kFloat,
            kString
        };

        explicit Value(int x)
            : m_type(kInt)
            , m_int(x)
        { }
        explicit Value(float x)
            : m_type(kFloat)
            , m_float(x)
        { }
        Value(const std::string& x)
            : m_type(kString)
            , m_string(x)
        { }

        void put(OSC::Client::Packet& packet) const
        {
            switch (m_type) {
                case kInt:
                    packet.int32(m_int);
                    break;
                case kFloat:
                    packet.float32(m_float);
                    break;
                case kString:
                    packet.string(m_string.c_str());
                    break;
            }
        }

    private:
        Type m_type;
        int m_int;
        float m_float;
        std::string m_string;
    };

    class Engine
    {
    public:
        Engine(const Methcla_Option* options)
            : m_requestId(kMethcla_Notification+1)
        {
            check(nullptr, methcla_engine_new(handlePacket, this, options, &m_engine));
        }
        ~Engine()
        {
            methcla_engine_free(m_engine);
        }

        operator const Methcla_Engine* () const
        {
            return m_engine;
        }

        operator Methcla_Engine* ()
        {
            return m_engine;
        }

        void start()
        {
            check(m_engine, methcla_engine_start(m_engine));
        }

        void stop()
        {
            check(m_engine, methcla_engine_stop(m_engine));
        }

        SynthId synth(const char* synthDef, const std::vector<float>& controls, const std::list<Value>& options=std::list<Value>())
        {
            const char address[] = "/s_new";
            const size_t numArgs = 4 + OSC::Size::array(controls.size()) + OSC::Size::array(options.size());
            const size_t packetSize = OSC::Size::message(address, numArgs)
                                         + OSC::Size::int32()
                                         + OSC::Size::string(256)
                                         + 2 * OSC::Size::int32()
                                         + controls.size() * OSC::Size::float32()
                                         + 256; // margin for options. better: pool allocator with fixed size packets.

            const Methcla_RequestId requestId = getRequestId();

            OSC::Client::DynamicPacket request(packetSize);
            request
                .openMessage(address, numArgs)
                .int32(requestId)
                .string(synthDef)
                .int32(0)
                .int32(0)
                .putArray(controls.begin(), controls.end());

            request.openArray();
            for (const auto& x : options) {
                x.put(request);
            }
            request.closeArray();

            request.closeMessage();

            dumpRequest(std::cerr, OSC::Server::Packet(request.data(), request.size()));

            Result<SynthId> result;

            withRequest(requestId, request, [&result](Methcla_RequestId requestId, const void* buffer, size_t size){
                OSC::Server::Packet response(buffer, size);
                if (checkResponse(response, result)) {
                    auto args = ((OSC::Server::Message)response).args();
                    int32_t requestId_ = args.int32();
                    BOOST_ASSERT_MSG( requestId_ == requestId, "Request id mismatch");
                    int32_t nodeId = args.int32();
                    std::cerr << "synth: " << requestId << " " << nodeId << std::endl;
                    result.set(SynthId(nodeId));
                }
            });

            return result.get();
        }

        void mapOutput(const SynthId& synth, size_t index, AudioBusId bus)
        {
            const char address[] = "/synth/map/output";
            const size_t numArgs = 4;
            const size_t packetSize = OSC::Size::message(address, numArgs)
                                        + numArgs * OSC::Size::int32();

            Methcla_RequestId requestId = getRequestId();

            OSC::Client::StaticPacket<packetSize> request;
            request
                .openMessage(address, numArgs)
                    .int32(requestId)
                    .int32(synth)
                    .int32(index)
                    .int32(bus)
                .closeMessage();

            dumpRequest(std::cerr, OSC::Server::Packet(request.data(), request.size()));

            Result<void> result;

            withRequest(requestId, request, [&result](Methcla_RequestId requestId, const void* buffer, size_t size){
                if (checkResponse(OSC::Server::Packet(buffer, size), result)) {
                    result.set();
                }
            });

            result.get();
        }

        void freeNode(const SynthId& synth)
        {
            const char address[] = "/n_free";
            const size_t numArgs = 2;
            const size_t packetSize = OSC::Size::message(address, numArgs) + numArgs * OSC::Size::int32();
            const Methcla_RequestId requestId = getRequestId();
            OSC::Client::StaticPacket<packetSize> request;
            request
                .openMessage(address, numArgs)
                    .int32(requestId)
                    .int32(synth)
                .closeMessage();

            Result<void> result;
            withRequest(requestId, request, [&result](Methcla_RequestId, const void* buffer, size_t size){
                if (checkResponse(OSC::Server::Packet(buffer, size), result)) {
                    result.set();
                }
            });
            result.get();
            // send(request);
        }

    private:
        static void check(const Methcla_Engine* engine, Methcla_Error err)
        {
            if (err != kMethcla_NoError) {
                const char* msg = methcla_engine_error_message(engine, err);
                if (err == kMethcla_InvalidArgument)
                    throw std::invalid_argument(msg);
                else if (err == kMethcla_BadAlloc)
                    throw std::bad_alloc();
                else
                    throw std::runtime_error(msg);
            }
        }

        static void handlePacket(void* data, Methcla_RequestId requestId, const void* packet, size_t size)
        {
            static_cast<Engine*>(data)->handlePacket(requestId, packet, size);
        }

        void handlePacket(Methcla_RequestId requestId, const void* packet, size_t size)
        {
            std::lock_guard<std::mutex> lock(m_callbacksMutex);
            // look up request id and invoke callback
            auto it = m_callbacks.find(requestId);
            if (it != m_callbacks.end()) {
                try {
                    it->second(requestId, packet, size);
                    m_callbacks.erase(it);
                } catch (...) {
                    m_callbacks.erase(it);
                    throw;
                }
            }
        }

        void send(const void* packet, size_t size)
        {
            methcla_engine_send(m_engine, packet, size);
        }

        void send(const OSC::Client::Packet& packet)
        {
            send(packet.data(), packet.size());
        }

        Methcla_RequestId getRequestId()
        {
            std::lock_guard<std::mutex> lock(m_requestIdMutex);
            Methcla_RequestId result = m_requestId;
            if (result == kMethcla_Notification) {
                result++;
            }
            m_requestId = result + 1;
            return result;
        }

        void registerResponse(Methcla_RequestId requestId, std::function<void (Methcla_RequestId, const void*, size_t)> callback)
        {
            std::lock_guard<std::mutex> lock(m_callbacksMutex);
            BOOST_ASSERT_MSG( m_callbacks.find(requestId) == m_callbacks.end(), "Duplicate request id" );
            m_callbacks[requestId] = callback;
        }

        void withRequest(Methcla_RequestId requestId, const OSC::Client::Packet& request, std::function<void (Methcla_RequestId, const void*, size_t)> callback)
        {
            registerResponse(requestId, callback);
            send(request);
        }

    private:
        Methcla_Engine*     m_engine;
        Methcla_RequestId   m_requestId;
        std::mutex          m_requestIdMutex;
        std::unordered_map<Methcla_RequestId,std::function<void (Methcla_RequestId, const void*, size_t)>> m_callbacks;
        std::mutex          m_callbacksMutex;
    };
};

#endif // METHCLA_ENGINE_HPP_INCLUDED
<commit_msg>Add bool constructor<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_ENGINE_HPP_INCLUDED
#define METHCLA_ENGINE_HPP_INCLUDED

#include <methcla/engine.h>

#include <future>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

#include <boost/optional.hpp>
#include <boost/serialization/strong_typedef.hpp>
#include <boost/utility.hpp>

#include <oscpp/client.hpp>
#include <oscpp/server.hpp>
#include <oscpp/print.hpp>

namespace Methcla
{
    inline static void dumpRequest(std::ostream& out, const OSC::Server::Packet& packet)
    {
        out << "Request (send): " << packet << std::endl;
    }

    inline static std::exception_ptr responseToException(const OSC::Server::Packet& packet)
    {
        if (packet.isMessage()) {
            OSC::Server::Message msg(packet);
            if (msg == "/error") {
                auto args(msg.args());
                args.drop(); // request id
                const char* error = args.string();
                return std::make_exception_ptr(std::runtime_error(error));
            } else {
                return std::exception_ptr();
            }
        } else {
            return std::make_exception_ptr(std::invalid_argument("Response is not a message"));
        }
    }

    BOOST_STRONG_TYPEDEF(int32_t, SynthId);
    BOOST_STRONG_TYPEDEF(int32_t, AudioBusId);

    namespace impl
    {
        struct Result : boost::noncopyable
        {
            Result()
                : m_cond(false)
            { }

            inline void notify()
            {
                m_cond = true;
                m_cond_var.notify_one();
            }

            inline void wait()
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                while (!m_cond) {
                    m_cond_var.wait(lock);
                }
                if (m_exc) {
                    std::rethrow_exception(m_exc);
                }
            }

            void set_exception(std::exception_ptr exc)
            {
                BOOST_ASSERT(m_cond);
                std::lock_guard<std::mutex> lock(m_mutex);
                m_exc = exc;
                notify();
            }

            std::mutex m_mutex;
            std::condition_variable m_cond_var;
            bool m_cond;
            std::exception_ptr m_exc;
        };
    };

    template <class T> class Result : impl::Result
    {
    public:
        void set(std::exception_ptr exc)
        {
            set_exception(exc);
        }

        void set(const T& value)
        {
            BOOST_ASSERT(!m_cond);
            std::lock_guard<std::mutex> lock(m_mutex);
            m_value = value;
            notify();
        }

        const T& get()
        {
            wait();
            return m_value;
        }

    private:
        T m_value;
    };

    template <> class Result<void> : impl::Result
    {
    public:
        void set(std::exception_ptr exc)
        {
            set_exception(exc);
        }

        void set()
        {
            BOOST_ASSERT(!m_cond);
            std::lock_guard<std::mutex> lock(m_mutex);
            notify();
        }

        void get()
        {
            wait();
        }
    };

    template <typename T> bool checkResponse(const OSC::Server::Packet& response, Result<T>& result)
    {
        auto error = responseToException(response);
        if (error) {
            result.set(error);
            return false;
        }
        return true;
    }

    class Value
    {
    public:
        enum Type
        {
            kInt,
            kFloat,
            kString
        };

        explicit Value(int x)
            : m_type(kInt)
            , m_int(x)
        { }
        explicit Value(float x)
            : m_type(kFloat)
            , m_float(x)
        { }
        Value(const std::string& x)
            : m_type(kString)
            , m_string(x)
        { }

        explicit Value(bool x)
            : m_type(kInt)
            , m_int(x)
        { }

        void put(OSC::Client::Packet& packet) const
        {
            switch (m_type) {
                case kInt:
                    packet.int32(m_int);
                    break;
                case kFloat:
                    packet.float32(m_float);
                    break;
                case kString:
                    packet.string(m_string.c_str());
                    break;
            }
        }

    private:
        Type m_type;
        int m_int;
        float m_float;
        std::string m_string;
    };

    class Engine
    {
    public:
        Engine(const Methcla_Option* options)
            : m_requestId(kMethcla_Notification+1)
        {
            check(nullptr, methcla_engine_new(handlePacket, this, options, &m_engine));
        }
        ~Engine()
        {
            methcla_engine_free(m_engine);
        }

        operator const Methcla_Engine* () const
        {
            return m_engine;
        }

        operator Methcla_Engine* ()
        {
            return m_engine;
        }

        void start()
        {
            check(m_engine, methcla_engine_start(m_engine));
        }

        void stop()
        {
            check(m_engine, methcla_engine_stop(m_engine));
        }

        SynthId synth(const char* synthDef, const std::vector<float>& controls, const std::list<Value>& options=std::list<Value>())
        {
            const char address[] = "/s_new";
            const size_t numArgs = 4 + OSC::Size::array(controls.size()) + OSC::Size::array(options.size());
            const size_t packetSize = OSC::Size::message(address, numArgs)
                                         + OSC::Size::int32()
                                         + OSC::Size::string(256)
                                         + 2 * OSC::Size::int32()
                                         + controls.size() * OSC::Size::float32()
                                         + 256; // margin for options. better: pool allocator with fixed size packets.

            const Methcla_RequestId requestId = getRequestId();

            OSC::Client::DynamicPacket request(packetSize);
            request
                .openMessage(address, numArgs)
                .int32(requestId)
                .string(synthDef)
                .int32(0)
                .int32(0)
                .putArray(controls.begin(), controls.end());

            request.openArray();
            for (const auto& x : options) {
                x.put(request);
            }
            request.closeArray();

            request.closeMessage();

            dumpRequest(std::cerr, OSC::Server::Packet(request.data(), request.size()));

            Result<SynthId> result;

            withRequest(requestId, request, [&result](Methcla_RequestId requestId, const void* buffer, size_t size){
                OSC::Server::Packet response(buffer, size);
                if (checkResponse(response, result)) {
                    auto args = ((OSC::Server::Message)response).args();
                    int32_t requestId_ = args.int32();
                    BOOST_ASSERT_MSG( requestId_ == requestId, "Request id mismatch");
                    int32_t nodeId = args.int32();
                    std::cerr << "synth: " << requestId << " " << nodeId << std::endl;
                    result.set(SynthId(nodeId));
                }
            });

            return result.get();
        }

        void mapOutput(const SynthId& synth, size_t index, AudioBusId bus)
        {
            const char address[] = "/synth/map/output";
            const size_t numArgs = 4;
            const size_t packetSize = OSC::Size::message(address, numArgs)
                                        + numArgs * OSC::Size::int32();

            Methcla_RequestId requestId = getRequestId();

            OSC::Client::StaticPacket<packetSize> request;
            request
                .openMessage(address, numArgs)
                    .int32(requestId)
                    .int32(synth)
                    .int32(index)
                    .int32(bus)
                .closeMessage();

            dumpRequest(std::cerr, OSC::Server::Packet(request.data(), request.size()));

            Result<void> result;

            withRequest(requestId, request, [&result](Methcla_RequestId requestId, const void* buffer, size_t size){
                if (checkResponse(OSC::Server::Packet(buffer, size), result)) {
                    result.set();
                }
            });

            result.get();
        }

        void freeNode(const SynthId& synth)
        {
            const char address[] = "/n_free";
            const size_t numArgs = 2;
            const size_t packetSize = OSC::Size::message(address, numArgs) + numArgs * OSC::Size::int32();
            const Methcla_RequestId requestId = getRequestId();
            OSC::Client::StaticPacket<packetSize> request;
            request
                .openMessage(address, numArgs)
                    .int32(requestId)
                    .int32(synth)
                .closeMessage();

            Result<void> result;
            withRequest(requestId, request, [&result](Methcla_RequestId, const void* buffer, size_t size){
                if (checkResponse(OSC::Server::Packet(buffer, size), result)) {
                    result.set();
                }
            });
            result.get();
            // send(request);
        }

    private:
        static void check(const Methcla_Engine* engine, Methcla_Error err)
        {
            if (err != kMethcla_NoError) {
                const char* msg = methcla_engine_error_message(engine, err);
                if (err == kMethcla_InvalidArgument)
                    throw std::invalid_argument(msg);
                else if (err == kMethcla_BadAlloc)
                    throw std::bad_alloc();
                else
                    throw std::runtime_error(msg);
            }
        }

        static void handlePacket(void* data, Methcla_RequestId requestId, const void* packet, size_t size)
        {
            static_cast<Engine*>(data)->handlePacket(requestId, packet, size);
        }

        void handlePacket(Methcla_RequestId requestId, const void* packet, size_t size)
        {
            std::lock_guard<std::mutex> lock(m_callbacksMutex);
            // look up request id and invoke callback
            auto it = m_callbacks.find(requestId);
            if (it != m_callbacks.end()) {
                try {
                    it->second(requestId, packet, size);
                    m_callbacks.erase(it);
                } catch (...) {
                    m_callbacks.erase(it);
                    throw;
                }
            }
        }

        void send(const void* packet, size_t size)
        {
            methcla_engine_send(m_engine, packet, size);
        }

        void send(const OSC::Client::Packet& packet)
        {
            send(packet.data(), packet.size());
        }

        Methcla_RequestId getRequestId()
        {
            std::lock_guard<std::mutex> lock(m_requestIdMutex);
            Methcla_RequestId result = m_requestId;
            if (result == kMethcla_Notification) {
                result++;
            }
            m_requestId = result + 1;
            return result;
        }

        void registerResponse(Methcla_RequestId requestId, std::function<void (Methcla_RequestId, const void*, size_t)> callback)
        {
            std::lock_guard<std::mutex> lock(m_callbacksMutex);
            BOOST_ASSERT_MSG( m_callbacks.find(requestId) == m_callbacks.end(), "Duplicate request id" );
            m_callbacks[requestId] = callback;
        }

        void withRequest(Methcla_RequestId requestId, const OSC::Client::Packet& request, std::function<void (Methcla_RequestId, const void*, size_t)> callback)
        {
            registerResponse(requestId, callback);
            send(request);
        }

    private:
        Methcla_Engine*     m_engine;
        Methcla_RequestId   m_requestId;
        std::mutex          m_requestIdMutex;
        std::unordered_map<Methcla_RequestId,std::function<void (Methcla_RequestId, const void*, size_t)>> m_callbacks;
        std::mutex          m_callbacksMutex;
    };
};

#endif // METHCLA_ENGINE_HPP_INCLUDED
<|endoftext|>


<commit_before>#include "LinearModule.h"
#include <cstdio>

LinearModule::LinearModule(ModularSynth& synth)
	:SynthModule(synth, moduleId, 3, 1, 0)
{
}

void LinearModule::cycle()
{
	float input = getInput(0);
	float x = std::min(1.0f, std::max(0.0f, getInput(1)));
	float y = std::min(1.0f, std::max(0.0f, getInput(1)));
	float amp;

	if (input >= x)
	{
		amp = (input - y) * (input - x) + y;
	}
	else
	{
		amp = input * y / x;
	}

	setOutput(0, input * amp);
}

const char * LinearModule::getInputName(int input) const
{
	static const char *names[] = {"Input", "X", "Y"};
	return names[input];
}

const char * LinearModule::getOutputName(int output) const
{
	static const char *names[] = {"Output"};
	return names[output];
}

const char * LinearModule::getName() const
{
	return "Linear";
}

SynthModule * LinearModule::createModule(ModularSynth& synth)
{
	return new LinearModule(synth);
}
<commit_msg>LinearModule<commit_after>#include "LinearModule.h"
#include <cstdio>
#include <algorithm>

LinearModule::LinearModule(ModularSynth& synth)
	:SynthModule(synth, moduleId, 3, 1, 0)
{
}

void LinearModule::cycle()
{
	float input = getInput(0);
	float x = std::min(1.0f, std::max(0.0f, getInput(1)));
	float y = std::min(1.0f, std::max(0.0f, getInput(2)));
	float amp;

	if (input >= x)
	{
		amp = (1.0f - y) * (input - x) / (1.0f - x) + y;
	}
	else
	{
		amp = y * input / x;
	}

	setOutput(0, amp);
}

const char * LinearModule::getInputName(int input) const
{
	static const char *names[] = {"Input", "X", "Y"};
	return names[input];
}

const char * LinearModule::getOutputName(int output) const
{
	static const char *names[] = {"Output"};
	return names[output];
}

const char * LinearModule::getName() const
{
	return "Linear";
}

SynthModule * LinearModule::createModule(ModularSynth& synth)
{
	return new LinearModule(synth);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5nodeinstanceclientproxy.h"

#include <QCoreApplication>

#include "qt5informationnodeinstanceserver.h"
#include "qt5previewnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h"

namespace QmlDesigner {

Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
    NodeInstanceClientProxy(parent)
{
    if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) {
        setNodeInstanceServer(new Qt5PreviewNodeInstanceServer(this));
    } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
        setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this));
    } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {
        setNodeInstanceServer(new Qt5RenderNodeInstanceServer(this));
    }

    initializeSocket();
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner.NodeInstances: Quick Window Manager Support<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5nodeinstanceclientproxy.h"

#include <QCoreApplication>

#include "qt5informationnodeinstanceserver.h"
#include "qt5previewnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h"

#include <designersupport.h>

namespace QmlDesigner {

Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
    NodeInstanceClientProxy(parent)
{
    DesignerSupport::activateDesignerWindowManager();
    if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) {
        setNodeInstanceServer(new Qt5PreviewNodeInstanceServer(this));
    } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
        setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this));
    } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {
        setNodeInstanceServer(new Qt5RenderNodeInstanceServer(this));
    }

    initializeSocket();
}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>#include <sys/errno.h>
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/io_system.h>

IOSystem::Handle::Handle(int fd, Channel *owner)
: log_("/io/system/handle"),
  fd_(fd),
  owner_(owner),
  close_callback_(NULL),
  close_action_(NULL),
  read_amount_(0),
  read_buffer_(),
  read_callback_(NULL),
  read_action_(NULL),
  write_buffer_(),
  write_callback_(NULL),
  write_action_(NULL)
{ }

IOSystem::Handle::~Handle()
{
	ASSERT(fd_ == -1);

	ASSERT(close_action_ == NULL);
	ASSERT(close_callback_ == NULL);

	ASSERT(read_action_ == NULL);
	ASSERT(read_callback_ == NULL);

	ASSERT(write_action_ == NULL);
	ASSERT(write_callback_ == NULL);
}

void
IOSystem::Handle::close_callback(void)
{
	close_action_->cancel();
	close_action_ = NULL;

	ASSERT(fd_ != -1);
	int rv = ::close(fd_);
	if (rv == -1) {
		switch (errno) {
		case EAGAIN:
			close_action_ = close_schedule();
			break;
		default:
			close_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(close_callback_);
			close_action_ = a;
			close_callback_ = NULL;
			break;
		}
		return;
	}
	fd_ = -1;
	close_callback_->event(Event(Event::Done, 0));
	Action *a = EventSystem::instance()->schedule(close_callback_);
	close_action_ = a;
	close_callback_ = NULL;
}

void
IOSystem::Handle::close_cancel(void)
{
	ASSERT(close_action_ != NULL);
	close_action_->cancel();
	close_action_ = NULL;

	if (close_callback_ != NULL) {
		delete close_callback_;
		close_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::close_schedule(void)
{
	ASSERT(close_action_ == NULL);
	Callback *cb = callback(this, &IOSystem::Handle::close_callback);
	Action *a = EventSystem::instance()->schedule(cb);
	return (a);
}

void
IOSystem::Handle::read_callback(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	size_t rlen;

	if (read_amount_ == 0)
		rlen = 65536;
	else
		rlen = read_amount_ - read_buffer_.length();
	ASSERT(rlen != 0);

	uint8_t data[rlen];
	ssize_t len = ::read(fd_, data, sizeof data);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			read_action_ = read_schedule();
			break;
		default:
			read_callback_->event(Event(Event::Error, errno, read_buffer_));
			Action *a = EventSystem::instance()->schedule(read_callback_);
			read_action_ = a;
			read_callback_ = NULL;
			read_buffer_.clear();
			read_amount_ = 0;
			break;
		}
		return;
	}

	/*
	 * XXX
	 * If we get an EOS from EventPoll, should we just terminate after that
	 * one read?  How can we tell how much data is still available to be
	 * read?  Will we get it all in one read?  Eventually, one would expect
	 * to get a read with a length of 0, or an error, but will kevent even
	 * continue to fire off read events?
	 */
	if (len == 0) {
		read_callback_->event(Event(Event::EOS, 0, read_buffer_));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_action_ = a;
		read_callback_ = NULL;
		read_buffer_.clear();
		read_amount_ = 0;
		return;
	}

	read_buffer_.append(data, len);
	read_action_ = read_schedule();
}

void
IOSystem::Handle::read_cancel(void)
{
	ASSERT(read_action_ != NULL);
	read_action_->cancel();
	read_action_ = NULL;

	if (read_callback_ != NULL) {
		delete read_callback_;
		read_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::read_schedule(void)
{
	ASSERT(read_action_ == NULL);

	if (!read_buffer_.empty() && read_buffer_.length() >= read_amount_) {
		if (read_amount_ == 0)
			read_amount_ = read_buffer_.length();
		read_callback_->event(Event(Event::Done, 0, Buffer(read_buffer_, read_amount_)));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_callback_ = NULL;
		read_buffer_.skip(read_amount_);
		read_amount_ = 0;
		return (a);
	}

	EventCallback *cb = callback(this, &IOSystem::Handle::read_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
IOSystem::Handle::write_callback(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	/* XXX This doesn't handle UDP nicely.  Right?  */
	struct iovec iov[IOV_MAX];
	size_t iovcnt = write_buffer_.fill_iovec(iov, IOV_MAX);

	ssize_t len = ::writev(fd_, iov, iovcnt);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			write_action_ = write_schedule();
			break;
		default:
			write_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(write_callback_);
			write_action_ = a;
			write_callback_ = NULL;
			break;
		}
		return;
	}

	write_buffer_.skip(len);

	if (write_buffer_.empty()) {
		write_callback_->event(Event(Event::Done, 0));
		Action *a = EventSystem::instance()->schedule(write_callback_);
		write_action_ = a;
		write_callback_ = NULL;
		return;
	}
	write_action_ = write_schedule();
}

void
IOSystem::Handle::write_cancel(void)
{
	ASSERT(write_action_ != NULL);
	write_action_->cancel();
	write_action_ = NULL;

	if (write_callback_ != NULL) {
		delete write_callback_;
		write_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::write_schedule(void)
{
	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &IOSystem::Handle::write_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

IOSystem::IOSystem(void)
: log_("/io/system"),
  handle_map_()
{ }

IOSystem::~IOSystem()
{
	ASSERT(handle_map_.empty());
}

void
IOSystem::attach(int fd, Channel *owner)
{
	ASSERT(handle_map_.find(handle_key_t(fd, owner)) == handle_map_.end());
	handle_map_[handle_key_t(fd, owner)] = new IOSystem::Handle(fd, owner);
}

void
IOSystem::detach(int fd, Channel *owner)
{
	handle_map_t::iterator it;
	IOSystem::Handle *h;

	it = handle_map_.find(handle_key_t(fd, owner));
	ASSERT(it != handle_map_.end());

	h = it->second;
	ASSERT(h != NULL);
	ASSERT(h->owner_ == owner);

	handle_map_.erase(it);
	delete h;
}

Action *
IOSystem::close(int fd, Channel *owner, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->close_callback_ == NULL);
	ASSERT(h->close_action_ == NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);

	ASSERT(h->fd_ != -1);

	h->close_callback_ = cb;
	h->close_action_ = h->close_schedule();
	return (cancellation(h, &IOSystem::Handle::close_cancel));
}

Action *
IOSystem::read(int fd, Channel *owner, size_t amount, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	h->read_amount_ = amount;
	h->read_callback_ = cb;
	h->read_action_ = h->read_schedule();
	return (cancellation(h, &IOSystem::Handle::read_cancel));
}

Action *
IOSystem::write(int fd, Channel *owner, Buffer *buffer, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);
	ASSERT(h->write_buffer_.empty());

	h->write_buffer_.append(buffer);
	buffer->clear();

	h->write_callback_ = cb;
	h->write_action_ = h->write_schedule();
	return (cancellation(h, &IOSystem::Handle::write_cancel));
}
<commit_msg>Only ever try to read 64K onto the stack at a time.<commit_after>#include <sys/errno.h>
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/io_system.h>

#define	IO_READ_BUFFER_SIZE	65536

IOSystem::Handle::Handle(int fd, Channel *owner)
: log_("/io/system/handle"),
  fd_(fd),
  owner_(owner),
  close_callback_(NULL),
  close_action_(NULL),
  read_amount_(0),
  read_buffer_(),
  read_callback_(NULL),
  read_action_(NULL),
  write_buffer_(),
  write_callback_(NULL),
  write_action_(NULL)
{ }

IOSystem::Handle::~Handle()
{
	ASSERT(fd_ == -1);

	ASSERT(close_action_ == NULL);
	ASSERT(close_callback_ == NULL);

	ASSERT(read_action_ == NULL);
	ASSERT(read_callback_ == NULL);

	ASSERT(write_action_ == NULL);
	ASSERT(write_callback_ == NULL);
}

void
IOSystem::Handle::close_callback(void)
{
	close_action_->cancel();
	close_action_ = NULL;

	ASSERT(fd_ != -1);
	int rv = ::close(fd_);
	if (rv == -1) {
		switch (errno) {
		case EAGAIN:
			close_action_ = close_schedule();
			break;
		default:
			close_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(close_callback_);
			close_action_ = a;
			close_callback_ = NULL;
			break;
		}
		return;
	}
	fd_ = -1;
	close_callback_->event(Event(Event::Done, 0));
	Action *a = EventSystem::instance()->schedule(close_callback_);
	close_action_ = a;
	close_callback_ = NULL;
}

void
IOSystem::Handle::close_cancel(void)
{
	ASSERT(close_action_ != NULL);
	close_action_->cancel();
	close_action_ = NULL;

	if (close_callback_ != NULL) {
		delete close_callback_;
		close_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::close_schedule(void)
{
	ASSERT(close_action_ == NULL);
	Callback *cb = callback(this, &IOSystem::Handle::close_callback);
	Action *a = EventSystem::instance()->schedule(cb);
	return (a);
}

void
IOSystem::Handle::read_callback(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	size_t rlen;

	if (read_amount_ == 0)
		rlen = IO_READ_BUFFER_SIZE;
	else {
		rlen = read_amount_ - read_buffer_.length();
		ASSERT(rlen != 0);
		if (rlen > IO_READ_BUFFER_SIZE)
			rlen = IO_READ_BUFFER_SIZE;
	}

	uint8_t data[IO_READ_BUFFER_SIZE];
	ssize_t len = ::read(fd_, data, sizeof data);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			read_action_ = read_schedule();
			break;
		default:
			read_callback_->event(Event(Event::Error, errno, read_buffer_));
			Action *a = EventSystem::instance()->schedule(read_callback_);
			read_action_ = a;
			read_callback_ = NULL;
			read_buffer_.clear();
			read_amount_ = 0;
			break;
		}
		return;
	}

	/*
	 * XXX
	 * If we get an EOS from EventPoll, should we just terminate after that
	 * one read?  How can we tell how much data is still available to be
	 * read?  Will we get it all in one read?  Eventually, one would expect
	 * to get a read with a length of 0, or an error, but will kevent even
	 * continue to fire off read events?
	 */
	if (len == 0) {
		read_callback_->event(Event(Event::EOS, 0, read_buffer_));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_action_ = a;
		read_callback_ = NULL;
		read_buffer_.clear();
		read_amount_ = 0;
		return;
	}

	read_buffer_.append(data, len);
	read_action_ = read_schedule();
}

void
IOSystem::Handle::read_cancel(void)
{
	ASSERT(read_action_ != NULL);
	read_action_->cancel();
	read_action_ = NULL;

	if (read_callback_ != NULL) {
		delete read_callback_;
		read_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::read_schedule(void)
{
	ASSERT(read_action_ == NULL);

	if (!read_buffer_.empty() && read_buffer_.length() >= read_amount_) {
		if (read_amount_ == 0)
			read_amount_ = read_buffer_.length();
		read_callback_->event(Event(Event::Done, 0, Buffer(read_buffer_, read_amount_)));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_callback_ = NULL;
		read_buffer_.skip(read_amount_);
		read_amount_ = 0;
		return (a);
	}

	EventCallback *cb = callback(this, &IOSystem::Handle::read_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
IOSystem::Handle::write_callback(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	/* XXX This doesn't handle UDP nicely.  Right?  */
	struct iovec iov[IOV_MAX];
	size_t iovcnt = write_buffer_.fill_iovec(iov, IOV_MAX);

	ssize_t len = ::writev(fd_, iov, iovcnt);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			write_action_ = write_schedule();
			break;
		default:
			write_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(write_callback_);
			write_action_ = a;
			write_callback_ = NULL;
			break;
		}
		return;
	}

	write_buffer_.skip(len);

	if (write_buffer_.empty()) {
		write_callback_->event(Event(Event::Done, 0));
		Action *a = EventSystem::instance()->schedule(write_callback_);
		write_action_ = a;
		write_callback_ = NULL;
		return;
	}
	write_action_ = write_schedule();
}

void
IOSystem::Handle::write_cancel(void)
{
	ASSERT(write_action_ != NULL);
	write_action_->cancel();
	write_action_ = NULL;

	if (write_callback_ != NULL) {
		delete write_callback_;
		write_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::write_schedule(void)
{
	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &IOSystem::Handle::write_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

IOSystem::IOSystem(void)
: log_("/io/system"),
  handle_map_()
{ }

IOSystem::~IOSystem()
{
	ASSERT(handle_map_.empty());
}

void
IOSystem::attach(int fd, Channel *owner)
{
	ASSERT(handle_map_.find(handle_key_t(fd, owner)) == handle_map_.end());
	handle_map_[handle_key_t(fd, owner)] = new IOSystem::Handle(fd, owner);
}

void
IOSystem::detach(int fd, Channel *owner)
{
	handle_map_t::iterator it;
	IOSystem::Handle *h;

	it = handle_map_.find(handle_key_t(fd, owner));
	ASSERT(it != handle_map_.end());

	h = it->second;
	ASSERT(h != NULL);
	ASSERT(h->owner_ == owner);

	handle_map_.erase(it);
	delete h;
}

Action *
IOSystem::close(int fd, Channel *owner, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->close_callback_ == NULL);
	ASSERT(h->close_action_ == NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);

	ASSERT(h->fd_ != -1);

	h->close_callback_ = cb;
	h->close_action_ = h->close_schedule();
	return (cancellation(h, &IOSystem::Handle::close_cancel));
}

Action *
IOSystem::read(int fd, Channel *owner, size_t amount, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	h->read_amount_ = amount;
	h->read_callback_ = cb;
	h->read_action_ = h->read_schedule();
	return (cancellation(h, &IOSystem::Handle::read_cancel));
}

Action *
IOSystem::write(int fd, Channel *owner, Buffer *buffer, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);
	ASSERT(h->write_buffer_.empty());

	h->write_buffer_.append(buffer);
	buffer->clear();

	h->write_callback_ = cb;
	h->write_action_ = h->write_schedule();
	return (cancellation(h, &IOSystem::Handle::write_cancel));
}
<|endoftext|>


<commit_before>/*
 * ESP8266 LLMNR responder
 * Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
 *
 * Based on:
 * ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
 * Version 1.1
 * Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
 * ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
 * MDNS-SD Suport 2015 Hristo Gochkov
 * Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
 *
 * License (MIT license):
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Reference:
 * https://tools.ietf.org/html/rfc4795 (LLMNR)
 * https://tools.ietf.org/html/rfc1035 (DNS)
 */

#include <debug.h>
#include <functional>
#include <ESP8266LLMNR.h>
#include <WiFiUdp.h>

extern "C" {
#include <user_interface.h>
}

#include <lwip/udp.h>
#include <lwip/igmp.h>
#include <include/UdpContext.h>

//#define LLMNR_DEBUG

#define BIT(x) (1 << (x))

#define FLAGS_QR                BIT(15)
#define FLAGS_OP_SHIFT          11
#define FLAGS_OP_MASK           0xf
#define FLAGS_C                 BIT(10)
#define FLAGS_TC                BIT(9)
#define FLAGS_T                 BIT(8)
#define FLAGS_RCODE_SHIFT       0
#define FLAGS_RCODE_MASK        0xf

#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read())
#define _conn_read8() _conn->read()
#define _conn_readS(b, l) _conn->read((b), (l));

static const IPAddress LLMNR_MULTICAST_ADDR(224, 0, 0, 252);
static const int LLMNR_MULTICAST_TTL = 1;
static const int LLMNR_PORT = 5355;

LLMNRResponder::LLMNRResponder() :
    _conn(0) {
}

LLMNRResponder::~LLMNRResponder() {
    if (_conn)
        _conn->unref();
}

bool LLMNRResponder::begin(const char* hostname) {
    // Max length for a single label in DNS
    if (strlen(hostname) > 63)
        return false;

    _hostname = hostname;
    _hostname.toLowerCase();

    _sta_got_ip_handler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& event){
        _restart();
    });

    _sta_disconnected_handler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& event) {
        _restart();
    });

    return _restart();
}

void LLMNRResponder::notify_ap_change() {
    _restart();
}

bool LLMNRResponder::_restart() {
    if (_conn) {
        _conn->unref();
        _conn = 0;
    }

    ip_addr_t multicast_addr;
    multicast_addr.addr = (uint32_t)LLMNR_MULTICAST_ADDR;

    if (igmp_joingroup(IP_ADDR_ANY, &multicast_addr) != ERR_OK)
        return false;

    _conn = new UdpContext;
    _conn->ref();

    if (!_conn->listen(*IP_ADDR_ANY, LLMNR_PORT))
        return false;

    _conn->setMulticastTTL(LLMNR_MULTICAST_TTL);
    _conn->onRx(std::bind(&LLMNRResponder::_process_packet, this));
    _conn->connect(multicast_addr, LLMNR_PORT);
}

void LLMNRResponder::_process_packet() {
    if (!_conn || !_conn->next())
        return;

#ifdef LLMNR_DEBUG
    Serial.println("LLMNR: RX'd packet");
#endif

    uint16_t id = _conn_read16();
    uint16_t flags = _conn_read16();
    uint16_t qdcount = _conn_read16();
    uint16_t ancount = _conn_read16();
    uint16_t nscount = _conn_read16();
    uint16_t arcount = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("LLMNR: ID=");
    Serial.println(id, HEX);
    Serial.print("LLMNR: FLAGS=");
    Serial.println(flags, HEX);
    Serial.print("LLMNR: QDCOUNT=");
    Serial.println(qdcount);
    Serial.print("LLMNR: ANCOUNT=");
    Serial.println(ancount);
    Serial.print("LLMNR: NSCOUNT=");
    Serial.println(nscount);
    Serial.print("LLMNR: ARCOUNT=");
    Serial.println(arcount);
#endif

#define BAD_FLAGS (FLAGS_QR | (FLAGS_OP_MASK << FLAGS_OP_SHIFT) | FLAGS_C)
    if (flags & BAD_FLAGS) {
#ifdef LLMNR_DEBUG
        Serial.println("Bad flags");
#endif
        return;
    }

    if (qdcount != 1) {
#ifdef LLMNR_DEBUG
        Serial.println("QDCOUNT != 1");
#endif
        return;
    }

    if (ancount || nscount || arcount) {
#ifdef LLMNR_DEBUG
        Serial.println("AN/NS/AR-COUNT != 0");
#endif
        return;
    }

    uint8_t namelen = _conn_read8();
#ifdef LLMNR_DEBUG
    Serial.print("QNAME len ");
    Serial.println(namelen);
#endif
    if (namelen != _hostname.length()) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME len mismatch");
#endif
        return;
    }

    char qname[64];
    _conn_readS(qname, namelen);
    _conn_read8();
    qname[namelen] = '\0';
#ifdef LLMNR_DEBUG
    Serial.print("QNAME ");
    Serial.println(qname);
#endif

    if (strcmp(_hostname.c_str(), qname)) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME mismatch");
#endif
        return;
    }

    uint16_t qtype = _conn_read16();
    uint16_t qclass = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("QTYPE ");
    Serial.print(qtype);
    Serial.print(" QCLASS ");
    Serial.println(qclass);
#endif

    bool have_rr =
        (qtype == 1) && /* A */
        (qclass == 1); /* IN */

    _conn->flush();

#ifdef LLMNR_DEBUG
    Serial.println("Match; responding");
    if (!have_rr)
        Serial.println("(no matching RRs)");
#endif

    struct ip_info remote_ip_info;
    remote_ip_info.ip.addr = _conn->getRemoteAddress();
    struct ip_info ip_info;
    bool match_ap = false;
    if (wifi_get_opmode() & SOFTAP_MODE) {
        wifi_get_ip_info(SOFTAP_IF, &ip_info);
        if (ip_info.ip.addr && ip_addr_netcmp(&remote_ip_info.ip, &ip_info.ip, &ip_info.netmask))
            match_ap = true;
    }
    if (!match_ap)
        wifi_get_ip_info(STATION_IF, &ip_info);
    uint32_t ip = ip_info.ip.addr;

    // Header
    uint8_t header[] = {
        id >> 8, id & 0xff, // ID
        FLAGS_QR >> 8, 0, // FLAGS
        0, 1, // QDCOUNT
        0, !!have_rr, // ANCOUNT
        0, 0, // NSCOUNT
        0, 0, // ARCOUNT
    };
    _conn->append(reinterpret_cast<const char*>(header), sizeof(header));
    // Question
    _conn->append(reinterpret_cast<const char*>(&namelen), 1);
    _conn->append(qname, namelen);
    uint8_t q[] = {
        0, // Name terminator
        0, 1, // TYPE (A)
        0, 1, // CLASS (IN)
    };
    _conn->append(reinterpret_cast<const char*>(q), sizeof(q));
    // Answer, if we have one
    if (have_rr) {
        _conn->append(reinterpret_cast<const char*>(&namelen), 1);
        _conn->append(qname, namelen);
        uint8_t rr[] = {
            0, // Name terminator
            0, 1, // TYPE (A)
            0, 1, // CLASS (IN)
            0, 0, 0, 30, // TTL (30 seconds)
            0, 4, // RDLENGTH
            ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, // RDATA
        };
        _conn->append(reinterpret_cast<const char*>(rr), sizeof(rr));
    }
    _conn->setMulticastInterface(remote_ip_info.ip);
    _conn->send(&remote_ip_info.ip, _conn->getRemotePort());
}

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_LLMNR)
LLMNRResponder LLMNR;
#endif
<commit_msg>Fix ESP8266LLMNR for build with lwip2 (#3821)<commit_after>/*
 * ESP8266 LLMNR responder
 * Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
 *
 * Based on:
 * ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
 * Version 1.1
 * Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
 * ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
 * MDNS-SD Suport 2015 Hristo Gochkov
 * Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
 *
 * License (MIT license):
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Reference:
 * https://tools.ietf.org/html/rfc4795 (LLMNR)
 * https://tools.ietf.org/html/rfc1035 (DNS)
 */

#include <debug.h>
#include <functional>
#include <ESP8266LLMNR.h>
#include <WiFiUdp.h>

extern "C" {
#include <user_interface.h>
}

#include <lwip/udp.h>
#include <lwip/igmp.h>
#include <include/UdpContext.h>

//#define LLMNR_DEBUG

//BIT(x) is defined in tools/sdk/c_types.h

#define FLAGS_QR                BIT(15)
#define FLAGS_OP_SHIFT          11
#define FLAGS_OP_MASK           0xf
#define FLAGS_C                 BIT(10)
#define FLAGS_TC                BIT(9)
#define FLAGS_T                 BIT(8)
#define FLAGS_RCODE_SHIFT       0
#define FLAGS_RCODE_MASK        0xf

#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read())
#define _conn_read8() _conn->read()
#define _conn_readS(b, l) _conn->read((b), (l));

static const IPAddress LLMNR_MULTICAST_ADDR(224, 0, 0, 252);
static const int LLMNR_MULTICAST_TTL = 1;
static const int LLMNR_PORT = 5355;

LLMNRResponder::LLMNRResponder() :
    _conn(0) {
}

LLMNRResponder::~LLMNRResponder() {
    if (_conn)
        _conn->unref();
}

bool LLMNRResponder::begin(const char* hostname) {
    // Max length for a single label in DNS
    if (strlen(hostname) > 63)
        return false;

    _hostname = hostname;
    _hostname.toLowerCase();

    _sta_got_ip_handler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& event){
        _restart();
    });

    _sta_disconnected_handler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& event) {
        _restart();
    });

    return _restart();
}

void LLMNRResponder::notify_ap_change() {
    _restart();
}

bool LLMNRResponder::_restart() {
    if (_conn) {
        _conn->unref();
        _conn = 0;
    }

    ip_addr_t multicast_addr;
    multicast_addr.addr = (uint32_t)LLMNR_MULTICAST_ADDR;

    if (igmp_joingroup(IP_ADDR_ANY, &multicast_addr) != ERR_OK)
        return false;

    _conn = new UdpContext;
    _conn->ref();

    if (!_conn->listen(*IP_ADDR_ANY, LLMNR_PORT))
        return false;

    _conn->setMulticastTTL(LLMNR_MULTICAST_TTL);
    _conn->onRx(std::bind(&LLMNRResponder::_process_packet, this));
    _conn->connect(multicast_addr, LLMNR_PORT);
}

void LLMNRResponder::_process_packet() {
    if (!_conn || !_conn->next())
        return;

#ifdef LLMNR_DEBUG
    Serial.println("LLMNR: RX'd packet");
#endif

    uint16_t id = _conn_read16();
    uint16_t flags = _conn_read16();
    uint16_t qdcount = _conn_read16();
    uint16_t ancount = _conn_read16();
    uint16_t nscount = _conn_read16();
    uint16_t arcount = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("LLMNR: ID=");
    Serial.println(id, HEX);
    Serial.print("LLMNR: FLAGS=");
    Serial.println(flags, HEX);
    Serial.print("LLMNR: QDCOUNT=");
    Serial.println(qdcount);
    Serial.print("LLMNR: ANCOUNT=");
    Serial.println(ancount);
    Serial.print("LLMNR: NSCOUNT=");
    Serial.println(nscount);
    Serial.print("LLMNR: ARCOUNT=");
    Serial.println(arcount);
#endif

#define BAD_FLAGS (FLAGS_QR | (FLAGS_OP_MASK << FLAGS_OP_SHIFT) | FLAGS_C)
    if (flags & BAD_FLAGS) {
#ifdef LLMNR_DEBUG
        Serial.println("Bad flags");
#endif
        return;
    }

    if (qdcount != 1) {
#ifdef LLMNR_DEBUG
        Serial.println("QDCOUNT != 1");
#endif
        return;
    }

    if (ancount || nscount || arcount) {
#ifdef LLMNR_DEBUG
        Serial.println("AN/NS/AR-COUNT != 0");
#endif
        return;
    }

    uint8_t namelen = _conn_read8();
#ifdef LLMNR_DEBUG
    Serial.print("QNAME len ");
    Serial.println(namelen);
#endif
    if (namelen != _hostname.length()) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME len mismatch");
#endif
        return;
    }

    char qname[64];
    _conn_readS(qname, namelen);
    _conn_read8();
    qname[namelen] = '\0';
#ifdef LLMNR_DEBUG
    Serial.print("QNAME ");
    Serial.println(qname);
#endif

    if (strcmp(_hostname.c_str(), qname)) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME mismatch");
#endif
        return;
    }

    uint16_t qtype = _conn_read16();
    uint16_t qclass = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("QTYPE ");
    Serial.print(qtype);
    Serial.print(" QCLASS ");
    Serial.println(qclass);
#endif

    bool have_rr =
        (qtype == 1) && /* A */
        (qclass == 1); /* IN */

    _conn->flush();

#ifdef LLMNR_DEBUG
    Serial.println("Match; responding");
    if (!have_rr)
        Serial.println("(no matching RRs)");
#endif

    ip_addr_t remote_ip;
    remote_ip.addr = _conn->getRemoteAddress();

    struct ip_info ip_info;
    bool match_ap = false;
    if (wifi_get_opmode() & SOFTAP_MODE) {
        wifi_get_ip_info(SOFTAP_IF, &ip_info);
    if (ip_info.ip.addr && ip_addr_netcmp(&remote_ip, &ip_info.ip, &ip_info.netmask))
        match_ap = true;
    }
    if (!match_ap)
        wifi_get_ip_info(STATION_IF, &ip_info);
    uint32_t ip = ip_info.ip.addr;

    // Header
    uint8_t header[] = {
        id >> 8, id & 0xff, // ID
        FLAGS_QR >> 8, 0, // FLAGS
        0, 1, // QDCOUNT
        0, !!have_rr, // ANCOUNT
        0, 0, // NSCOUNT
        0, 0, // ARCOUNT
    };
    _conn->append(reinterpret_cast<const char*>(header), sizeof(header));
    // Question
    _conn->append(reinterpret_cast<const char*>(&namelen), 1);
    _conn->append(qname, namelen);
    uint8_t q[] = {
        0, // Name terminator
        0, 1, // TYPE (A)
        0, 1, // CLASS (IN)
    };
    _conn->append(reinterpret_cast<const char*>(q), sizeof(q));
    // Answer, if we have one
    if (have_rr) {
        _conn->append(reinterpret_cast<const char*>(&namelen), 1);
        _conn->append(qname, namelen);
        uint8_t rr[] = {
            0, // Name terminator
            0, 1, // TYPE (A)
            0, 1, // CLASS (IN)
            0, 0, 0, 30, // TTL (30 seconds)
            0, 4, // RDLENGTH
            ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, // RDATA
        };
        _conn->append(reinterpret_cast<const char*>(rr), sizeof(rr));
    }
    _conn->setMulticastInterface(remote_ip);
    _conn->send(&remote_ip, _conn->getRemotePort());
}

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_LLMNR)
LLMNRResponder LLMNR;
#endif
<|endoftext|>


<commit_before>//===--- Stubs.cpp - Swift Language ABI Runtime Stubs ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Misc stubs for functions which should be defined in the core standard
// library, but are difficult or impossible to write in Swift at the
// moment.
//
//===----------------------------------------------------------------------===//

#if defined(__FreeBSD__)
#define _WITH_GETLINE
#endif

#include <sys/resource.h>
#include <sys/errno.h>
#include <unistd.h>
#include <climits>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#if defined(__CYGWIN__)
// Cygwin does not support uselocal() and locale_t.
// Instead, we will use the locale feature in stringstream.
typedef void *locale_t;
#include <sstream>
#include <cmath>
#define  fmodl(lhs, rhs)  std::fmod(lhs, rhs)
#else
#include <xlocale.h>
#endif
#include <limits>
#include "llvm/ADT/StringExtras.h"
#include "swift/Runtime/Debug.h"
#include "swift/Basic/Lazy.h"

static uint64_t uint64ToStringImpl(char *Buffer, uint64_t Value,
                                   int64_t Radix, bool Uppercase,
                                   bool Negative) {
  char *P = Buffer;
  uint64_t Y = Value;

  if (Y == 0) {
    *P++ = '0';
  } else if (Radix == 10) {
    while (Y) {
      *P++ = '0' + char(Y % 10);
      Y /= 10;
    }
  } else {
    unsigned Radix32 = Radix;
    while (Y) {
      *P++ = llvm::hexdigit(Y % Radix32, !Uppercase);
      Y /= Radix32;
    }
  }

  if (Negative)
    *P++ = '-';
  std::reverse(Buffer, P);
  return size_t(P - Buffer);
}

extern "C" uint64_t swift_int64ToString(char *Buffer, size_t BufferLength,
                                        int64_t Value, int64_t Radix,
                                        bool Uppercase) {
  if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 65))
    swift::crash("swift_int64ToString: insufficient buffer size");

  if (Radix == 0 || Radix > 36)
    swift::crash("swift_int64ToString: invalid radix for string conversion");

  bool Negative = Value < 0;

  // Compute an absolute value safely, without using unary negation on INT_MIN,
  // which is undefined behavior.
  uint64_t UnsignedValue = Value;
  if (Negative) {
    // Assumes two's complement representation.
    UnsignedValue = ~UnsignedValue + 1;
  }

  return uint64ToStringImpl(Buffer, UnsignedValue, Radix, Uppercase,
                            Negative);
}

extern "C" uint64_t swift_uint64ToString(char *Buffer, intptr_t BufferLength,
                                         uint64_t Value, int64_t Radix,
                                         bool Uppercase) {
  if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 64))
    swift::crash("swift_int64ToString: insufficient buffer size");

  if (Radix == 0 || Radix > 36)
    swift::crash("swift_int64ToString: invalid radix for string conversion");

  return uint64ToStringImpl(Buffer, Value, Radix, Uppercase,
                            /*Negative=*/false);
}

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__CYGWIN__)
static inline locale_t getCLocale() {
  // On these platforms convenience functions from xlocale.h interpret nullptr
  // as C locale.
  return nullptr;
}
#else
static locale_t makeCLocale() {
  locale_t CLocale = newlocale(LC_ALL_MASK, "C", nullptr);
  if (!CLocale) {
    swift::crash("makeCLocale: newlocale() returned a null pointer");
  }
  return CLocale;
}

static locale_t getCLocale() {
  return SWIFT_LAZY_CONSTANT(makeCLocale());
}
#endif

#if defined(__APPLE__)
#define swift_snprintf_l snprintf_l
#elif defined(__CYGWIN__)
// In Cygwin, swift_snprintf_l() is not used.
#else
static int swift_snprintf_l(char *Str, size_t StrSize, locale_t Locale,
                            const char *Format, ...) {
  if (Locale == nullptr) {
    Locale = getCLocale();
  }
  locale_t OldLocale = uselocale(Locale);

  va_list Args;
  va_start(Args, Format);
  int Result = std::vsnprintf(Str, StrSize, Format, Args);
  va_end(Args);

  uselocale(OldLocale);

  return Result;
}
#endif

template <typename T>
static uint64_t swift_floatingPointToString(char *Buffer, size_t BufferLength,
                                            T Value, const char *Format,
                                            bool Debug) {
  if (BufferLength < 32)
    swift::crash("swift_floatingPointToString: insufficient buffer size");

  int Precision = std::numeric_limits<T>::digits10;
  if (Debug) {
    Precision = std::numeric_limits<T>::max_digits10;
  }

#if defined(__CYGWIN__)
  // Cygwin does not support uselocale(), but we can use the locale feature
  // in stringstrem object.
  std::ostringstream ValueStream;
  ValueStream.width(0);
  ValueStream.precision(Precision);
  ValueStream.imbue(std::locale::classic());
  ValueStream << Value;
  std::string  ValueString(ValueStream.str());
  int i = ValueString.length();
  if (size_t(i) < BufferLength) {
    std::copy(ValueString.begin(), ValueString.end(), Buffer);
    Buffer[i] = '\0';
  }
#else
  // Pass a null locale to use the C locale.
  int i = swift_snprintf_l(Buffer, BufferLength, /*locale=*/nullptr, Format,
                           Precision, Value);
#endif

  if (i < 0)
    swift::crash(
        "swift_floatingPointToString: unexpected return value from sprintf");
  if (size_t(i) >= BufferLength)
    swift::crash("swift_floatingPointToString: insufficient buffer size");

  // Add ".0" to a float that (a) is not in scientific notation, (b) does not
  // already have a fractional part, (c) is not infinite, and (d) is not a NaN
  // value.
  if (strchr(Buffer, 'e') == nullptr && strchr(Buffer, '.') == nullptr &&
      strchr(Buffer, 'n') == nullptr) {
    Buffer[i++] = '.';
    Buffer[i++] = '0';
  }

  return i;
}

extern "C" uint64_t swift_float32ToString(char *Buffer, size_t BufferLength,
                                          float Value, bool Debug) {
  return swift_floatingPointToString<float>(Buffer, BufferLength, Value,
                                            "%0.*g", Debug);
}

extern "C" uint64_t swift_float64ToString(char *Buffer, size_t BufferLength,
                                          double Value, bool Debug) {
  return swift_floatingPointToString<double>(Buffer, BufferLength, Value,
                                             "%0.*g", Debug);
}

extern "C" uint64_t swift_float80ToString(char *Buffer, size_t BufferLength,
                                          long double Value, bool Debug) {
  return swift_floatingPointToString<long double>(Buffer, BufferLength, Value,
                                                  "%0.*Lg", Debug);
}

/// \param[out] LinePtr Replaced with the pointer to the malloc()-allocated
/// line.  Can be NULL if no characters were read.
///
/// \returns Size of character data returned in \c LinePtr, or -1
/// if an error occurred, or EOF was reached.
extern "C" ssize_t swift_stdlib_readLine_stdin(char **LinePtr) {
  size_t Capacity = 0;
  return getline(LinePtr, &Capacity, stdin);
}

extern "C" float _swift_fmodf(float lhs, float rhs) {
    return fmodf(lhs, rhs);
}

extern "C" double _swift_fmod(double lhs, double rhs) {
    return fmod(lhs, rhs);
}

extern "C" long double _swift_fmodl(long double lhs, long double rhs) {
    return fmodl(lhs, rhs);
}

// Although this builtin is provided by clang rt builtins,
// it isn't provided by libgcc, which is the default
// runtime library on Linux, even when compiling with clang.
// This implementation is copied here to avoid a new dependency
// on compiler-rt on Linux.
// FIXME: rdar://14883575 Libcompiler_rt omits muloti4
#if (defined(__APPLE__) && defined(__arm64__)) || \
    (defined(__linux__) && defined(__x86_64__)) || \
    (defined(__linux__) && defined(__aarch64__)) || \
    (defined(__linux__) && defined(__powerpc64__))

typedef int      ti_int __attribute__ ((mode (TI)));
extern "C"
ti_int
__muloti4(ti_int a, ti_int b, int* overflow)
{
    const int N = (int)(sizeof(ti_int) * CHAR_BIT);
    const ti_int MIN = (ti_int)1 << (N-1);
    const ti_int MAX = ~MIN;
    *overflow = 0;
    ti_int result = a * b;
    if (a == MIN)
    {
        if (b != 0 && b != 1)
	    *overflow = 1;
	return result;
    }
    if (b == MIN)
    {
        if (a != 0 && a != 1)
	    *overflow = 1;
        return result;
    }
    ti_int sa = a >> (N - 1);
    ti_int abs_a = (a ^ sa) - sa;
    ti_int sb = b >> (N - 1);
    ti_int abs_b = (b ^ sb) - sb;
    if (abs_a < 2 || abs_b < 2)
        return result;
    if (sa == sb)
    {
        if (abs_a > MAX / abs_b)
            *overflow = 1;
    }
    else
    {
        if (abs_a > MIN / -abs_b)
            *overflow = 1;
    }
    return result;
}

#endif

#if defined(__linux__) && defined(__arm__)
// Similar to above, but with mulodi4.  Perhaps this is
// something that shouldn't be done, and is a bandaid over
// some other lower-level architecture issue that I'm
// missing.  Perhaps relevant bug report:
// FIXME: https://llvm.org/bugs/show_bug.cgi?id=14469
typedef int      di_int __attribute__ ((mode (DI)));
extern "C"
di_int
__mulodi4(di_int a, di_int b, int* overflow)
{
    const int N = (int)(sizeof(di_int) * CHAR_BIT);
    const di_int MIN = (di_int)1 << (N-1);
    const di_int MAX = ~MIN;
    *overflow = 0;
    di_int result = a * b;
    if (a == MIN)
    {
        if (b != 0 && b != 1)
            *overflow = 1;
        return result;
    }
    if (b == MIN)
    {
        if (a != 0 && a != 1)
            *overflow = 1;
        return result;
    }
    di_int sa = a >> (N - 1);
    di_int abs_a = (a ^ sa) - sa;
    di_int sb = b >> (N - 1);
    di_int abs_b = (b ^ sb) - sb;
    if (abs_a < 2 || abs_b < 2)
        return result;
    if (sa == sb)
    {
        if (abs_a > MAX / abs_b)
            *overflow = 1;
    }
    else
    {
        if (abs_a > MIN / -abs_b)
            *overflow = 1;
    }
    return result;
}
#endif

#if defined(__CYGWIN__)
// Cygwin does not have strtoXX_l() functions.
// These are wrapper functions only for C locale.
static long double strtold_l(const char *nptr, char **EndPtr, locale_t) {
  std::string lastLocale = setlocale(LC_ALL, "");
  setlocale(LC_ALL, "C");
  long double result = strtold(nptr, EndPtr);
  setlocale(LC_ALL, lastLocale.c_str());
  return result;
}

static double strtod_l(const char *nptr, char **EndPtr, locale_t) {
  std::string lastLocale = setlocale(LC_ALL, "");
  setlocale(LC_ALL, "C");
  double result = strtod(nptr, EndPtr);
  setlocale(LC_ALL, lastLocale.c_str());
  return result;
}

static float strtof_l(const char *nptr, char **EndPtr, locale_t) {
  std::string lastLocale = setlocale(LC_ALL, "");
  setlocale(LC_ALL, "C");
  float result = strtof(nptr, EndPtr);
  setlocale(LC_ALL, lastLocale.c_str());
  return result;
}
#endif

// We can't return Float80, but we can receive a pointer to one, so
// switch the return type and the out parameter on strtold.
template <typename T>
static const char *_swift_stdlib_strtoX_clocale_impl(
    const char * nptr, T* outResult, T huge,
    T (*posixImpl)(const char *, char **, locale_t)
) {
  char *EndPtr;
  errno = 0;
  const auto result = posixImpl(nptr, &EndPtr, getCLocale());
  *outResult = result;
  if (result == huge || result == -huge || result == 0.0 || result == -0.0) {
      if (errno == ERANGE)
          EndPtr = nullptr;
  }
  return EndPtr;
}

extern "C" const char *_swift_stdlib_strtold_clocale(
  const char * nptr, void *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, static_cast<long double*>(outResult), HUGE_VALL, strtold_l);
}

extern "C" const char *_swift_stdlib_strtod_clocale(
    const char * nptr, double *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, outResult, HUGE_VAL, strtod_l);
}

extern "C" const char *_swift_stdlib_strtof_clocale(
    const char * nptr, float *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, outResult, HUGE_VALF, strtof_l);
}

extern "C" void _swift_stdlib_flockfile_stdout() {
  flockfile(stdout);
}

extern "C" void _swift_stdlib_funlockfile_stdout() {
  funlockfile(stdout);
}

extern "C" int _swift_stdlib_putc_stderr(int C) {
  return putc(C, stderr);
}

extern "C" size_t _swift_stdlib_getHardwareConcurrency() {
  return sysconf(_SC_NPROCESSORS_ONLN);
}
<commit_msg>Rewrite strtoX_clocale_impl with stringstream<commit_after>//===--- Stubs.cpp - Swift Language ABI Runtime Stubs ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Misc stubs for functions which should be defined in the core standard
// library, but are difficult or impossible to write in Swift at the
// moment.
//
//===----------------------------------------------------------------------===//

#if defined(__FreeBSD__)
#define _WITH_GETLINE
#endif

#include <sys/resource.h>
#include <sys/errno.h>
#include <unistd.h>
#include <climits>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#if defined(__CYGWIN__)
#include <sstream>
#include <cmath>
#define  fmodl(lhs, rhs)  std::fmod(lhs, rhs)
#else
#include <xlocale.h>
#endif
#include <limits>
#include "llvm/ADT/StringExtras.h"
#include "swift/Runtime/Debug.h"
#include "swift/Basic/Lazy.h"

static uint64_t uint64ToStringImpl(char *Buffer, uint64_t Value,
                                   int64_t Radix, bool Uppercase,
                                   bool Negative) {
  char *P = Buffer;
  uint64_t Y = Value;

  if (Y == 0) {
    *P++ = '0';
  } else if (Radix == 10) {
    while (Y) {
      *P++ = '0' + char(Y % 10);
      Y /= 10;
    }
  } else {
    unsigned Radix32 = Radix;
    while (Y) {
      *P++ = llvm::hexdigit(Y % Radix32, !Uppercase);
      Y /= Radix32;
    }
  }

  if (Negative)
    *P++ = '-';
  std::reverse(Buffer, P);
  return size_t(P - Buffer);
}

extern "C" uint64_t swift_int64ToString(char *Buffer, size_t BufferLength,
                                        int64_t Value, int64_t Radix,
                                        bool Uppercase) {
  if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 65))
    swift::crash("swift_int64ToString: insufficient buffer size");

  if (Radix == 0 || Radix > 36)
    swift::crash("swift_int64ToString: invalid radix for string conversion");

  bool Negative = Value < 0;

  // Compute an absolute value safely, without using unary negation on INT_MIN,
  // which is undefined behavior.
  uint64_t UnsignedValue = Value;
  if (Negative) {
    // Assumes two's complement representation.
    UnsignedValue = ~UnsignedValue + 1;
  }

  return uint64ToStringImpl(Buffer, UnsignedValue, Radix, Uppercase,
                            Negative);
}

extern "C" uint64_t swift_uint64ToString(char *Buffer, intptr_t BufferLength,
                                         uint64_t Value, int64_t Radix,
                                         bool Uppercase) {
  if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 64))
    swift::crash("swift_int64ToString: insufficient buffer size");

  if (Radix == 0 || Radix > 36)
    swift::crash("swift_int64ToString: invalid radix for string conversion");

  return uint64ToStringImpl(Buffer, Value, Radix, Uppercase,
                            /*Negative=*/false);
}

#if defined(__APPLE__) || defined(__FreeBSD__)
static inline locale_t getCLocale() {
  // On these platforms convenience functions from xlocale.h interpret nullptr
  // as C locale.
  return nullptr;
}
#elif defined(__CYGWIN__)
// In Cygwin, getCLocale() is not used.
#else
static locale_t makeCLocale() {
  locale_t CLocale = newlocale(LC_ALL_MASK, "C", nullptr);
  if (!CLocale) {
    swift::crash("makeCLocale: newlocale() returned a null pointer");
  }
  return CLocale;
}

static locale_t getCLocale() {
  return SWIFT_LAZY_CONSTANT(makeCLocale());
}
#endif

#if defined(__APPLE__)
#define swift_snprintf_l snprintf_l
#elif defined(__CYGWIN__)
// In Cygwin, swift_snprintf_l() is not used.
#else
static int swift_snprintf_l(char *Str, size_t StrSize, locale_t Locale,
                            const char *Format, ...) {
  if (Locale == nullptr) {
    Locale = getCLocale();
  }
  locale_t OldLocale = uselocale(Locale);

  va_list Args;
  va_start(Args, Format);
  int Result = std::vsnprintf(Str, StrSize, Format, Args);
  va_end(Args);

  uselocale(OldLocale);

  return Result;
}
#endif

template <typename T>
static uint64_t swift_floatingPointToString(char *Buffer, size_t BufferLength,
                                            T Value, const char *Format,
                                            bool Debug) {
  if (BufferLength < 32)
    swift::crash("swift_floatingPointToString: insufficient buffer size");

  int Precision = std::numeric_limits<T>::digits10;
  if (Debug) {
    Precision = std::numeric_limits<T>::max_digits10;
  }

#if defined(__CYGWIN__)
  // Cygwin does not support uselocale(), but we can use the locale feature
  // in stringstream object.
  std::ostringstream ValueStream;
  ValueStream.width(0);
  ValueStream.precision(Precision);
  ValueStream.imbue(std::locale::classic());
  ValueStream << Value;
  std::string  ValueString(ValueStream.str());
  size_t i = ValueString.length();

  if (i < BufferLength) {
    std::copy(ValueString.begin(), ValueString.end(), Buffer);
    Buffer[i] = '\0';
  } else {
    swift::crash("swift_floatingPointToString: insufficient buffer size");
  }
#else
  // Pass a null locale to use the C locale.
  int i = swift_snprintf_l(Buffer, BufferLength, /*locale=*/nullptr, Format,
                           Precision, Value);

  if (i < 0)
    swift::crash(
        "swift_floatingPointToString: unexpected return value from sprintf");
  if (size_t(i) >= BufferLength)
    swift::crash("swift_floatingPointToString: insufficient buffer size");
#endif

  // Add ".0" to a float that (a) is not in scientific notation, (b) does not
  // already have a fractional part, (c) is not infinite, and (d) is not a NaN
  // value.
  if (strchr(Buffer, 'e') == nullptr && strchr(Buffer, '.') == nullptr &&
      strchr(Buffer, 'n') == nullptr) {
    Buffer[i++] = '.';
    Buffer[i++] = '0';
  }

  return i;
}

extern "C" uint64_t swift_float32ToString(char *Buffer, size_t BufferLength,
                                          float Value, bool Debug) {
  return swift_floatingPointToString<float>(Buffer, BufferLength, Value,
                                            "%0.*g", Debug);
}

extern "C" uint64_t swift_float64ToString(char *Buffer, size_t BufferLength,
                                          double Value, bool Debug) {
  return swift_floatingPointToString<double>(Buffer, BufferLength, Value,
                                             "%0.*g", Debug);
}

extern "C" uint64_t swift_float80ToString(char *Buffer, size_t BufferLength,
                                          long double Value, bool Debug) {
  return swift_floatingPointToString<long double>(Buffer, BufferLength, Value,
                                                  "%0.*Lg", Debug);
}

/// \param[out] LinePtr Replaced with the pointer to the malloc()-allocated
/// line.  Can be NULL if no characters were read.
///
/// \returns Size of character data returned in \c LinePtr, or -1
/// if an error occurred, or EOF was reached.
extern "C" ssize_t swift_stdlib_readLine_stdin(char **LinePtr) {
  size_t Capacity = 0;
  return getline(LinePtr, &Capacity, stdin);
}

extern "C" float _swift_fmodf(float lhs, float rhs) {
    return fmodf(lhs, rhs);
}

extern "C" double _swift_fmod(double lhs, double rhs) {
    return fmod(lhs, rhs);
}

extern "C" long double _swift_fmodl(long double lhs, long double rhs) {
    return fmodl(lhs, rhs);
}

// Although this builtin is provided by clang rt builtins,
// it isn't provided by libgcc, which is the default
// runtime library on Linux, even when compiling with clang.
// This implementation is copied here to avoid a new dependency
// on compiler-rt on Linux.
// FIXME: rdar://14883575 Libcompiler_rt omits muloti4
#if (defined(__APPLE__) && defined(__arm64__)) || \
    (defined(__linux__) && defined(__x86_64__)) || \
    (defined(__linux__) && defined(__aarch64__)) || \
    (defined(__linux__) && defined(__powerpc64__))

typedef int      ti_int __attribute__ ((mode (TI)));
extern "C"
ti_int
__muloti4(ti_int a, ti_int b, int* overflow)
{
    const int N = (int)(sizeof(ti_int) * CHAR_BIT);
    const ti_int MIN = (ti_int)1 << (N-1);
    const ti_int MAX = ~MIN;
    *overflow = 0;
    ti_int result = a * b;
    if (a == MIN)
    {
        if (b != 0 && b != 1)
	    *overflow = 1;
	return result;
    }
    if (b == MIN)
    {
        if (a != 0 && a != 1)
	    *overflow = 1;
        return result;
    }
    ti_int sa = a >> (N - 1);
    ti_int abs_a = (a ^ sa) - sa;
    ti_int sb = b >> (N - 1);
    ti_int abs_b = (b ^ sb) - sb;
    if (abs_a < 2 || abs_b < 2)
        return result;
    if (sa == sb)
    {
        if (abs_a > MAX / abs_b)
            *overflow = 1;
    }
    else
    {
        if (abs_a > MIN / -abs_b)
            *overflow = 1;
    }
    return result;
}

#endif

#if defined(__linux__) && defined(__arm__)
// Similar to above, but with mulodi4.  Perhaps this is
// something that shouldn't be done, and is a bandaid over
// some other lower-level architecture issue that I'm
// missing.  Perhaps relevant bug report:
// FIXME: https://llvm.org/bugs/show_bug.cgi?id=14469
typedef int      di_int __attribute__ ((mode (DI)));
extern "C"
di_int
__mulodi4(di_int a, di_int b, int* overflow)
{
    const int N = (int)(sizeof(di_int) * CHAR_BIT);
    const di_int MIN = (di_int)1 << (N-1);
    const di_int MAX = ~MIN;
    *overflow = 0;
    di_int result = a * b;
    if (a == MIN)
    {
        if (b != 0 && b != 1)
            *overflow = 1;
        return result;
    }
    if (b == MIN)
    {
        if (a != 0 && a != 1)
            *overflow = 1;
        return result;
    }
    di_int sa = a >> (N - 1);
    di_int abs_a = (a ^ sa) - sa;
    di_int sb = b >> (N - 1);
    di_int abs_b = (b ^ sb) - sb;
    if (abs_a < 2 || abs_b < 2)
        return result;
    if (sa == sb)
    {
        if (abs_a > MAX / abs_b)
            *overflow = 1;
    }
    else
    {
        if (abs_a > MIN / -abs_b)
            *overflow = 1;
    }
    return result;
}
#endif

#if defined(__CYGWIN__)
// Cygwin does not support uselocale(), but we can use the locale feature
// in stringstream object.
template <typename T>
static const char *_swift_stdlib_strtoX_clocale_impl(
    const char *nptr, T *outResult) {
  std::istringstream ValueStream(nptr);
  ValueStream.imbue(std::locale::classic());
  T ParsedValue;
  ValueStream >> ParsedValue;
  *outResult = ParsedValue;

  int pos = ValueStream.tellg();
  if (pos <= 0)
    return nullptr;

  return nptr + pos;
}

extern "C" const char *_swift_stdlib_strtold_clocale(
    const char *nptr, void *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, static_cast<long double*>(outResult));
}

extern "C" const char *_swift_stdlib_strtod_clocale(
    const char * nptr, double *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(nptr, outResult);
}

extern "C" const char *_swift_stdlib_strtof_clocale(
    const char * nptr, float *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(nptr, outResult);
}
#else

// We can't return Float80, but we can receive a pointer to one, so
// switch the return type and the out parameter on strtold.
template <typename T>
static const char *_swift_stdlib_strtoX_clocale_impl(
    const char * nptr, T* outResult, T huge,
    T (*posixImpl)(const char *, char **, locale_t)
) {
  char *EndPtr;
  errno = 0;
  const auto result = posixImpl(nptr, &EndPtr, getCLocale());
  *outResult = result;
  if (result == huge || result == -huge || result == 0.0 || result == -0.0) {
      if (errno == ERANGE)
          EndPtr = nullptr;
  }
  return EndPtr;
}

extern "C" const char *_swift_stdlib_strtold_clocale(
  const char * nptr, void *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, static_cast<long double*>(outResult), HUGE_VALL, strtold_l);
}

extern "C" const char *_swift_stdlib_strtod_clocale(
    const char * nptr, double *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, outResult, HUGE_VAL, strtod_l);
}

extern "C" const char *_swift_stdlib_strtof_clocale(
    const char * nptr, float *outResult) {
  return _swift_stdlib_strtoX_clocale_impl(
    nptr, outResult, HUGE_VALF, strtof_l);
}
#endif

extern "C" void _swift_stdlib_flockfile_stdout() {
  flockfile(stdout);
}

extern "C" void _swift_stdlib_funlockfile_stdout() {
  funlockfile(stdout);
}

extern "C" int _swift_stdlib_putc_stderr(int C) {
  return putc(C, stderr);
}

extern "C" size_t _swift_stdlib_getHardwareConcurrency() {
  return sysconf(_SC_NPROCESSORS_ONLN);
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: ioapic.cc,v 1.8 2002/08/27 19:54:46 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
#include <stdio.h>
#include  "bochs.h"

class bx_ioapic_c bx_ioapic;
#define LOG_THIS  bx_ioapic.

void
bx_io_redirect_entry_t::parse_value ()
{
  dest = (value >> 56) & 0xff;
  masked = (value >> 16) & 1;
  trig_mode = (value >> 15) & 1;
  remote_irr = (value >> 14) & 1;
  polarity = (value >> 13) & 1;
  //delivery_status = (value >> 12) & 1;
  delivery_status = 0;  // always say the message has gone through
  dest_mode = (value >> 11) & 1;
  delivery_mode = (value >> 8) & 7;
  vector = (value >> 0) & 0xff;
}

void
bx_io_redirect_entry_t::sprintf_self (char *buf)
{
  sprintf (buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
}

bx_ioapic_c::bx_ioapic_c ()
  : bx_generic_apic_c ()
{
  put("IOAP");
  settype(IOAPICLOG);
}

bx_ioapic_c::~bx_ioapic_c () {
}

void
bx_ioapic_c::init ()
{
  bx_generic_apic_c::init ();
  BX_DEBUG(("initializing I/O APIC"));
  base_addr = 0xfec00000;
  ioregsel = 0;
  // all interrupts masked
  for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    ioredtbl[i].set_even_word (0x00010000);
    ioredtbl[i].set_odd_word  (0x00000000);
  }
  irr = 0;
}

void
bx_ioapic_c::reset ()
{
}

void
bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
{
  BX_DEBUG( ("I/O APIC read_aligned addr=%08x, len=%d", address, len));
  BX_ASSERT (len == 4);
  address &= 0xff;
  if (address == 0x00) {
    // select register
    *data = ioregsel;
    return;
  } else if (address != 0x10) {
      BX_PANIC(("IOAPIC: read from unsupported address"));
  }
  // only reached when reading data register
  switch (ioregsel) {
  case 0x00:  // APIC ID
    *data = ((id & 0xf) << 24);
    return;
  case 0x01:  // version
    *data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16)
            | (BX_IOAPIC_VERSION_ID & 0x0f);
    return;
  case 0x02:
    BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
    *data = 0;
    return;
  default:
    int index = (ioregsel - 0x10) >> 1;
    if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
      bx_io_redirect_entry_t *entry = ioredtbl + index;
      *data = (ioregsel&1) ? entry->get_odd_word() : entry->get_even_word ();
      return;
    }
    BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void
bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
{
  BX_DEBUG(("IOAPIC: write addr=%08x, data=%08x, len=%d", address, *value, len));
  address &= 0xff;
  if (address == 0x00)  {
    ioregsel = *value;
    return;
  } else if (address != 0x10) {
    BX_PANIC(("IOAPIC: write to unsupported address"));
  }
  // only reached when writing data register
  switch (ioregsel) {
    case 0x00: // set APIC ID
      {
	Bit8u newid = (*value >> 24) & 0xf;
	BX_INFO(("IOAPIC: setting id to 0x%x", newid));
	set_id (newid);
	return;
      }
    case 0x01: // version
    case 0x02: // arbitration id
      BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
      return;
    default:
      int index = (ioregsel - 0x10) >> 1;
      if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
	bx_io_redirect_entry_t *entry = ioredtbl + index;
	if (ioregsel&1)
	  entry->set_odd_word (*value);
	else
	  entry->set_even_word (*value);
	char buf[1024];
	entry->sprintf_self (buf);
	BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
	service_ioapic ();
	return;
      }
      BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::trigger_irq (unsigned vector, unsigned from)
{
  BX_DEBUG(("IOAPIC: received interrupt %d", vector));
  if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) {
    Bit32u bit = 1<<vector;
    if ((irr & bit) == 0) {
      irr |= bit;
      service_ioapic ();
    }
  } else BX_PANIC(("IOAPIC: vector %d out of range", vector));
}

void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from)
{
  BX_DEBUG(("IOAPIC: interrupt %d went away", num));
}

void bx_ioapic_c::service_ioapic ()
{
  // look in IRR and deliver any interrupts that are not masked.
  BX_DEBUG(("IOAPIC: servicing"));
  for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
    if (irr & (1<<bit)) {
      bx_io_redirect_entry_t *entry = ioredtbl + bit;
      if (!entry->masked) {
	// clear irr bit and deliver
	Boolean done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
	if (done) irr &= ~(1<<bit);
      }
    }
  }
}
<commit_msg>- reset should have one arg, unsigned int type<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: ioapic.cc,v 1.9 2002/08/29 16:52:47 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
#include <stdio.h>
#include  "bochs.h"

class bx_ioapic_c bx_ioapic;
#define LOG_THIS  bx_ioapic.

void
bx_io_redirect_entry_t::parse_value ()
{
  dest = (value >> 56) & 0xff;
  masked = (value >> 16) & 1;
  trig_mode = (value >> 15) & 1;
  remote_irr = (value >> 14) & 1;
  polarity = (value >> 13) & 1;
  //delivery_status = (value >> 12) & 1;
  delivery_status = 0;  // always say the message has gone through
  dest_mode = (value >> 11) & 1;
  delivery_mode = (value >> 8) & 7;
  vector = (value >> 0) & 0xff;
}

void
bx_io_redirect_entry_t::sprintf_self (char *buf)
{
  sprintf (buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
}

bx_ioapic_c::bx_ioapic_c ()
  : bx_generic_apic_c ()
{
  put("IOAP");
  settype(IOAPICLOG);
}

bx_ioapic_c::~bx_ioapic_c () {
}

void
bx_ioapic_c::init ()
{
  bx_generic_apic_c::init ();
  BX_DEBUG(("initializing I/O APIC"));
  base_addr = 0xfec00000;
  ioregsel = 0;
  // all interrupts masked
  for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    ioredtbl[i].set_even_word (0x00010000);
    ioredtbl[i].set_odd_word  (0x00000000);
  }
  irr = 0;
}

void
bx_ioapic_c::reset (unsigned type)
{
}

void
bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
{
  BX_DEBUG( ("I/O APIC read_aligned addr=%08x, len=%d", address, len));
  BX_ASSERT (len == 4);
  address &= 0xff;
  if (address == 0x00) {
    // select register
    *data = ioregsel;
    return;
  } else if (address != 0x10) {
      BX_PANIC(("IOAPIC: read from unsupported address"));
  }
  // only reached when reading data register
  switch (ioregsel) {
  case 0x00:  // APIC ID
    *data = ((id & 0xf) << 24);
    return;
  case 0x01:  // version
    *data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16)
            | (BX_IOAPIC_VERSION_ID & 0x0f);
    return;
  case 0x02:
    BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
    *data = 0;
    return;
  default:
    int index = (ioregsel - 0x10) >> 1;
    if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
      bx_io_redirect_entry_t *entry = ioredtbl + index;
      *data = (ioregsel&1) ? entry->get_odd_word() : entry->get_even_word ();
      return;
    }
    BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void
bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
{
  BX_DEBUG(("IOAPIC: write addr=%08x, data=%08x, len=%d", address, *value, len));
  address &= 0xff;
  if (address == 0x00)  {
    ioregsel = *value;
    return;
  } else if (address != 0x10) {
    BX_PANIC(("IOAPIC: write to unsupported address"));
  }
  // only reached when writing data register
  switch (ioregsel) {
    case 0x00: // set APIC ID
      {
	Bit8u newid = (*value >> 24) & 0xf;
	BX_INFO(("IOAPIC: setting id to 0x%x", newid));
	set_id (newid);
	return;
      }
    case 0x01: // version
    case 0x02: // arbitration id
      BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
      return;
    default:
      int index = (ioregsel - 0x10) >> 1;
      if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
	bx_io_redirect_entry_t *entry = ioredtbl + index;
	if (ioregsel&1)
	  entry->set_odd_word (*value);
	else
	  entry->set_even_word (*value);
	char buf[1024];
	entry->sprintf_self (buf);
	BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
	service_ioapic ();
	return;
      }
      BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::trigger_irq (unsigned vector, unsigned from)
{
  BX_DEBUG(("IOAPIC: received interrupt %d", vector));
  if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) {
    Bit32u bit = 1<<vector;
    if ((irr & bit) == 0) {
      irr |= bit;
      service_ioapic ();
    }
  } else BX_PANIC(("IOAPIC: vector %d out of range", vector));
}

void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from)
{
  BX_DEBUG(("IOAPIC: interrupt %d went away", num));
}

void bx_ioapic_c::service_ioapic ()
{
  // look in IRR and deliver any interrupts that are not masked.
  BX_DEBUG(("IOAPIC: servicing"));
  for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
    if (irr & (1<<bit)) {
      bx_io_redirect_entry_t *entry = ioredtbl + bit;
      if (!entry->masked) {
	// clear irr bit and deliver
	Boolean done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
	if (done) irr &= ~(1<<bit);
      }
    }
  }
}
<|endoftext|>