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

/**
 * @file
 *   This file implements the web server of border router
 */

#define OTBR_LOG_TAG "WEB"

#include "web/web-service/web_server.hpp"

#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#undef BOOST_NO_CXX11_SCOPED_ENUMS

#include <server_http.hpp>

#include "common/code_utils.hpp"
#include "common/logging.hpp"

#define OT_ADD_PREFIX_PATH "^/add_prefix"
#define OT_AVAILABLE_NETWORK_PATH "^/available_network$"
#define OT_DELETE_PREFIX_PATH "^/delete_prefix"
#define OT_FORM_NETWORK_PATH "^/form_network$"
#define OT_GET_NETWORK_PATH "^/get_properties$"
#define OT_JOIN_NETWORK_PATH "^/join_network$"
#define OT_GET_QRCODE_PATH "^/get_qrcode$"
#define OT_SET_NETWORK_PATH "^/settings$"
#define OT_COMMISSIONER_START_PATH "^/commission$"
#define OT_REQUEST_METHOD_GET "GET"
#define OT_REQUEST_METHOD_POST "POST"
#define OT_RESPONSE_SUCCESS_STATUS "HTTP/1.1 200 OK\r\n"
#define OT_RESPONSE_HEADER_LENGTH "Content-Length: "
#define OT_RESPONSE_HEADER_CSS_TYPE "\r\nContent-Type: text/css"
#define OT_RESPONSE_HEADER_TYPE "Content-Type: application/json\r\n charset=utf-8"
#define OT_RESPONSE_PLACEHOLD "\r\n\r\n"
#define OT_RESPONSE_FAILURE_STATUS "HTTP/1.1 400 Bad Request\r\n"
#define OT_BUFFER_SIZE 1024

namespace otbr {
namespace Web {

static void EscapeHtml(std::string &content)
{
    std::string output;

    output.reserve(content.size());
    for (char c : content)
    {
        switch (c)
        {
        case '&':
            output.append("&");
            break;
        case '<':
            output.append("<");
            break;
        case '>':
            output.append(">");
            break;
        case '"':
            output.append(""");
            break;
        case '\'':
            output.append("'");
            break;
        default:
            output.push_back(c);
            break;
        }
    }

    output.swap(content);
}

WebServer::WebServer(void)
    : mServer(new HttpServer())
{
}

WebServer::~WebServer(void)
{
    delete mServer;
}

void WebServer::Init()
{
    std::string networkName, extPanId;

    if (mWpanService.GetWpanServiceStatus(networkName, extPanId) > 0)
    {
        return;
    }
}

void WebServer::StartWebServer(const char *aIfName, const char *aListenAddr, uint16_t aPort)
{
    if (aListenAddr != nullptr)
    {
        mServer->config.address = aListenAddr;
    }
    mServer->config.port = aPort;
    mWpanService.SetInterfaceName(aIfName);
    Init();
    ResponseGetQRCode();
    ResponseJoinNetwork();
    ResponseFormNetwork();
    ResponseAddOnMeshPrefix();
    ResponseDeleteOnMeshPrefix();
    ResponseGetStatus();
    ResponseGetAvailableNetwork();
    ResponseCommission();
    DefaultHttpResponse();

    try
    {
        mServer->start();
    } catch (const std::exception &e)
    {
        otbrLogCrit("failed to start web server: %s", e.what());
        abort();
    }
}

void WebServer::StopWebServer(void)
{
    try
    {
        mServer->stop();
    } catch (const std::exception &e)
    {
        otbrLogCrit("failed to stop web server: %s", e.what());
    }
}

void WebServer::HandleHttpRequest(const char *aUrl, const char *aMethod, HttpRequestCallback aCallback)
{
    mServer->resource[aUrl][aMethod] = [aCallback, this](std::shared_ptr<HttpServer::Response> response,
                                                         std::shared_ptr<HttpServer::Request>  request) {
        try
        {
            std::string httpResponse;
            if (aCallback != nullptr)
            {
                httpResponse = aCallback(request->content.string(), this);
            }

            *response << OT_RESPONSE_SUCCESS_STATUS << OT_RESPONSE_HEADER_LENGTH << httpResponse.length()
                      << OT_RESPONSE_PLACEHOLD << httpResponse;
        } catch (std::exception &e)
        {
            std::string content = e.what();
            EscapeHtml(content);
            *response << OT_RESPONSE_FAILURE_STATUS << OT_RESPONSE_HEADER_LENGTH << strlen(e.what())
                      << OT_RESPONSE_PLACEHOLD << content;
        }
    };
}

void DefaultResourceSend(const HttpServer &                           aServer,
                         const std::shared_ptr<HttpServer::Response> &aResponse,
                         const std::shared_ptr<std::ifstream> &       aIfStream)
{
    static std::vector<char> buffer(OT_BUFFER_SIZE); // Safe when server is running on one thread

    std::streamsize readLength;

    if ((readLength = aIfStream->read(&buffer[0], buffer.size()).gcount()) > 0)
    {
        aResponse->write(&buffer[0], readLength);
        if (readLength == static_cast<std::streamsize>(buffer.size()))
        {
            aServer.send(aResponse, [&aServer, aResponse, aIfStream](const boost::system::error_code &ec) {
                if (!ec)
                {
                    DefaultResourceSend(aServer, aResponse, aIfStream);
                }
                else
                {
                    std::cerr << "Connection interrupted" << std::endl;
                }
            });
        }
    }
}

void WebServer::DefaultHttpResponse(void)
{
    mServer->default_resource[OT_REQUEST_METHOD_GET] = [this](std::shared_ptr<HttpServer::Response> response,
                                                              std::shared_ptr<HttpServer::Request>  request) {
        try
        {
            auto webRootPath = boost::filesystem::canonical(WEB_FILE_PATH);
            auto path        = boost::filesystem::canonical(webRootPath / request->path);
            // Check if path is within webRootPath
            if (std::distance(webRootPath.begin(), webRootPath.end()) > std::distance(path.begin(), path.end()) ||
                !std::equal(webRootPath.begin(), webRootPath.end(), path.begin()))
            {
                throw std::invalid_argument("path must be within root path");
            }
            if (boost::filesystem::is_directory(path))
            {
                path /= "index.html";
            }
            if (!(boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path)))
            {
                throw std::invalid_argument("file does not exist");
            }

            std::string cacheControl, etag;

            auto ifs = std::make_shared<std::ifstream>();
            ifs->open(path.string(), std::ifstream::in | std::ios::binary | std::ios::ate);
            std::string extension = boost::filesystem::extension(path.string());
            std::string style     = "";
            if (extension == ".css")
            {
                style = OT_RESPONSE_HEADER_CSS_TYPE;
            }

            if (*ifs)
            {
                auto length = ifs->tellg();
                ifs->seekg(0, std::ios::beg);

                *response << OT_RESPONSE_SUCCESS_STATUS << cacheControl << etag << OT_RESPONSE_HEADER_LENGTH << length
                          << style << OT_RESPONSE_PLACEHOLD;

                DefaultResourceSend(*mServer, response, ifs);
            }
            else
            {
                throw std::invalid_argument("could not read file");
            }

        } catch (const std::exception &e)
        {
            std::string content = "Could not open path `" + request->path + "`: " + e.what();
            EscapeHtml(content);
            *response << OT_RESPONSE_FAILURE_STATUS << OT_RESPONSE_HEADER_LENGTH << content.length()
                      << OT_RESPONSE_PLACEHOLD << content;
        }
    };
}

std::string WebServer::HandleJoinNetworkRequest(const std::string &aJoinRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleJoinNetworkRequest(aJoinRequest);
}

std::string WebServer::HandleGetQRCodeRequest(const std::string &aGetQRCodeRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetQRCodeRequest(aGetQRCodeRequest);
}

std::string WebServer::HandleFormNetworkRequest(const std::string &aFormRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleFormNetworkRequest(aFormRequest);
}

std::string WebServer::HandleAddPrefixRequest(const std::string &aAddPrefixRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleAddPrefixRequest(aAddPrefixRequest);
}

std::string WebServer::HandleDeletePrefixRequest(const std::string &aDeletePrefixRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleDeletePrefixRequest(aDeletePrefixRequest);
}

std::string WebServer::HandleGetStatusRequest(const std::string &aGetStatusRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetStatusRequest(aGetStatusRequest);
}

std::string WebServer::HandleGetAvailableNetworkResponse(const std::string &aGetAvailableNetworkRequest,
                                                         void *             aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetAvailableNetworkResponse(aGetAvailableNetworkRequest);
}

std::string WebServer::HandleCommission(const std::string &aCommissionRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleCommission(aCommissionRequest);
}

void WebServer::ResponseJoinNetwork(void)
{
    HandleHttpRequest(OT_JOIN_NETWORK_PATH, OT_REQUEST_METHOD_POST, HandleJoinNetworkRequest);
}

void WebServer::ResponseGetQRCode(void)
{
    HandleHttpRequest(OT_GET_QRCODE_PATH, OT_REQUEST_METHOD_GET, HandleGetQRCodeRequest);
}

void WebServer::ResponseFormNetwork(void)
{
    HandleHttpRequest(OT_FORM_NETWORK_PATH, OT_REQUEST_METHOD_POST, HandleFormNetworkRequest);
}

void WebServer::ResponseAddOnMeshPrefix(void)
{
    HandleHttpRequest(OT_ADD_PREFIX_PATH, OT_REQUEST_METHOD_POST, HandleAddPrefixRequest);
}

void WebServer::ResponseDeleteOnMeshPrefix(void)
{
    HandleHttpRequest(OT_DELETE_PREFIX_PATH, OT_REQUEST_METHOD_POST, HandleDeletePrefixRequest);
}

void WebServer::ResponseGetStatus(void)
{
    HandleHttpRequest(OT_GET_NETWORK_PATH, OT_REQUEST_METHOD_GET, HandleGetStatusRequest);
}

void WebServer::ResponseGetAvailableNetwork(void)
{
    HandleHttpRequest(OT_AVAILABLE_NETWORK_PATH, OT_REQUEST_METHOD_GET, HandleGetAvailableNetworkResponse);
}

void WebServer::ResponseCommission(void)
{
    HandleHttpRequest(OT_COMMISSIONER_START_PATH, OT_REQUEST_METHOD_POST, HandleCommission);
}

std::string WebServer::HandleJoinNetworkRequest(const std::string &aJoinRequest)
{
    return mWpanService.HandleJoinNetworkRequest(aJoinRequest);
}

std::string WebServer::HandleGetQRCodeRequest(const std::string &aGetQRCodeRequest)
{
    OTBR_UNUSED_VARIABLE(aGetQRCodeRequest);
    return mWpanService.HandleGetQRCodeRequest();
}

std::string WebServer::HandleFormNetworkRequest(const std::string &aFormRequest)
{
    return mWpanService.HandleFormNetworkRequest(aFormRequest);
}

std::string WebServer::HandleAddPrefixRequest(const std::string &aAddPrefixRequest)
{
    return mWpanService.HandleAddPrefixRequest(aAddPrefixRequest);
}

std::string WebServer::HandleDeletePrefixRequest(const std::string &aDeletePrefixRequest)
{
    return mWpanService.HandleDeletePrefixRequest(aDeletePrefixRequest);
}

std::string WebServer::HandleGetStatusRequest(const std::string &aGetStatusRequest)
{
    OTBR_UNUSED_VARIABLE(aGetStatusRequest);
    return mWpanService.HandleStatusRequest();
}

std::string WebServer::HandleGetAvailableNetworkResponse(const std::string &aGetAvailableNetworkRequest)
{
    OTBR_UNUSED_VARIABLE(aGetAvailableNetworkRequest);
    return mWpanService.HandleAvailableNetworkRequest();
}

std::string WebServer::HandleCommission(const std::string &aCommissionRequest)
{
    return mWpanService.HandleCommission(aCommissionRequest);
}

} // namespace Web
} // namespace otbr
<commit_msg>[web] set text/html Content-Type for html files (#1261)<commit_after>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements the web server of border router
 */

#define OTBR_LOG_TAG "WEB"

#include "web/web-service/web_server.hpp"

#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#undef BOOST_NO_CXX11_SCOPED_ENUMS

#include <server_http.hpp>

#include "common/code_utils.hpp"
#include "common/logging.hpp"

#define OT_ADD_PREFIX_PATH "^/add_prefix"
#define OT_AVAILABLE_NETWORK_PATH "^/available_network$"
#define OT_DELETE_PREFIX_PATH "^/delete_prefix"
#define OT_FORM_NETWORK_PATH "^/form_network$"
#define OT_GET_NETWORK_PATH "^/get_properties$"
#define OT_JOIN_NETWORK_PATH "^/join_network$"
#define OT_GET_QRCODE_PATH "^/get_qrcode$"
#define OT_SET_NETWORK_PATH "^/settings$"
#define OT_COMMISSIONER_START_PATH "^/commission$"
#define OT_REQUEST_METHOD_GET "GET"
#define OT_REQUEST_METHOD_POST "POST"
#define OT_RESPONSE_SUCCESS_STATUS "HTTP/1.1 200 OK\r\n"
#define OT_RESPONSE_HEADER_LENGTH "Content-Length: "
#define OT_RESPONSE_HEADER_CSS_TYPE "\r\nContent-Type: text/css"
#define OT_RESPONSE_HEADER_TEXT_HTML_TYPE "\r\nContent-Type: text/html; charset=utf-8"
#define OT_RESPONSE_HEADER_TYPE "Content-Type: application/json\r\n charset=utf-8"
#define OT_RESPONSE_PLACEHOLD "\r\n\r\n"
#define OT_RESPONSE_FAILURE_STATUS "HTTP/1.1 400 Bad Request\r\n"
#define OT_BUFFER_SIZE 1024

namespace otbr {
namespace Web {

static void EscapeHtml(std::string &content)
{
    std::string output;

    output.reserve(content.size());
    for (char c : content)
    {
        switch (c)
        {
        case '&':
            output.append("&");
            break;
        case '<':
            output.append("<");
            break;
        case '>':
            output.append(">");
            break;
        case '"':
            output.append(""");
            break;
        case '\'':
            output.append("'");
            break;
        default:
            output.push_back(c);
            break;
        }
    }

    output.swap(content);
}

WebServer::WebServer(void)
    : mServer(new HttpServer())
{
}

WebServer::~WebServer(void)
{
    delete mServer;
}

void WebServer::Init()
{
    std::string networkName, extPanId;

    if (mWpanService.GetWpanServiceStatus(networkName, extPanId) > 0)
    {
        return;
    }
}

void WebServer::StartWebServer(const char *aIfName, const char *aListenAddr, uint16_t aPort)
{
    if (aListenAddr != nullptr)
    {
        mServer->config.address = aListenAddr;
    }
    mServer->config.port = aPort;
    mWpanService.SetInterfaceName(aIfName);
    Init();
    ResponseGetQRCode();
    ResponseJoinNetwork();
    ResponseFormNetwork();
    ResponseAddOnMeshPrefix();
    ResponseDeleteOnMeshPrefix();
    ResponseGetStatus();
    ResponseGetAvailableNetwork();
    ResponseCommission();
    DefaultHttpResponse();

    try
    {
        mServer->start();
    } catch (const std::exception &e)
    {
        otbrLogCrit("failed to start web server: %s", e.what());
        abort();
    }
}

void WebServer::StopWebServer(void)
{
    try
    {
        mServer->stop();
    } catch (const std::exception &e)
    {
        otbrLogCrit("failed to stop web server: %s", e.what());
    }
}

void WebServer::HandleHttpRequest(const char *aUrl, const char *aMethod, HttpRequestCallback aCallback)
{
    mServer->resource[aUrl][aMethod] = [aCallback, this](std::shared_ptr<HttpServer::Response> response,
                                                         std::shared_ptr<HttpServer::Request>  request) {
        try
        {
            std::string httpResponse;
            if (aCallback != nullptr)
            {
                httpResponse = aCallback(request->content.string(), this);
            }

            *response << OT_RESPONSE_SUCCESS_STATUS << OT_RESPONSE_HEADER_LENGTH << httpResponse.length()
                      << OT_RESPONSE_PLACEHOLD << httpResponse;
        } catch (std::exception &e)
        {
            std::string content = e.what();
            EscapeHtml(content);
            *response << OT_RESPONSE_FAILURE_STATUS << OT_RESPONSE_HEADER_LENGTH << strlen(e.what())
                      << OT_RESPONSE_PLACEHOLD << content;
        }
    };
}

void DefaultResourceSend(const HttpServer &                           aServer,
                         const std::shared_ptr<HttpServer::Response> &aResponse,
                         const std::shared_ptr<std::ifstream> &       aIfStream)
{
    static std::vector<char> buffer(OT_BUFFER_SIZE); // Safe when server is running on one thread

    std::streamsize readLength;

    if ((readLength = aIfStream->read(&buffer[0], buffer.size()).gcount()) > 0)
    {
        aResponse->write(&buffer[0], readLength);
        if (readLength == static_cast<std::streamsize>(buffer.size()))
        {
            aServer.send(aResponse, [&aServer, aResponse, aIfStream](const boost::system::error_code &ec) {
                if (!ec)
                {
                    DefaultResourceSend(aServer, aResponse, aIfStream);
                }
                else
                {
                    std::cerr << "Connection interrupted" << std::endl;
                }
            });
        }
    }
}

void WebServer::DefaultHttpResponse(void)
{
    mServer->default_resource[OT_REQUEST_METHOD_GET] = [this](std::shared_ptr<HttpServer::Response> response,
                                                              std::shared_ptr<HttpServer::Request>  request) {
        try
        {
            auto webRootPath = boost::filesystem::canonical(WEB_FILE_PATH);
            auto path        = boost::filesystem::canonical(webRootPath / request->path);

            // Check if path is within webRootPath
            if (std::distance(webRootPath.begin(), webRootPath.end()) > std::distance(path.begin(), path.end()) ||
                !std::equal(webRootPath.begin(), webRootPath.end(), path.begin()))
            {
                throw std::invalid_argument("path must be within root path");
            }
            if (boost::filesystem::is_directory(path))
            {
                path /= "index.html";
            }
            if (!(boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path)))
            {
                throw std::invalid_argument("file does not exist");
            }

            std::string cacheControl, etag;

            auto ifs = std::make_shared<std::ifstream>();
            ifs->open(path.string(), std::ifstream::in | std::ios::binary | std::ios::ate);
            std::string extension = boost::filesystem::extension(path.string());
            std::string header    = "";
            if (extension == ".css")
            {
                header = OT_RESPONSE_HEADER_CSS_TYPE;
            }
            else if (extension == ".html")
            {
                header = OT_RESPONSE_HEADER_TEXT_HTML_TYPE;
            }

            if (*ifs)
            {
                auto length = ifs->tellg();
                ifs->seekg(0, std::ios::beg);

                *response << OT_RESPONSE_SUCCESS_STATUS << cacheControl << etag << OT_RESPONSE_HEADER_LENGTH << length
                          << header << OT_RESPONSE_PLACEHOLD;

                DefaultResourceSend(*mServer, response, ifs);
            }
            else
            {
                throw std::invalid_argument("could not read file");
            }

        } catch (const std::exception &e)
        {
            std::string content = "Could not open path `" + request->path + "`: " + e.what();
            EscapeHtml(content);
            *response << OT_RESPONSE_FAILURE_STATUS << OT_RESPONSE_HEADER_LENGTH << content.length()
                      << OT_RESPONSE_PLACEHOLD << content;
        }
    };
}

std::string WebServer::HandleJoinNetworkRequest(const std::string &aJoinRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleJoinNetworkRequest(aJoinRequest);
}

std::string WebServer::HandleGetQRCodeRequest(const std::string &aGetQRCodeRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetQRCodeRequest(aGetQRCodeRequest);
}

std::string WebServer::HandleFormNetworkRequest(const std::string &aFormRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleFormNetworkRequest(aFormRequest);
}

std::string WebServer::HandleAddPrefixRequest(const std::string &aAddPrefixRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleAddPrefixRequest(aAddPrefixRequest);
}

std::string WebServer::HandleDeletePrefixRequest(const std::string &aDeletePrefixRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleDeletePrefixRequest(aDeletePrefixRequest);
}

std::string WebServer::HandleGetStatusRequest(const std::string &aGetStatusRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetStatusRequest(aGetStatusRequest);
}

std::string WebServer::HandleGetAvailableNetworkResponse(const std::string &aGetAvailableNetworkRequest,
                                                         void *             aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleGetAvailableNetworkResponse(aGetAvailableNetworkRequest);
}

std::string WebServer::HandleCommission(const std::string &aCommissionRequest, void *aUserData)
{
    WebServer *webServer = static_cast<WebServer *>(aUserData);

    return webServer->HandleCommission(aCommissionRequest);
}

void WebServer::ResponseJoinNetwork(void)
{
    HandleHttpRequest(OT_JOIN_NETWORK_PATH, OT_REQUEST_METHOD_POST, HandleJoinNetworkRequest);
}

void WebServer::ResponseGetQRCode(void)
{
    HandleHttpRequest(OT_GET_QRCODE_PATH, OT_REQUEST_METHOD_GET, HandleGetQRCodeRequest);
}

void WebServer::ResponseFormNetwork(void)
{
    HandleHttpRequest(OT_FORM_NETWORK_PATH, OT_REQUEST_METHOD_POST, HandleFormNetworkRequest);
}

void WebServer::ResponseAddOnMeshPrefix(void)
{
    HandleHttpRequest(OT_ADD_PREFIX_PATH, OT_REQUEST_METHOD_POST, HandleAddPrefixRequest);
}

void WebServer::ResponseDeleteOnMeshPrefix(void)
{
    HandleHttpRequest(OT_DELETE_PREFIX_PATH, OT_REQUEST_METHOD_POST, HandleDeletePrefixRequest);
}

void WebServer::ResponseGetStatus(void)
{
    HandleHttpRequest(OT_GET_NETWORK_PATH, OT_REQUEST_METHOD_GET, HandleGetStatusRequest);
}

void WebServer::ResponseGetAvailableNetwork(void)
{
    HandleHttpRequest(OT_AVAILABLE_NETWORK_PATH, OT_REQUEST_METHOD_GET, HandleGetAvailableNetworkResponse);
}

void WebServer::ResponseCommission(void)
{
    HandleHttpRequest(OT_COMMISSIONER_START_PATH, OT_REQUEST_METHOD_POST, HandleCommission);
}

std::string WebServer::HandleJoinNetworkRequest(const std::string &aJoinRequest)
{
    return mWpanService.HandleJoinNetworkRequest(aJoinRequest);
}

std::string WebServer::HandleGetQRCodeRequest(const std::string &aGetQRCodeRequest)
{
    OTBR_UNUSED_VARIABLE(aGetQRCodeRequest);
    return mWpanService.HandleGetQRCodeRequest();
}

std::string WebServer::HandleFormNetworkRequest(const std::string &aFormRequest)
{
    return mWpanService.HandleFormNetworkRequest(aFormRequest);
}

std::string WebServer::HandleAddPrefixRequest(const std::string &aAddPrefixRequest)
{
    return mWpanService.HandleAddPrefixRequest(aAddPrefixRequest);
}

std::string WebServer::HandleDeletePrefixRequest(const std::string &aDeletePrefixRequest)
{
    return mWpanService.HandleDeletePrefixRequest(aDeletePrefixRequest);
}

std::string WebServer::HandleGetStatusRequest(const std::string &aGetStatusRequest)
{
    OTBR_UNUSED_VARIABLE(aGetStatusRequest);
    return mWpanService.HandleStatusRequest();
}

std::string WebServer::HandleGetAvailableNetworkResponse(const std::string &aGetAvailableNetworkRequest)
{
    OTBR_UNUSED_VARIABLE(aGetAvailableNetworkRequest);
    return mWpanService.HandleAvailableNetworkRequest();
}

std::string WebServer::HandleCommission(const std::string &aCommissionRequest)
{
    return mWpanService.HandleCommission(aCommissionRequest);
}

} // namespace Web
} // namespace otbr
<|endoftext|>


<commit_before>// This file is part of SWGANH which is released under the MIT license.
// See file LICENSE or go to http://swganh.com/LICENSE

#ifndef WIN32
#include <Python.h>
#endif

#include "swganh/app/swganh_app.h"

#include <algorithm>
#include <exception>
#include <fstream>
#include <iostream>

#ifdef WIN32
#include <regex>
#else
#include <boost/regex.hpp>
#endif

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>

#include "swganh/logger.h"
#include "swganh/database/database_manager_interface.h"
#include "swganh/event_dispatcher.h"
#include "swganh/plugin/plugin_manager.h"
#include "swganh/service/datastore.h"
#include "swganh/service/service_manager.h"

#include "swganh/app/swganh_kernel.h"

#include "swganh/combat/combat_service_interface.h"
#include "swganh/chat/chat_service_interface.h"
#include "swganh/character/character_service_interface.h"
#include "swganh/login/login_service_interface.h"
#include "swganh/connection/connection_service_interface.h"
#include "swganh/simulation/simulation_service_interface.h"
#include "swganh/scripting/utilities.h"

#include "version.h"

using namespace boost::asio;
using namespace boost::program_options;
using namespace std;
using namespace swganh;
using namespace swganh::app;
using namespace swganh::chat;
using namespace swganh::login;
using namespace swganh::character;
using namespace swganh::connection;
using namespace swganh::simulation;
using namespace swganh::galaxy;

using swganh::plugin::RegistrationMap;

#ifdef WIN32
using std::regex;
using std::smatch;
using std::regex_match;
#else
using boost::regex;
using boost::smatch;
using boost::regex_match;
#endif

options_description AppConfig::BuildConfigDescription() {
    options_description desc;

    desc.add_options()
        ("help,h", "Display help message and config options")

		("server_mode", boost::program_options::value<std::string>(&server_mode)->default_value("all"),
			"Specifies the service configuration mode to run the server in.")

        ("plugin,p", boost::program_options::value<std::vector<std::string>>(&plugins),
            "Only used when single_server_mode is disabled, loads a module of the specified name")
        ("plugin_directory", value<string>(&plugin_directory)->default_value("plugins/"),
            "Directory containing the application plugins")

        ("script_directory", value<string>(&script_directory)->default_value("scripts"),
            "Directory containing the application scripts")

        ("tre_config", boost::program_options::value<std::string>(&tre_config),
            "File containing the tre configuration (live.cfg)")

        ("galaxy_name", boost::program_options::value<std::string>(&galaxy_name),
            "Name of the galaxy (cluster) to this process should run")

        ("resource_cache_size", boost::program_options::value<uint32_t>(&resource_cache_size),
            "Available cache size for the resource manager (in Megabytes)")

        ("db.galaxy_manager.host", boost::program_options::value<std::string>(&galaxy_manager_db.host),
            "Host address for the galaxy_manager datastore")
        ("db.galaxy_manager.schema", boost::program_options::value<std::string>(&galaxy_manager_db.schema),
            "Schema name for the galaxy_manager datastore")
        ("db.galaxy_manager.username", boost::program_options::value<std::string>(&galaxy_manager_db.username),
            "Username for authentication with the galaxy_manager datastore")
        ("db.galaxy_manager.password", boost::program_options::value<std::string>(&galaxy_manager_db.password),
            "Password for authentication with the galaxy_manager datastore")

        ("db.galaxy.host", boost::program_options::value<std::string>(&galaxy_db.host),
            "Host address for the galaxy datastore")
        ("db.galaxy.schema", boost::program_options::value<std::string>(&galaxy_db.schema),
            "Schema name for the galaxy datastore")
        ("db.galaxy.username", boost::program_options::value<std::string>(&galaxy_db.username),
            "Username for authentication with the galaxy datastore")
        ("db.galaxy.password", boost::program_options::value<std::string>(&galaxy_db.password),
            "Password for authentication with the galaxy datastore")

        ("service.login.udp_port",
            boost::program_options::value<uint16_t>(&login_config.listen_port),
            "The port the login service will listen for incoming client connections on")
        ("service.login.address",
            boost::program_options::value<string>(&login_config.listen_address),
            "The public address the login service will listen for incoming client connections on")
        ("service.login.status_check_duration_secs",
            boost::program_options::value<int>(&login_config.galaxy_status_check_duration_secs),
            "The amount of time between checks for updated galaxy status")
        ("service.login.login_error_timeout_secs",
            boost::program_options::value<int>(&login_config.login_error_timeout_secs)->default_value(5),
            "The number of seconds to wait before disconnecting a client after failed login attempt")
        ("service.login.auto_registration",
            boost::program_options::value<bool>(&login_config.login_auto_registration)->default_value(false),
            "Auto Registration flag")

        ("service.connection.ping_port", boost::program_options::value<uint16_t>(&connection_config.ping_port),
            "The port the connection service will listen for incoming client ping requests on")
        ("service.connection.udp_port", boost::program_options::value<uint16_t>(&connection_config.listen_port),
            "The port the connection service will listen for incoming client connections on")
        ("service.connection.address", boost::program_options::value<string>(&connection_config.listen_address),
            "The public address the connection service will listen for incoming client connections on")
    ;

    return desc;
}

SwganhApp::SwganhApp(int argc, char* argv[])
    : io_service_()
    , io_work_(new boost::asio::io_service::work(io_service_))
{
    kernel_ = make_shared<SwganhKernel>(io_service_);
    running_ = false;
    initialized_ = false;

    Initialize(argc, argv);
    Start();
}

SwganhApp::~SwganhApp()
{
    Stop();
	// Shutdown Event Dispatcher
	kernel_->GetEventDispatcher()->Shutdown();

    kernel_.reset();
    io_work_.reset();

    // join the threadpool threads until each one has exited.
    for_each(io_threads_.begin(), io_threads_.end(), std::mem_fn(&boost::thread::join));
}

void SwganhApp::Initialize(int argc, char* argv[]) {
    // Init Logging
    SetupLogging_();

    // Load the configuration
    LoadAppConfig_(argc, argv);

    auto app_config = kernel_->GetAppConfig();

    // Initialize kernel resources
    kernel_->GetDatabaseManager()->registerStorageType(
        "galaxy_manager",
        app_config.galaxy_manager_db.schema,
        app_config.galaxy_manager_db.host,
        app_config.galaxy_manager_db.username,
        app_config.galaxy_manager_db.password);

    kernel_->GetDatabaseManager()->registerStorageType(
        "galaxy",
        app_config.galaxy_db.schema,
        app_config.galaxy_db.host,
        app_config.galaxy_db.username,
        app_config.galaxy_db.password);

    CleanupServices_();

    // append command dir
    std::string py_path = "import sys; sys.path.append('.'); sys.path.append('" + app_config.script_directory + "');";
    {
        swganh::scripting::ScopedGilLock lock;
        PyRun_SimpleString(py_path.c_str());
    }

    // Load the plugin configuration.
    LoadPlugins_(app_config.plugins);

    // Load core services
    LoadCoreServices_();

    initialized_ = true;
}

void SwganhApp::Start() {
    if (!initialized_) {
        throw std::runtime_error("Called application Start before Initialize");
    }

    running_ = true;

    // Start up a threadpool for running io_service based tasks/active objects
    // The increment starts at 2 because the main thread of execution already counts
    // as thread in use as does the console thread.
    for (uint32_t i = 1; i < boost::thread::hardware_concurrency(); ++i) {
        boost::thread t([this] () {
            io_service_.run();
        });

#ifdef _WIN32
        SetPriorityClass(t.native_handle(), REALTIME_PRIORITY_CLASS);
#endif

        io_threads_.push_back(move(t));
    }

    kernel_->GetServiceManager()->Start();
}

void SwganhApp::Stop() {
    running_ = false;
}

bool SwganhApp::IsRunning() {
    return running_;
}

SwganhKernel* SwganhApp::GetAppKernel() const {
    return kernel_.get();
}

void SwganhApp::StartInteractiveConsole()
{
    swganh::scripting::ScopedGilLock lock;
    swganh::Logger::getInstance().DisableConsoleLogging();

#ifdef WIN32
    std::system("cls");
#else
    if (std::system("clear") != 0)
    {
        LOG(::error) << "Error clearing screen, ignoring console mode";
        return;
    }
#endif

    std::cout << "swgpy console " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH << std::endl;

    boost::python::object main = boost::python::object (boost::python::handle<>(boost::python::borrowed(
        PyImport_AddModule("__main__")
    )));
    auto global_dict = main.attr("__dict__");
    global_dict["kernel"] = boost::python::ptr(GetAppKernel());

    PyRun_InteractiveLoop(stdin, "<stdin>");

    swganh::Logger::getInstance().EnableConsoleLogging();
}

void SwganhApp::LoadAppConfig_(int argc, char* argv[]) {
    auto config_description = kernel_->GetAppConfig().BuildConfigDescription();

    variables_map vm;
    store(parse_command_line(argc, argv, config_description), vm);

    ifstream config_file("config/swganh.cfg");

    if (!config_file.is_open()) {
        throw runtime_error("Unable to open the configuration file at: config/swganh.cfg");
    }

    try {
        store(parse_config_file(config_file, config_description, true), vm);
    } catch(...) {
        throw runtime_error("Unable to parse the configuration file at: config/swganh.cfg");
    }

    notify(vm);
    config_file.close();

    if (vm.count("help")) {
        std::cout << config_description << "\n\n";
        exit(0);
    }
}

void SwganhApp::LoadPlugins_(vector<string> plugins) {
    LOG(info) << "Loading plugins...";

    if (!plugins.empty()) {
        auto plugin_manager = kernel_->GetPluginManager();
        auto plugin_directory = kernel_->GetAppConfig().plugin_directory;

        for_each(plugins.begin(), plugins.end(), [plugin_manager, plugin_directory] (const string& plugin) {
			LOG(info) << "Loading plugin " << plugin;
            plugin_manager->LoadPlugin(plugin, plugin_directory);
        });
    }
	LOG(info) << "Finished Loading plugins...";
}

void SwganhApp::CleanupServices_() {

    auto service_directory = kernel_->GetServiceDirectory();

    auto services = service_directory->getServiceSnapshot(service_directory->galaxy());

    if (services.empty()) {
        return;
    }

    LOG(warning) << "Services were not shutdown properly";

    for_each(services.begin(), services.end(), [this, &service_directory] (swganh::service::ServiceDescription& service) {
        service_directory->removeService(service);
    });
}

void SwganhApp::LoadCoreServices_()
{

    auto plugin_manager = kernel_->GetPluginManager();
    auto registration_map = plugin_manager->registration_map();

    regex rx("(?:.*\\:\\:)(.*Service)");
    smatch m;

    for_each(registration_map.begin(), registration_map.end(), [this, &rx, &m] (RegistrationMap::value_type& entry) {
        std::string name = entry.first;

        if (entry.first.length() > 7 && regex_match(name, m, rx)) {
            auto service_name = m[1].str();
			LOG(info) << "Loading Service " << name << "...";
            auto service = kernel_->GetPluginManager()->CreateObject<swganh::service::ServiceInterface>(name);

            kernel_->GetServiceManager()->AddService(service_name, service);
			LOG(info) << "Loaded Service " << name;
        }
    });

    auto app_config = kernel_->GetAppConfig();

	if(strcmp("simulation", app_config.server_mode.c_str()) == 0 || strcmp("all", app_config.server_mode.c_str()) == 0)
	{
		auto simulation_service = kernel_->GetServiceManager()->GetService<SimulationServiceInterface>("SimulationService");
		simulation_service->StartScene("corellia");
	}
}

void SwganhApp::SetupLogging_()
{
    swganh::Logger::getInstance().init("swganh");
}<commit_msg>Update src/swganh/app/swganh_app.cc<commit_after>// This file is part of SWGANH which is released under the MIT license.
// See file LICENSE or go to http://swganh.com/LICENSE

#ifndef WIN32
#include <Python.h>
#endif

#include "swganh/app/swganh_app.h"

#include <algorithm>
#include <exception>
#include <fstream>
#include <iostream>

#ifdef WIN32
#include <regex>
#else
#include <boost/regex.hpp>
#endif

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>

#include "swganh/logger.h"
#include "swganh/database/database_manager_interface.h"
#include "swganh/event_dispatcher.h"
#include "swganh/plugin/plugin_manager.h"
#include "swganh/service/datastore.h"
#include "swganh/service/service_manager.h"

#include "swganh/app/swganh_kernel.h"

#include "swganh/combat/combat_service_interface.h"
#include "swganh/chat/chat_service_interface.h"
#include "swganh/character/character_service_interface.h"
#include "swganh/login/login_service_interface.h"
#include "swganh/connection/connection_service_interface.h"
#include "swganh/simulation/simulation_service_interface.h"
#include "swganh/scripting/utilities.h"

#include "version.h"

using namespace boost::asio;
using namespace boost::program_options;
using namespace std;
using namespace swganh;
using namespace swganh::app;
using namespace swganh::chat;
using namespace swganh::login;
using namespace swganh::character;
using namespace swganh::connection;
using namespace swganh::simulation;
using namespace swganh::galaxy;

using swganh::plugin::RegistrationMap;

#ifdef WIN32
using std::regex;
using std::smatch;
using std::regex_match;
#else
using boost::regex;
using boost::smatch;
using boost::regex_match;
#endif

options_description AppConfig::BuildConfigDescription() {
    options_description desc;

    desc.add_options()
        ("help,h", "Display help message and config options")

		("server_mode", boost::program_options::value<std::string>(&server_mode)->default_value("all"),
			"Specifies the service configuration mode to run the server in.")

        ("plugin,p", boost::program_options::value<std::vector<std::string>>(&plugins),
            "Only used when single_server_mode is disabled, loads a module of the specified name")
        ("plugin_directory", value<string>(&plugin_directory)->default_value("plugins/"),
            "Directory containing the application plugins")

        ("script_directory", value<string>(&script_directory)->default_value("scripts"),
            "Directory containing the application scripts")

        ("tre_config", boost::program_options::value<std::string>(&tre_config),
            "File containing the tre configuration (live.cfg)")

        ("galaxy_name", boost::program_options::value<std::string>(&galaxy_name),
            "Name of the galaxy (cluster) to this process should run")

        ("resource_cache_size", boost::program_options::value<uint32_t>(&resource_cache_size),
            "Available cache size for the resource manager (in Megabytes)")

        ("db.galaxy_manager.host", boost::program_options::value<std::string>(&galaxy_manager_db.host),
            "Host address for the galaxy_manager datastore")
        ("db.galaxy_manager.schema", boost::program_options::value<std::string>(&galaxy_manager_db.schema),
            "Schema name for the galaxy_manager datastore")
        ("db.galaxy_manager.username", boost::program_options::value<std::string>(&galaxy_manager_db.username),
            "Username for authentication with the galaxy_manager datastore")
        ("db.galaxy_manager.password", boost::program_options::value<std::string>(&galaxy_manager_db.password),
            "Password for authentication with the galaxy_manager datastore")

        ("db.galaxy.host", boost::program_options::value<std::string>(&galaxy_db.host),
            "Host address for the galaxy datastore")
        ("db.galaxy.schema", boost::program_options::value<std::string>(&galaxy_db.schema),
            "Schema name for the galaxy datastore")
        ("db.galaxy.username", boost::program_options::value<std::string>(&galaxy_db.username),
            "Username for authentication with the galaxy datastore")
        ("db.galaxy.password", boost::program_options::value<std::string>(&galaxy_db.password),
            "Password for authentication with the galaxy datastore")

        ("service.login.udp_port",
            boost::program_options::value<uint16_t>(&login_config.listen_port),
            "The port the login service will listen for incoming client connections on")
        ("service.login.address",
            boost::program_options::value<string>(&login_config.listen_address),
            "The public address the login service will listen for incoming client connections on")
        ("service.login.status_check_duration_secs",
            boost::program_options::value<int>(&login_config.galaxy_status_check_duration_secs),
            "The amount of time between checks for updated galaxy status")
        ("service.login.login_error_timeout_secs",
            boost::program_options::value<int>(&login_config.login_error_timeout_secs)->default_value(5),
            "The number of seconds to wait before disconnecting a client after failed login attempt")
        ("service.login.auto_registration",
            boost::program_options::value<bool>(&login_config.login_auto_registration)->default_value(false),
            "Auto Registration flag")

        ("service.connection.ping_port", boost::program_options::value<uint16_t>(&connection_config.ping_port),
            "The port the connection service will listen for incoming client ping requests on")
        ("service.connection.udp_port", boost::program_options::value<uint16_t>(&connection_config.listen_port),
            "The port the connection service will listen for incoming client connections on")
        ("service.connection.address", boost::program_options::value<string>(&connection_config.listen_address),
            "The public address the connection service will listen for incoming client connections on")
    ;

    return desc;
}

SwganhApp::SwganhApp(int argc, char* argv[])
    : io_service_()
    , io_work_(new boost::asio::io_service::work(io_service_))
{
    kernel_ = make_shared<SwganhKernel>(io_service_);
    running_ = false;
    initialized_ = false;

    Initialize(argc, argv);
    Start();
}

SwganhApp::~SwganhApp()
{
    Stop();
	// Shutdown Event Dispatcher
	kernel_->GetEventDispatcher()->Shutdown();

    kernel_.reset();
    io_work_.reset();

    // join the threadpool threads until each one has exited.
    for_each(io_threads_.begin(), io_threads_.end(), std::mem_fn(&boost::thread::join));
}

void SwganhApp::Initialize(int argc, char* argv[]) {
    // Init Logging
    SetupLogging_();

    // Load the configuration
    LoadAppConfig_(argc, argv);

    auto app_config = kernel_->GetAppConfig();

    try {

	// Initialize kernel resources
        kernel_->GetDatabaseManager()->registerStorageType(
	    "galaxy_manager",
	    app_config.galaxy_manager_db.schema,
	    app_config.galaxy_manager_db.host,
	    app_config.galaxy_manager_db.username,
	    app_config.galaxy_manager_db.password);

	kernel_->GetDatabaseManager()->registerStorageType(
	    "galaxy",
	    app_config.galaxy_db.schema,
	    app_config.galaxy_db.host,
	    app_config.galaxy_db.username,
	    app_config.galaxy_db.password);

    }
    catch(...)
    {
    	LOG(fatal) << "Database connection errors occurred. Did you forget to populate the db?";
    }

    CleanupServices_();

    // append command dir
    std::string py_path = "import sys; sys.path.append('.'); sys.path.append('" + app_config.script_directory + "');";
    {
        swganh::scripting::ScopedGilLock lock;
        PyRun_SimpleString(py_path.c_str());
    }

    // Load the plugin configuration.
    LoadPlugins_(app_config.plugins);

    // Load core services
    LoadCoreServices_();

    initialized_ = true;
}

void SwganhApp::Start() {
    if (!initialized_) {
        throw std::runtime_error("Called application Start before Initialize");
    }

    running_ = true;

    // Start up a threadpool for running io_service based tasks/active objects
    // The increment starts at 2 because the main thread of execution already counts
    // as thread in use as does the console thread.
    for (uint32_t i = 1; i < boost::thread::hardware_concurrency(); ++i) {
        boost::thread t([this] () {
            io_service_.run();
        });

#ifdef _WIN32
        SetPriorityClass(t.native_handle(), REALTIME_PRIORITY_CLASS);
#endif

        io_threads_.push_back(move(t));
    }

    kernel_->GetServiceManager()->Start();
}

void SwganhApp::Stop() {
    running_ = false;
}

bool SwganhApp::IsRunning() {
    return running_;
}

SwganhKernel* SwganhApp::GetAppKernel() const {
    return kernel_.get();
}

void SwganhApp::StartInteractiveConsole()
{
    swganh::scripting::ScopedGilLock lock;
    swganh::Logger::getInstance().DisableConsoleLogging();

#ifdef WIN32
    std::system("cls");
#else
    if (std::system("clear") != 0)
    {
        LOG(::error) << "Error clearing screen, ignoring console mode";
        return;
    }
#endif

    std::cout << "swgpy console " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH << std::endl;

    boost::python::object main = boost::python::object (boost::python::handle<>(boost::python::borrowed(
        PyImport_AddModule("__main__")
    )));
    auto global_dict = main.attr("__dict__");
    global_dict["kernel"] = boost::python::ptr(GetAppKernel());

    PyRun_InteractiveLoop(stdin, "<stdin>");

    swganh::Logger::getInstance().EnableConsoleLogging();
}

void SwganhApp::LoadAppConfig_(int argc, char* argv[]) {
    auto config_description = kernel_->GetAppConfig().BuildConfigDescription();

    variables_map vm;
    store(parse_command_line(argc, argv, config_description), vm);

    ifstream config_file("config/swganh.cfg");

    if (!config_file.is_open()) {
        throw runtime_error("Unable to open the configuration file at: config/swganh.cfg");
    }

    try {
        store(parse_config_file(config_file, config_description, true), vm);
    } catch(...) {
        throw runtime_error("Unable to parse the configuration file at: config/swganh.cfg");
    }

    notify(vm);
    config_file.close();

    if (vm.count("help")) {
        std::cout << config_description << "\n\n";
        exit(0);
    }
}

void SwganhApp::LoadPlugins_(vector<string> plugins) {
    LOG(info) << "Loading plugins...";

    if (!plugins.empty()) {
        auto plugin_manager = kernel_->GetPluginManager();
        auto plugin_directory = kernel_->GetAppConfig().plugin_directory;

        for_each(plugins.begin(), plugins.end(), [plugin_manager, plugin_directory] (const string& plugin) {
			LOG(info) << "Loading plugin " << plugin;
            plugin_manager->LoadPlugin(plugin, plugin_directory);
        });
    }
	LOG(info) << "Finished Loading plugins...";
}

void SwganhApp::CleanupServices_() {

    auto service_directory = kernel_->GetServiceDirectory();

    auto services = service_directory->getServiceSnapshot(service_directory->galaxy());

    if (services.empty()) {
        return;
    }

    LOG(warning) << "Services were not shutdown properly";

    for_each(services.begin(), services.end(), [this, &service_directory] (swganh::service::ServiceDescription& service) {
        service_directory->removeService(service);
    });
}

void SwganhApp::LoadCoreServices_()
{

    auto plugin_manager = kernel_->GetPluginManager();
    auto registration_map = plugin_manager->registration_map();

    regex rx("(?:.*\\:\\:)(.*Service)");
    smatch m;

    for_each(registration_map.begin(), registration_map.end(), [this, &rx, &m] (RegistrationMap::value_type& entry) {
        std::string name = entry.first;

        if (entry.first.length() > 7 && regex_match(name, m, rx)) {
            auto service_name = m[1].str();
			LOG(info) << "Loading Service " << name << "...";
            auto service = kernel_->GetPluginManager()->CreateObject<swganh::service::ServiceInterface>(name);

            kernel_->GetServiceManager()->AddService(service_name, service);
			LOG(info) << "Loaded Service " << name;
        }
    });

    auto app_config = kernel_->GetAppConfig();

	if(strcmp("simulation", app_config.server_mode.c_str()) == 0 || strcmp("all", app_config.server_mode.c_str()) == 0)
	{
		auto simulation_service = kernel_->GetServiceManager()->GetService<SimulationServiceInterface>("SimulationService");
		simulation_service->StartScene("corellia");
	}
}

void SwganhApp::SetupLogging_()
{
    swganh::Logger::getInstance().init("swganh");
}<|endoftext|>


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

#ifdef USING_QT_UI
#include <QtGui/QImage>
#else
#include "libpng17/png.h"
#endif

#include "png_load.h"
#include "base/logging.h"

// *image_data_ptr should be deleted with free()
// return value of 1 == success.
int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr, bool flip) {
#ifdef USING_QT_UI
	QImage image(file, "PNG");
	if (image.isNull()) {
		ELOG("pngLoad: Error loading image %s", file);
		return 0;
	}

	if (flip)
		image = image.mirrored();
	*pwidth = image.width();
	*pheight = image.height();
	*image_data_ptr = (unsigned char *)malloc(image.byteCount());
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
	image.convertToFormat(QImage::Format_ARGB32);
	uint32_t *src = (uint32_t*) image.bits();
	uint32_t *dest = (uint32_t*) *image_data_ptr;
        // Qt4 does not support RGBA
	for (size_t sz = 0; sz < image.byteCount(); sz+=4, ++src, ++dest) {
		const uint32_t v = *src;
		*dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // ARGB -> RGBA
	}
#else
	image.convertToFormat(QImage::Format_RGBA8888);
	memcpy(image.bits(), *image_data_ptr, image.byteCount());
#endif
#else
	if (flip)
		ELOG("pngLoad: flip flag not supported, image will be loaded upside down");
	png_image png;
	memset(&png, 0, sizeof(png));
	png.version = PNG_IMAGE_VERSION;

	png_image_begin_read_from_file(&png, file);

	if (PNG_IMAGE_FAILED(png))
	{
		ELOG("pngLoad: %s", png.message);
		return 0;
	}
	*pwidth = png.width;
	*pheight = png.height;
	png.format = PNG_FORMAT_RGBA;

	int stride = PNG_IMAGE_ROW_STRIDE(png);
	*image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png));
	png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
#endif

	return 1;
}

int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, int *pheight, unsigned char **image_data_ptr,
	bool flip) {
#ifdef USING_QT_UI
	QImage image;
	if (!image.loadFromData(input_ptr, input_len, "PNG")) {
		ELOG("pngLoad: Error loading image");
		return 0;
	}

	if (flip)
		image = image.mirrored();
	*pwidth = image.width();
	*pheight = image.height();
	*image_data_ptr = (unsigned char *)malloc(image.byteCount());
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
	uint32_t *src = (uint32_t*) image.bits();
	uint32_t *dest = (uint32_t*) *image_data_ptr;
	// Qt4 does not support RGBA
	for (size_t sz = 0; sz < image.byteCount(); sz+=4, ++src, ++dest) {
		const uint32_t v = *src;
		*dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // convert it!
	}
#else
	image.convertToFormat(QImage::Format_RGBA8888);
	memcpy(image.bits(), *image_data_ptr, image.byteCount());
#endif
#else
	if (flip)
		ELOG("pngLoad: flip flag not supported, image will be loaded upside down");
	png_image png;
	memset(&png, 0, sizeof(png));
	png.version = PNG_IMAGE_VERSION;

	png_image_begin_read_from_memory(&png, input_ptr, input_len);

	if (PNG_IMAGE_FAILED(png))
	{
		ELOG("pngLoad: %s", png.message);
		return 0;
	}
	*pwidth = png.width;
	*pheight = png.height;
	png.format = PNG_FORMAT_RGBA;

	int stride = PNG_IMAGE_ROW_STRIDE(png);
	*image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png));
	png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
#endif

	return 1;
}
<commit_msg>Qt: RGBA8888 only in Qt5.2+<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USING_QT_UI
#include <QtGui/QImage>
#else
#include "libpng17/png.h"
#endif

#include "png_load.h"
#include "base/logging.h"

// *image_data_ptr should be deleted with free()
// return value of 1 == success.
int pngLoad(const char *file, int *pwidth, int *pheight, unsigned char **image_data_ptr, bool flip) {
#ifdef USING_QT_UI
	QImage image(file, "PNG");
	if (image.isNull()) {
		ELOG("pngLoad: Error loading image %s", file);
		return 0;
	}

	if (flip)
		image = image.mirrored();
	*pwidth = image.width();
	*pheight = image.height();
	*image_data_ptr = (unsigned char *)malloc(image.byteCount());
#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
	image.convertToFormat(QImage::Format_ARGB32);
	uint32_t *src = (uint32_t*) image.bits();
	uint32_t *dest = (uint32_t*) *image_data_ptr;
        // Qt4 does not support RGBA
	for (size_t sz = 0; sz < image.byteCount(); sz+=4, ++src, ++dest) {
		const uint32_t v = *src;
		*dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // ARGB -> RGBA
	}
#else
	image.convertToFormat(QImage::Format_RGBA8888);
	memcpy(image.bits(), *image_data_ptr, image.byteCount());
#endif
#else
	if (flip)
		ELOG("pngLoad: flip flag not supported, image will be loaded upside down");
	png_image png;
	memset(&png, 0, sizeof(png));
	png.version = PNG_IMAGE_VERSION;

	png_image_begin_read_from_file(&png, file);

	if (PNG_IMAGE_FAILED(png))
	{
		ELOG("pngLoad: %s", png.message);
		return 0;
	}
	*pwidth = png.width;
	*pheight = png.height;
	png.format = PNG_FORMAT_RGBA;

	int stride = PNG_IMAGE_ROW_STRIDE(png);
	*image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png));
	png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
#endif

	return 1;
}

int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, int *pheight, unsigned char **image_data_ptr,
	bool flip) {
#ifdef USING_QT_UI
	QImage image;
	if (!image.loadFromData(input_ptr, input_len, "PNG")) {
		ELOG("pngLoad: Error loading image");
		return 0;
	}

	if (flip)
		image = image.mirrored();
	*pwidth = image.width();
	*pheight = image.height();
	*image_data_ptr = (unsigned char *)malloc(image.byteCount());
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
	uint32_t *src = (uint32_t*) image.bits();
	uint32_t *dest = (uint32_t*) *image_data_ptr;
	// Qt4 does not support RGBA
	for (size_t sz = 0; sz < image.byteCount(); sz+=4, ++src, ++dest) {
		const uint32_t v = *src;
		*dest = (v & 0xFF00FF00) | ((v & 0xFF) << 16) | (( v >> 16 ) & 0xFF); // convert it!
	}
#else
	image.convertToFormat(QImage::Format_RGBA8888);
	memcpy(image.bits(), *image_data_ptr, image.byteCount());
#endif
#else
	if (flip)
		ELOG("pngLoad: flip flag not supported, image will be loaded upside down");
	png_image png;
	memset(&png, 0, sizeof(png));
	png.version = PNG_IMAGE_VERSION;

	png_image_begin_read_from_memory(&png, input_ptr, input_len);

	if (PNG_IMAGE_FAILED(png))
	{
		ELOG("pngLoad: %s", png.message);
		return 0;
	}
	*pwidth = png.width;
	*pheight = png.height;
	png.format = PNG_FORMAT_RGBA;

	int stride = PNG_IMAGE_ROW_STRIDE(png);
	*image_data_ptr = (unsigned char *)malloc(PNG_IMAGE_SIZE(png));
	png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
#endif

	return 1;
}
<|endoftext|>


<commit_before>#include "destructureTupleAssignments.h"
#include "stmt.h"
#include "expr.h"
#include "type.h"
#include "stringutil.h"

void DestructureTupleAssignments::postProcessStmt(Stmt* stmt) {
  ExprStmt* assign_stmt = dynamic_cast<ExprStmt*>(stmt);

  if (!assign_stmt) {
    return;
  }

  AssignOp* assign_expr = dynamic_cast<AssignOp*>(assign_stmt->expr);

  if (!assign_expr) {
    return;
  }

  TupleType* left_type = dynamic_cast<TupleType*>(assign_expr->left->typeInfo()->getType());
  TupleType* right_type = dynamic_cast<TupleType*>(assign_expr->right->typeInfo()->getType());

  if (left_type && right_type) {
    return;
  }

  Tuple* left_tuple = dynamic_cast<Tuple*>(assign_expr->left);
  Tuple* right_tuple = dynamic_cast<Tuple*>(assign_expr->right);

  if (!left_type && !left_tuple && !right_type && !right_tuple) {
    return;
  }

  if (!left_type && !left_tuple) {
    INT_FATAL(stmt, "Tuple to non-tuple assignment should be caught earlier");
  }

  if (!right_type && !right_tuple) {
    INT_FATAL(stmt, "Non-tuple to tuple assignment should be caught earlier");
  }

  int left_n =
    (left_type)
    ? left_type->components.n
    : left_tuple->exprs->length();

  int right_n =
    (right_type)
    ? right_type->components.n
    : right_tuple->exprs->length();

  if (left_n != right_n) {
    INT_FATAL(stmt, "Non-matching tuple assign should be caught earlier");
  }

  if (assign_expr->type != GETS_NORM) {
    INT_FATAL(stmt, "Non-standard tuple assign should be caught earlier");
  }

  for (int i = 1; i <= left_n; i++) {
    TupleSelect* new_left =
      new TupleSelect(assign_expr->left->copy(), new IntLiteral(intstring(i), i));
    TupleSelect* new_right =
      new TupleSelect(assign_expr->right->copy(), new IntLiteral(intstring(i), i));
    AssignOp* new_assign_expr =
      new AssignOp(assign_expr->type, new_left, new_right);
    ExprStmt* new_assign_stmt = new ExprStmt(new_assign_expr);
    stmt->insertBefore(new_assign_stmt);
  }
  stmt->extract();
}
<commit_msg>A small modification of this pass led to failure of test_index_expr1.chpl. Corrected that.<commit_after>#include "destructureTupleAssignments.h"
#include "stmt.h"
#include "expr.h"
#include "type.h"
#include "stringutil.h"

void DestructureTupleAssignments::postProcessStmt(Stmt* stmt) {
  ExprStmt* assign_stmt = dynamic_cast<ExprStmt*>(stmt);

  if (!assign_stmt) {
    return;
  }

  AssignOp* assign_expr = dynamic_cast<AssignOp*>(assign_stmt->expr);

  if (!assign_expr) {
    return;
  }

  TupleType* left_type = dynamic_cast<TupleType*>(assign_expr->left->typeInfo()->getType());
  TupleType* right_type = dynamic_cast<TupleType*>(assign_expr->right->typeInfo()->getType());

  //RED -- temporary workaround the situation when a index is assigned to a tuple
  //the index->idxType may be a tuple and thus this test will pass
  //the downside is that index to tuple assignment still has to be destructured so this
  //leads to incorrect code generation
  if (left_type && right_type && (assign_expr->left->typeInfo() == assign_expr->right->typeInfo())) {
    return;
  }

  Tuple* left_tuple = dynamic_cast<Tuple*>(assign_expr->left);
  Tuple* right_tuple = dynamic_cast<Tuple*>(assign_expr->right);

  if (!left_type && !left_tuple && !right_type && !right_tuple) {
    return;
  }

  if (!left_type && !left_tuple) {
    INT_FATAL(stmt, "Tuple to non-tuple assignment should be caught earlier");
  }

  if (!right_type && !right_tuple) {
    INT_FATAL(stmt, "Non-tuple to tuple assignment should be caught earlier");
  }

  int left_n =
    (left_type)
    ? left_type->components.n
    : left_tuple->exprs->length();

  int right_n =
    (right_type)
    ? right_type->components.n
    : right_tuple->exprs->length();

  if (left_n != right_n) {
    INT_FATAL(stmt, "Non-matching tuple assign should be caught earlier");
  }

  if (assign_expr->type != GETS_NORM) {
    INT_FATAL(stmt, "Non-standard tuple assign should be caught earlier");
  }

  for (int i = 1; i <= left_n; i++) {
    TupleSelect* new_left =
      new TupleSelect(assign_expr->left->copy(), new IntLiteral(intstring(i), i));
    TupleSelect* new_right =
      new TupleSelect(assign_expr->right->copy(), new IntLiteral(intstring(i), i));
    AssignOp* new_assign_expr =
      new AssignOp(assign_expr->type, new_left, new_right);
    ExprStmt* new_assign_stmt = new ExprStmt(new_assign_expr);
    stmt->insertBefore(new_assign_stmt);
  }
  stmt->extract();
}
<|endoftext|>


<commit_before>#include "Base.h"
#include "AudioBuffer.h"
#include "FileSystem.h"

#ifdef __ANDROID__
extern AAssetManager* __assetManager;
#endif

namespace gameplay
{

// Audio buffer cache
static std::vector<AudioBuffer*> __buffers;

#ifndef __ANDROID__
AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
    : _filePath(path), _alBuffer(buffer)
{
}
#else
AudioBuffer::AudioBuffer(const char* path) : _filePath(path)
{
}
#endif

AudioBuffer::~AudioBuffer()
{
#ifndef __ANDROID__
    if (_alBuffer)
    {
        alDeleteBuffers(1, &_alBuffer);
        _alBuffer = 0;
    }
#endif
}

AudioBuffer* AudioBuffer::create(const char* path)
{
    assert(path);

    // Search the cache for a stream from this file.
    unsigned int bufferCount = (unsigned int)__buffers.size();
    AudioBuffer* buffer = NULL;
    for (unsigned int i = 0; i < bufferCount; i++)
    {
        buffer = __buffers[i];
        if (buffer->_filePath.compare(path) == 0)
        {
            buffer->addRef();
            return buffer;
        }
    }

#ifndef __ANDROID__
    ALuint alBuffer;
    ALCenum al_error;

    // Load audio data into a buffer.
    alGenBuffers(1, &alBuffer);
    al_error = alGetError();
    if (al_error != AL_NO_ERROR)
    {
        LOG_ERROR_VARG("AudioBuffer alGenBuffers AL error: %d", al_error);
        alDeleteBuffers(1, &alBuffer);
        return NULL;
    }

    // Load sound file.
    FILE* file = FileSystem::openFile(path, "rb");
    if (!file)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        goto cleanup;
    }

    // Read the file header
    char header[12];
    if (fread(header, 1, 12, file) != 12)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        goto cleanup;
    }

    // Check the file format
    if (memcmp(header, "RIFF", 4) == 0)
    {
        if (!AudioBuffer::loadWav(file, alBuffer))
        {
            LOG_ERROR_VARG("Invalid wave file: %s", path);
            goto cleanup;
        }
    }
    else if (memcmp(header, "OggS", 4) == 0)
    {
        if (!AudioBuffer::loadOgg(file, alBuffer))
        {
            LOG_ERROR_VARG("Invalid ogg file: %s", path);
            goto cleanup;
        }
    }
    else
    {
        LOG_ERROR_VARG("Unsupported audio file: %s", path);
    }

    fclose(file);

    buffer = new AudioBuffer(path, alBuffer);

    // Add the buffer to the cache.
    __buffers.push_back(buffer);

    return buffer;

cleanup:

    if (file)
        fclose(file);
    if (alBuffer)
        alDeleteBuffers(1, &alBuffer);
    return NULL;
#else
    // Get the file header in order to determine the type.
    AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
    char header[12];
    if (AAsset_read(asset, header, 12) != 12)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        return NULL;
    }

    // Get the file descriptor for the audio file.
    off_t start, length;
    int fd = AAsset_openFileDescriptor(asset, &start, &length);
    if (fd < 0)
    {
        LOG_ERROR_VARG("Failed to open file descriptor for asset: %s", path);
        return NULL;
    }
    AAsset_close(asset);
    SLDataLocator_AndroidFD data = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};

    // Set the appropriate mime type information.
    SLDataFormat_MIME mime;
    mime.formatType = SL_DATAFORMAT_MIME;
    std::string pathStr = path;
    if (memcmp(header, "RIFF", 4) == 0)
    {
        mime.mimeType = (SLchar*)"audio/x-wav";
        mime.containerType = SL_CONTAINERTYPE_WAV;
    }
    else if (memcmp(header, "OggS", 4) == 0)
    {
        mime.mimeType = (SLchar*)"application/ogg";
        mime.containerType = SL_CONTAINERTYPE_OGG;
    }
    else
    {
        LOG_ERROR_VARG("Unsupported audio file: %s", path);
    }

    buffer = new AudioBuffer(path);
    buffer->_data = data;
    buffer->_mime = mime;

    // Add the buffer to the cache.
    __buffers.push_back(buffer);

    return buffer;
#endif
}

#ifndef __ANDROID__
bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
{
    unsigned char stream[12];

    // Verify the wave fmt magic value meaning format.
    if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
        return false;

    // Check for a valid pcm format.
    if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
    {
        LOG_ERROR("Unsupported audio file, not PCM format.");
        return false;
    }

    // Get the channel count (16-bit little-endian)
    int channels;
    if (fread(stream, 1, 2, file) != 2)
        return false;
    channels  = stream[1]<<8;
    channels |= stream[0];

    // Get the sample frequency (32-bit little-endian)
    ALuint frequency;
    if (fread(stream, 1, 4, file) != 4)
        return false;

    frequency  = stream[3]<<24;
    frequency |= stream[2]<<16;
    frequency |= stream[1]<<8;
    frequency |= stream[0];

    // The next 6 bytes hold the block size and bytes-per-second.
    // We don't need that info, so just read and ignore it.
    // We could use this later if we need to know the duration.
    if (fread(stream, 1, 6, file) != 6)
        return false;

    // Get the bit depth (16-bit little-endian)
    int bits;
    if (fread(stream, 1, 2, file) != 2)
        return false;
    bits  = stream[1]<<8;
    bits |= stream[0];

    // Now convert the given channel count and bit depth into an OpenAL format.
    ALuint format = 0;
    if (bits == 8)
    {
        if (channels == 1)
            format = AL_FORMAT_MONO8;
        else if (channels == 2)
            format = AL_FORMAT_STEREO8;
    }
    else if (bits == 16)
    {
        if (channels == 1)
            format = AL_FORMAT_MONO16;
        else if (channels == 2)
            format = AL_FORMAT_STEREO16;
    }
    else
    {
        LOG_ERROR_VARG("Incompatible format: (%d, %d)", channels, bits);
        return false;
    }

    // Read the data chunk, which will hold the decoded sample data
    if (fread(stream, 1, 4, file) != 4 || memcmp(stream, "data", 4) != 0)
    {
        LOG_ERROR("WAV file has no data.");
        return false;
    }

    // Read how much data is remaining and buffer it up.
    unsigned int dataSize;
    fread(&dataSize, sizeof(int), 1, file);

    char* data = new char[dataSize];
    if (fread(data, sizeof(char), dataSize, file) != dataSize)
    {
        LOG_ERROR("WAV file missing data.");
        SAFE_DELETE_ARRAY(data);
        return false;
    }

    alBufferData(buffer, format, data, dataSize, frequency);
    SAFE_DELETE_ARRAY(data);
    return true;
}

bool AudioBuffer::loadOgg(FILE* file, ALuint buffer)
{
    OggVorbis_File ogg_file;
    vorbis_info* info;
    ALenum format;
    int result;
    int section;
    unsigned int size = 0;

    rewind(file);

    if ((result = ov_open(file, &ogg_file, NULL, 0)) < 0)
    {
        fclose(file);
        LOG_ERROR("Could not open Ogg stream.");
        return false;
    }

    info = ov_info(&ogg_file, -1);

    if (info->channels == 1)
        format = AL_FORMAT_MONO16;
    else
        format = AL_FORMAT_STEREO16;

	// size = #samples * #channels * 2 (for 16 bit)
    unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2;
    char* data = new char[data_size];

    while (size < data_size)
    {
    	result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, &section);
    	if (result > 0)
    	{
    		size += result;
    	}
    	else if (result < 0)
    	{
    		SAFE_DELETE_ARRAY(data);
    		LOG_ERROR("OGG file missing data.");
    		return false;
    	}
    	else
    	{
    		break;
    	}
    }

    if (size == 0)
    {
    	SAFE_DELETE_ARRAY(data);
    	LOG_ERROR("Unable to read OGG data.");
    	return false;
    }

    alBufferData(buffer, format, data, data_size, info->rate);

    SAFE_DELETE_ARRAY(data);
    ov_clear(&ogg_file);

    // ov_clear actually closes the file pointer as well
    file = 0;

    return true;
}
#endif

}
<commit_msg>Fixing a bug with some of the .wav files not loading.  All wave files are not guaranteed to have 16 bytes in the fmt section.  There can be optional information in there.  See http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html for example.  Modified the code so that it accounts for those optional sections.<commit_after>#include "Base.h"
#include "AudioBuffer.h"
#include "FileSystem.h"

#ifdef __ANDROID__
extern AAssetManager* __assetManager;
#endif

namespace gameplay
{

// Audio buffer cache
static std::vector<AudioBuffer*> __buffers;

#ifndef __ANDROID__
AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
    : _filePath(path), _alBuffer(buffer)
{
}
#else
AudioBuffer::AudioBuffer(const char* path) : _filePath(path)
{
}
#endif

AudioBuffer::~AudioBuffer()
{
#ifndef __ANDROID__
    if (_alBuffer)
    {
        alDeleteBuffers(1, &_alBuffer);
        _alBuffer = 0;
    }
#endif
}

AudioBuffer* AudioBuffer::create(const char* path)
{
    assert(path);

    // Search the cache for a stream from this file.
    unsigned int bufferCount = (unsigned int)__buffers.size();
    AudioBuffer* buffer = NULL;
    for (unsigned int i = 0; i < bufferCount; i++)
    {
        buffer = __buffers[i];
        if (buffer->_filePath.compare(path) == 0)
        {
            buffer->addRef();
            return buffer;
        }
    }

#ifndef __ANDROID__
    ALuint alBuffer;
    ALCenum al_error;

    // Load audio data into a buffer.
    alGenBuffers(1, &alBuffer);
    al_error = alGetError();
    if (al_error != AL_NO_ERROR)
    {
        LOG_ERROR_VARG("AudioBuffer alGenBuffers AL error: %d", al_error);
        alDeleteBuffers(1, &alBuffer);
        return NULL;
    }

    // Load sound file.
    FILE* file = FileSystem::openFile(path, "rb");
    if (!file)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        goto cleanup;
    }

    // Read the file header
    char header[12];
    if (fread(header, 1, 12, file) != 12)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        goto cleanup;
    }

    // Check the file format
    if (memcmp(header, "RIFF", 4) == 0)
    {
        if (!AudioBuffer::loadWav(file, alBuffer))
        {
            LOG_ERROR_VARG("Invalid wave file: %s", path);
            goto cleanup;
        }
    }
    else if (memcmp(header, "OggS", 4) == 0)
    {
        if (!AudioBuffer::loadOgg(file, alBuffer))
        {
            LOG_ERROR_VARG("Invalid ogg file: %s", path);
            goto cleanup;
        }
    }
    else
    {
        LOG_ERROR_VARG("Unsupported audio file: %s", path);
    }

    fclose(file);

    buffer = new AudioBuffer(path, alBuffer);

    // Add the buffer to the cache.
    __buffers.push_back(buffer);

    return buffer;

cleanup:

    if (file)
        fclose(file);
    if (alBuffer)
        alDeleteBuffers(1, &alBuffer);
    return NULL;
#else
    // Get the file header in order to determine the type.
    AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
    char header[12];
    if (AAsset_read(asset, header, 12) != 12)
    {
        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
        return NULL;
    }

    // Get the file descriptor for the audio file.
    off_t start, length;
    int fd = AAsset_openFileDescriptor(asset, &start, &length);
    if (fd < 0)
    {
        LOG_ERROR_VARG("Failed to open file descriptor for asset: %s", path);
        return NULL;
    }
    AAsset_close(asset);
    SLDataLocator_AndroidFD data = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};

    // Set the appropriate mime type information.
    SLDataFormat_MIME mime;
    mime.formatType = SL_DATAFORMAT_MIME;
    std::string pathStr = path;
    if (memcmp(header, "RIFF", 4) == 0)
    {
        mime.mimeType = (SLchar*)"audio/x-wav";
        mime.containerType = SL_CONTAINERTYPE_WAV;
    }
    else if (memcmp(header, "OggS", 4) == 0)
    {
        mime.mimeType = (SLchar*)"application/ogg";
        mime.containerType = SL_CONTAINERTYPE_OGG;
    }
    else
    {
        LOG_ERROR_VARG("Unsupported audio file: %s", path);
    }

    buffer = new AudioBuffer(path);
    buffer->_data = data;
    buffer->_mime = mime;

    // Add the buffer to the cache.
    __buffers.push_back(buffer);

    return buffer;
#endif
}

#ifndef __ANDROID__
bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
{
    unsigned char stream[12];

    // Verify the wave fmt magic value meaning format.
    if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
        return false;

    unsigned int section_size;
    section_size  = stream[7]<<24;
    section_size |= stream[6]<<16;
    section_size |= stream[5]<<8;
    section_size |= stream[4];

    // Check for a valid pcm format.
    if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
    {
        LOG_ERROR("Unsupported audio file, not PCM format.");
        return false;
    }

    // Get the channel count (16-bit little-endian)
    int channels;
    if (fread(stream, 1, 2, file) != 2)
        return false;
    channels  = stream[1]<<8;
    channels |= stream[0];

    // Get the sample frequency (32-bit little-endian)
    ALuint frequency;
    if (fread(stream, 1, 4, file) != 4)
        return false;

    frequency  = stream[3]<<24;
    frequency |= stream[2]<<16;
    frequency |= stream[1]<<8;
    frequency |= stream[0];

    // The next 6 bytes hold the block size and bytes-per-second.
    // We don't need that info, so just read and ignore it.
    // We could use this later if we need to know the duration.
    if (fread(stream, 1, 6, file) != 6)
        return false;

    // Get the bit depth (16-bit little-endian)
    int bits;
    if (fread(stream, 1, 2, file) != 2)
        return false;
    bits  = stream[1]<<8;
    bits |= stream[0];

    // Now convert the given channel count and bit depth into an OpenAL format.
    ALuint format = 0;
    if (bits == 8)
    {
        if (channels == 1)
            format = AL_FORMAT_MONO8;
        else if (channels == 2)
            format = AL_FORMAT_STEREO8;
    }
    else if (bits == 16)
    {
        if (channels == 1)
            format = AL_FORMAT_MONO16;
        else if (channels == 2)
            format = AL_FORMAT_STEREO16;
    }
    else
    {
        LOG_ERROR_VARG("Incompatible format: (%d, %d)", channels, bits);
        return false;
    }

    // Check against the size of the format header as there may be more data that we need to read
    if (section_size > 16)
    {
    	unsigned int length = section_size - 16;

    	// extension size is 2 bytes
    	if (fread(stream, 1, length, file) != length)
    		return false;
    }

    if (fread(stream, 1, 4, file) != 4)
    	return false;

    // read the next chunk, could be fact section or the data section
    if (memcmp(stream, "fact", 4) == 0)
    {
    	if (fread(stream, 1, 4, file) != 4)
    		return false;

    	section_size  = stream[3]<<24;
    	section_size |= stream[2]<<16;
    	section_size |= stream[1]<<8;
    	section_size |= stream[0];

    	// read in the rest of the fact section
    	if (fread(stream, 1, section_size, file) != section_size)
    		return false;

    	if (fread(stream, 1, 4, file) != 4)
    		return false;
    }

    // should now be the data section which holds the decoded sample data
    if (memcmp(stream, "data", 4) != 0)
    {
    	LOG_ERROR("WAV file has no data.");
    	return false;
    }

    // Read how much data is remaining and buffer it up.
    unsigned int dataSize;
    fread(&dataSize, sizeof(int), 1, file);

    char* data = new char[dataSize];
    if (fread(data, sizeof(char), dataSize, file) != dataSize)
    {
        LOG_ERROR("WAV file missing data.");
        SAFE_DELETE_ARRAY(data);
        return false;
    }

    alBufferData(buffer, format, data, dataSize, frequency);
    SAFE_DELETE_ARRAY(data);
    return true;
}

bool AudioBuffer::loadOgg(FILE* file, ALuint buffer)
{
    OggVorbis_File ogg_file;
    vorbis_info* info;
    ALenum format;
    int result;
    int section;
    unsigned int size = 0;

    rewind(file);

    if ((result = ov_open(file, &ogg_file, NULL, 0)) < 0)
    {
        fclose(file);
        LOG_ERROR("Could not open Ogg stream.");
        return false;
    }

    info = ov_info(&ogg_file, -1);

    if (info->channels == 1)
        format = AL_FORMAT_MONO16;
    else
        format = AL_FORMAT_STEREO16;

	// size = #samples * #channels * 2 (for 16 bit)
    unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2;
    char* data = new char[data_size];

    while (size < data_size)
    {
    	result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, &section);
    	if (result > 0)
    	{
    		size += result;
    	}
    	else if (result < 0)
    	{
    		SAFE_DELETE_ARRAY(data);
    		LOG_ERROR("OGG file missing data.");
    		return false;
    	}
    	else
    	{
    		break;
    	}
    }

    if (size == 0)
    {
    	SAFE_DELETE_ARRAY(data);
    	LOG_ERROR("Unable to read OGG data.");
    	return false;
    }

    alBufferData(buffer, format, data, data_size, info->rate);

    SAFE_DELETE_ARRAY(data);
    ov_clear(&ogg_file);

    // ov_clear actually closes the file pointer as well
    file = 0;

    return true;
}
#endif

}
<|endoftext|>


<commit_before>#ifndef __FACTOR_MASTER_H__
#define __FACTOR_MASTER_H__

#ifndef _THREAD_SAFE
#define _THREAD_SAFE
#endif

#ifndef _REENTRANT
#define _REENTRANT
#endif

#include <errno.h>

/* C headers */
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <stdint.h>

/* C++ headers */
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <iomanip>
#include <limits>

#define FACTOR_STRINGIZE_I(x) #x
#define FACTOR_STRINGIZE(x) FACTOR_STRINGIZE_I(x)

/* Record compiler version */
#if defined(__clang__)
#define FACTOR_COMPILER_VERSION "Clang (GCC " __VERSION__ ")"
#elif defined(__INTEL_COMPILER)
#define FACTOR_COMPILER_VERSION \
  "Intel C Compiler " FACTOR_STRINGIZE(__INTEL_COMPILER)
#elif defined(__GNUC__)
#define FACTOR_COMPILER_VERSION "GCC " __VERSION__
#elif defined(_MSC_FULL_VER)
#define FACTOR_COMPILER_VERSION \
  "Microsoft Visual C++ " FACTOR_STRINGIZE(_MSC_FULL_VER)
#else
#define FACTOR_COMPILER_VERSION "unknown"
#endif

/* Detect target CPU type */
#if defined(__arm__)
#define FACTOR_ARM
#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
#define FACTOR_AMD64
#define FACTOR_64
#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define FACTOR_X86
#elif(defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)) && \
    (defined(__PPC64__) || defined(__64BIT__))
#define FACTOR_PPC64
#define FACTOR_PPC
#define FACTOR_64
#elif defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)
#define FACTOR_PPC32
#define FACTOR_PPC
#else
#error "Unsupported architecture"
#endif

#if defined(_MSC_VER)
#define WINDOWS
#define WINNT
#elif defined(WIN32)
#define WINDOWS
#endif

/* Forward-declare this since it comes up in function prototypes */
namespace factor { struct factor_vm; }

/* Factor headers */
#include "assert.hpp"
#include "layouts.hpp"
#include "platform.hpp"
#include "primitives.hpp"
#include "segments.hpp"
#include "gc_info.hpp"
#include "contexts.hpp"
#include "run.hpp"
#include "objects.hpp"
#include "sampling_profiler.hpp"
#include "errors.hpp"
#include "bignumint.hpp"
#include "bignum.hpp"
#include "booleans.hpp"
#include "instruction_operands.hpp"
#include "code_blocks.hpp"
#include "bump_allocator.hpp"
#include "bitwise_hacks.hpp"
#include "mark_bits.hpp"
#include "free_list.hpp"
#include "fixup.hpp"
#include "tuples.hpp"
#include "free_list_allocator.hpp"
#include "write_barrier.hpp"
#include "object_start_map.hpp"
#include "nursery_space.hpp"
#include "aging_space.hpp"
#include "tenured_space.hpp"
#include "data_heap.hpp"
#include "code_heap.hpp"
#include "gc.hpp"
#include "strings.hpp"
#include "float_bits.hpp"
#include "io.hpp"
#include "image.hpp"
#include "callbacks.hpp"
#include "dispatch.hpp"
#include "entry_points.hpp"
#include "safepoints.hpp"
#include "vm.hpp"
#include "allot.hpp"
#include "tagged.hpp"
#include "data_roots.hpp"
#include "code_roots.hpp"
#include "generic_arrays.hpp"
#include "callstack.hpp"
#include "slot_visitor.hpp"
#include "collector.hpp"
#include "copying_collector.hpp"
#include "nursery_collector.hpp"
#include "aging_collector.hpp"
#include "to_tenured_collector.hpp"
#include "code_block_visitor.hpp"
#include "full_collector.hpp"
#include "arrays.hpp"
#include "math.hpp"
#include "byte_arrays.hpp"
#include "jit.hpp"
#include "quotations.hpp"
#include "inline_cache.hpp"
#include "mvm.hpp"
#include "factor.hpp"
#include "utilities.hpp"

#endif /* __FACTOR_MASTER_H__ */
<commit_msg>vm: Fix compilation on Windows. Fixes #1086.<commit_after>#ifndef __FACTOR_MASTER_H__
#define __FACTOR_MASTER_H__

#ifndef _THREAD_SAFE
#define _THREAD_SAFE
#endif

#ifndef _REENTRANT
#define _REENTRANT
#endif

#include <errno.h>

/* C headers */
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <stdint.h>

/* C++ headers */
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>

#define FACTOR_STRINGIZE_I(x) #x
#define FACTOR_STRINGIZE(x) FACTOR_STRINGIZE_I(x)

/* Record compiler version */
#if defined(__clang__)
#define FACTOR_COMPILER_VERSION "Clang (GCC " __VERSION__ ")"
#elif defined(__INTEL_COMPILER)
#define FACTOR_COMPILER_VERSION \
  "Intel C Compiler " FACTOR_STRINGIZE(__INTEL_COMPILER)
#elif defined(__GNUC__)
#define FACTOR_COMPILER_VERSION "GCC " __VERSION__
#elif defined(_MSC_FULL_VER)
#define FACTOR_COMPILER_VERSION \
  "Microsoft Visual C++ " FACTOR_STRINGIZE(_MSC_FULL_VER)
#else
#define FACTOR_COMPILER_VERSION "unknown"
#endif

/* Detect target CPU type */
#if defined(__arm__)
#define FACTOR_ARM
#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
#define FACTOR_AMD64
#define FACTOR_64
#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define FACTOR_X86
#elif(defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)) && \
    (defined(__PPC64__) || defined(__64BIT__))
#define FACTOR_PPC64
#define FACTOR_PPC
#define FACTOR_64
#elif defined(__POWERPC__) || defined(__ppc__) || defined(_ARCH_PPC)
#define FACTOR_PPC32
#define FACTOR_PPC
#else
#error "Unsupported architecture"
#endif

#if defined(_MSC_VER)
#define WINDOWS
#define WINNT
#elif defined(WIN32)
#define WINDOWS
#endif

/* Forward-declare this since it comes up in function prototypes */
namespace factor { struct factor_vm; }

/* Factor headers */
#include "assert.hpp"
#include "layouts.hpp"
#include "platform.hpp"
#include "primitives.hpp"
#include "segments.hpp"
#include "gc_info.hpp"
#include "contexts.hpp"
#include "run.hpp"
#include "objects.hpp"
#include "sampling_profiler.hpp"
#include "errors.hpp"
#include "bignumint.hpp"
#include "bignum.hpp"
#include "booleans.hpp"
#include "instruction_operands.hpp"
#include "code_blocks.hpp"
#include "bump_allocator.hpp"
#include "bitwise_hacks.hpp"
#include "mark_bits.hpp"
#include "free_list.hpp"
#include "fixup.hpp"
#include "tuples.hpp"
#include "free_list_allocator.hpp"
#include "write_barrier.hpp"
#include "object_start_map.hpp"
#include "nursery_space.hpp"
#include "aging_space.hpp"
#include "tenured_space.hpp"
#include "data_heap.hpp"
#include "code_heap.hpp"
#include "gc.hpp"
#include "strings.hpp"
#include "float_bits.hpp"
#include "io.hpp"
#include "image.hpp"
#include "callbacks.hpp"
#include "dispatch.hpp"
#include "entry_points.hpp"
#include "safepoints.hpp"
#include "vm.hpp"
#include "allot.hpp"
#include "tagged.hpp"
#include "data_roots.hpp"
#include "code_roots.hpp"
#include "generic_arrays.hpp"
#include "callstack.hpp"
#include "slot_visitor.hpp"
#include "collector.hpp"
#include "copying_collector.hpp"
#include "nursery_collector.hpp"
#include "aging_collector.hpp"
#include "to_tenured_collector.hpp"
#include "code_block_visitor.hpp"
#include "full_collector.hpp"
#include "arrays.hpp"
#include "math.hpp"
#include "byte_arrays.hpp"
#include "jit.hpp"
#include "quotations.hpp"
#include "inline_cache.hpp"
#include "mvm.hpp"
#include "factor.hpp"
#include "utilities.hpp"

#endif /* __FACTOR_MASTER_H__ */
<|endoftext|>


<commit_before>// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>

#include <cassert>
#include <cstdint>
#include <netinet/in.h>
#include <vector>

namespace {
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
    const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
    if (network == Network::NET_IPV4) {
        const in_addr v4_addr = {
            .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
        return CNetAddr{v4_addr};
    } else if (network == Network::NET_IPV6) {
        if (fuzzed_data_provider.remaining_bytes() < 16) {
            return CNetAddr{};
        }
        in6_addr v6_addr = {};
        memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
        return CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
    } else if (network == Network::NET_INTERNAL) {
        CNetAddr net_addr;
        net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
        return net_addr;
    } else if (network == Network::NET_ONION) {
        CNetAddr net_addr;
        net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
        return net_addr;
    } else {
        assert(false);
    }
}
}; // namespace

void test_one_input(const std::vector<uint8_t>& buffer)
{
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());

    const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider);
    for (int i = 0; i < 15; ++i) {
        (void)net_addr.GetByte(i);
    }
    (void)net_addr.GetHash();
    (void)net_addr.GetNetClass();
    if (net_addr.GetNetwork() == Network::NET_IPV4) {
        assert(net_addr.IsIPv4());
    }
    if (net_addr.GetNetwork() == Network::NET_IPV6) {
        assert(net_addr.IsIPv6());
    }
    if (net_addr.GetNetwork() == Network::NET_ONION) {
        assert(net_addr.IsTor());
    }
    if (net_addr.GetNetwork() == Network::NET_INTERNAL) {
        assert(net_addr.IsInternal());
    }
    if (net_addr.GetNetwork() == Network::NET_UNROUTABLE) {
        assert(!net_addr.IsRoutable());
    }
    (void)net_addr.IsBindAny();
    if (net_addr.IsInternal()) {
        assert(net_addr.GetNetwork() == Network::NET_INTERNAL);
    }
    if (net_addr.IsIPv4()) {
        assert(net_addr.GetNetwork() == Network::NET_IPV4 || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    if (net_addr.IsIPv6()) {
        assert(net_addr.GetNetwork() == Network::NET_IPV6 || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    (void)net_addr.IsLocal();
    if (net_addr.IsRFC1918() || net_addr.IsRFC2544() || net_addr.IsRFC6598() || net_addr.IsRFC5737() || net_addr.IsRFC3927()) {
        assert(net_addr.IsIPv4());
    }
    (void)net_addr.IsRFC2544();
    if (net_addr.IsRFC3849() || net_addr.IsRFC3964() || net_addr.IsRFC4380() || net_addr.IsRFC4843() || net_addr.IsRFC7343() || net_addr.IsRFC4862() || net_addr.IsRFC6052() || net_addr.IsRFC6145()) {
        assert(net_addr.IsIPv6());
    }
    (void)net_addr.IsRFC3927();
    (void)net_addr.IsRFC3964();
    if (net_addr.IsRFC4193()) {
        assert(net_addr.GetNetwork() == Network::NET_ONION || net_addr.GetNetwork() == Network::NET_INTERNAL || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    (void)net_addr.IsRFC4380();
    (void)net_addr.IsRFC4843();
    (void)net_addr.IsRFC4862();
    (void)net_addr.IsRFC5737();
    (void)net_addr.IsRFC6052();
    (void)net_addr.IsRFC6145();
    (void)net_addr.IsRFC6598();
    (void)net_addr.IsRFC7343();
    if (!net_addr.IsRoutable()) {
        assert(net_addr.GetNetwork() == Network::NET_UNROUTABLE || net_addr.GetNetwork() == Network::NET_INTERNAL);
    }
    if (net_addr.IsTor()) {
        assert(net_addr.GetNetwork() == Network::NET_ONION);
    }
    (void)net_addr.IsValid();
    (void)net_addr.ToString();
    (void)net_addr.ToStringIP();

    const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<int32_t>()};
    (void)sub_net.IsValid();
    (void)sub_net.ToString();

    const CService service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
    (void)service.GetKey();
    (void)service.GetPort();
    (void)service.ToString();
    (void)service.ToStringIPPort();
    (void)service.ToStringPort();

    const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider);
    (void)net_addr.GetReachabilityFrom(&other_net_addr);
    (void)sub_net.Match(other_net_addr);

    const CService other_service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
    assert((service == other_service) != (service != other_service));
}
<commit_msg>tests: Add fuzzing of CSubNet, CNetAddr and CService related functions<commit_after>// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>

#include <cassert>
#include <cstdint>
#include <netinet/in.h>
#include <vector>

namespace {
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
    const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
    if (network == Network::NET_IPV4) {
        const in_addr v4_addr = {
            .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
        return CNetAddr{v4_addr};
    } else if (network == Network::NET_IPV6) {
        if (fuzzed_data_provider.remaining_bytes() < 16) {
            return CNetAddr{};
        }
        in6_addr v6_addr = {};
        memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
        return CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
    } else if (network == Network::NET_INTERNAL) {
        CNetAddr net_addr;
        net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
        return net_addr;
    } else if (network == Network::NET_ONION) {
        CNetAddr net_addr;
        net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
        return net_addr;
    } else {
        assert(false);
    }
}
}; // namespace

void test_one_input(const std::vector<uint8_t>& buffer)
{
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());

    const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider);
    for (int i = 0; i < 15; ++i) {
        (void)net_addr.GetByte(i);
    }
    (void)net_addr.GetHash();
    (void)net_addr.GetNetClass();
    if (net_addr.GetNetwork() == Network::NET_IPV4) {
        assert(net_addr.IsIPv4());
    }
    if (net_addr.GetNetwork() == Network::NET_IPV6) {
        assert(net_addr.IsIPv6());
    }
    if (net_addr.GetNetwork() == Network::NET_ONION) {
        assert(net_addr.IsTor());
    }
    if (net_addr.GetNetwork() == Network::NET_INTERNAL) {
        assert(net_addr.IsInternal());
    }
    if (net_addr.GetNetwork() == Network::NET_UNROUTABLE) {
        assert(!net_addr.IsRoutable());
    }
    (void)net_addr.IsBindAny();
    if (net_addr.IsInternal()) {
        assert(net_addr.GetNetwork() == Network::NET_INTERNAL);
    }
    if (net_addr.IsIPv4()) {
        assert(net_addr.GetNetwork() == Network::NET_IPV4 || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    if (net_addr.IsIPv6()) {
        assert(net_addr.GetNetwork() == Network::NET_IPV6 || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    (void)net_addr.IsLocal();
    if (net_addr.IsRFC1918() || net_addr.IsRFC2544() || net_addr.IsRFC6598() || net_addr.IsRFC5737() || net_addr.IsRFC3927()) {
        assert(net_addr.IsIPv4());
    }
    (void)net_addr.IsRFC2544();
    if (net_addr.IsRFC3849() || net_addr.IsRFC3964() || net_addr.IsRFC4380() || net_addr.IsRFC4843() || net_addr.IsRFC7343() || net_addr.IsRFC4862() || net_addr.IsRFC6052() || net_addr.IsRFC6145()) {
        assert(net_addr.IsIPv6());
    }
    (void)net_addr.IsRFC3927();
    (void)net_addr.IsRFC3964();
    if (net_addr.IsRFC4193()) {
        assert(net_addr.GetNetwork() == Network::NET_ONION || net_addr.GetNetwork() == Network::NET_INTERNAL || net_addr.GetNetwork() == Network::NET_UNROUTABLE);
    }
    (void)net_addr.IsRFC4380();
    (void)net_addr.IsRFC4843();
    (void)net_addr.IsRFC4862();
    (void)net_addr.IsRFC5737();
    (void)net_addr.IsRFC6052();
    (void)net_addr.IsRFC6145();
    (void)net_addr.IsRFC6598();
    (void)net_addr.IsRFC7343();
    if (!net_addr.IsRoutable()) {
        assert(net_addr.GetNetwork() == Network::NET_UNROUTABLE || net_addr.GetNetwork() == Network::NET_INTERNAL);
    }
    if (net_addr.IsTor()) {
        assert(net_addr.GetNetwork() == Network::NET_ONION);
    }
    (void)net_addr.IsValid();
    (void)net_addr.ToString();
    (void)net_addr.ToStringIP();

    const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<int32_t>()};
    (void)sub_net.IsValid();
    (void)sub_net.ToString();

    const CService service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
    (void)service.GetKey();
    (void)service.GetPort();
    (void)service.ToString();
    (void)service.ToStringIPPort();
    (void)service.ToStringPort();

    const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider);
    (void)net_addr.GetReachabilityFrom(&other_net_addr);
    (void)sub_net.Match(other_net_addr);

    const CService other_service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
    assert((service == other_service) != (service != other_service));
    (void)(service < other_service);

    const CSubNet sub_net_copy_1{net_addr, other_net_addr};
    const CSubNet sub_net_copy_2{net_addr};

    CNetAddr mutable_net_addr;
    mutable_net_addr.SetIP(net_addr);
    assert(net_addr == mutable_net_addr);
}
<|endoftext|>