<commit_before>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Main program to start and inject a DLL into a process via a remote thread.
 *
 * For background see:
 * - http://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows
 * - http://www.codeproject.com/KB/threads/completeinject.aspx
 * - http://www.codeproject.com/KB/threads/winspy.aspx
 * - http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
 * - http://www.codeproject.com/KB/threads/APIHooking.aspx
 *
 * Other slightly different techniques:
 * - http://www.fr33project.org/pages/projects/phook.htm
 * - http://www.hbgary.com/loading-a-dll-without-calling-loadlibrary
 * - http://securityxploded.com/ntcreatethreadex.php
 */

#include <string>

#include <windows.h>
#include <stdio.h>

#include "inject.h"

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

int
main(int argc, char *argv[])
{

    if (argc < 3) {
        fprintf(stderr, "inject dllname.dll command [args] ...\n");
        return 1;
    }

    const char *szDll = argv[1];
    if (!USE_SHARED_MEM) {
        SetEnvironmentVariableA("INJECT_DLL", szDll);
    } else {
        SetSharedMem(szDll);
    }

    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    BOOL bAttach;
    if (isdigit(argv[2][0])) {
        bAttach = TRUE;

        BOOL bRet;
        HANDLE hToken   = NULL;
        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
        if (!bRet) {
            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
            return 1;
        }

        LUID Luid;
        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
        if (!bRet) {
            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
            return 1;
        }

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = Luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
        if (!bRet) {
            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
            return 1;
        }

        DWORD dwDesiredAccess =
            PROCESS_CREATE_THREAD |
            PROCESS_QUERY_INFORMATION |
            PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_VM_OPERATION |
            PROCESS_VM_WRITE |
            PROCESS_VM_READ;
        DWORD dwProcessId = atol(argv[2]);
        hProcess = OpenProcess(
            dwDesiredAccess,
            FALSE /* bInheritHandle */,
            dwProcessId);
        if (!hProcess) {
            DWORD dwLastError = GetLastError();
            fprintf(stderr, "error: failed to open process %lu (%lu)\n", dwProcessId, dwLastError);
            return 1;
        }
    } else {
        bAttach = FALSE;
        std::string commandLine;
        char sep = 0;
        for (int i = 2; i < argc; ++i) {
            const char *arg = argv[i];

            if (sep) {
                commandLine.push_back(sep);
            }

            if (needsQuote(arg)) {
                quoteArg(commandLine, arg);
            } else {
                commandLine.append(arg);
            }

            sep = ' ';
        }

        STARTUPINFO startupInfo;
        memset(&startupInfo, 0, sizeof startupInfo);
        startupInfo.cb = sizeof startupInfo;

        // Create the process in suspended state
        if (!CreateProcessA(
               NULL,
               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
               0, // process attributes
               0, // thread attributes
               TRUE, // inherit handles
               CREATE_SUSPENDED,
               NULL, // environment
               NULL, // current directory
               &startupInfo,
               &processInfo)) {
            fprintf(stderr, "error: failed to execute %s\n", commandLine.c_str());
            return 1;
        }

        hProcess = processInfo.hProcess;
    }

    /*
     * XXX: Mixed architecture don't quite work.  See also
     * http://www.corsix.org/content/dll-injection-and-wow64
     */
    {
        typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
        PFNISWOW64PROCESS pfnIsWow64Process;
        pfnIsWow64Process = (PFNISWOW64PROCESS)
            GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
        if (pfnIsWow64Process) {
            BOOL isParentWow64 = FALSE;
            BOOL isChildWow64 = FALSE;
            if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) &&
                pfnIsWow64Process(hProcess, &isChildWow64) &&
                isParentWow64 != isChildWow64) {
                fprintf(stderr, "error: binaries mismatch: you need to use the "
#ifdef _WIN64
                        "32-bits"
#else
                        "64-bits"
#endif
                        " apitrace binaries to trace this application\n");
                TerminateProcess(hProcess, 1);
                return 1;
            }
        }
    }

    const char *szDllName;
    szDllName = "injectee.dll";

    char szDllPath[MAX_PATH];
    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
    getDirName(szDllPath);
    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);

    const char *szError = NULL;
    if (!injectDll(hProcess, szDllPath, &szError)) {
        fprintf(stderr, "error: %s\n", szError);
        TerminateProcess(hProcess, 1);
        return 1;
    }

    if (bAttach) {
        return 0;
    }

    // Start main process thread
    ResumeThread(processInfo.hThread);

    // Wait for it to finish
    WaitForSingleObject(hProcess, INFINITE);

    if (pSharedMem && !pSharedMem->bReplaced) {
        fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll);
    }

    DWORD exitCode = ~0;
    GetExitCodeProcess(hProcess, &exitCode);

    CloseHandle(hProcess);
    CloseHandle(processInfo.hThread);

    return (int)exitCode;
}
<commit_msg>inject: Use a semaphore to prevent multiple runs of inject to interfere with each other.<commit_after>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Main program to start and inject a DLL into a process via a remote thread.
 *
 * For background see:
 * - http://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows
 * - http://www.codeproject.com/KB/threads/completeinject.aspx
 * - http://www.codeproject.com/KB/threads/winspy.aspx
 * - http://www.codeproject.com/KB/DLL/DLL_Injection_tutorial.aspx
 * - http://www.codeproject.com/KB/threads/APIHooking.aspx
 *
 * Other slightly different techniques:
 * - http://www.fr33project.org/pages/projects/phook.htm
 * - http://www.hbgary.com/loading-a-dll-without-calling-loadlibrary
 * - http://securityxploded.com/ntcreatethreadex.php
 */

#include <string>

#include <windows.h>
#include <stdio.h>

#include "inject.h"

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

int
main(int argc, char *argv[])
{
    if (argc < 3) {
        fprintf(stderr, "inject dllname.dll command [args] ...\n");
        return 1;
    }

    HANDLE hSemaphore = NULL;
    const char *szDll = argv[1];
    if (!USE_SHARED_MEM) {
        SetEnvironmentVariableA("INJECT_DLL", szDll);
    } else {
        hSemaphore = CreateSemaphore(NULL, 1, 1, "inject_semaphore");
        if (hSemaphore == NULL) {
            fprintf(stderr, "error: failed to create semaphore\n");
            return 1;
        }

        DWORD dwWait = WaitForSingleObject(hSemaphore, 0);
        if (dwWait == WAIT_TIMEOUT) {
            fprintf(stderr, "info: waiting for another inject instance to finish\n");
            dwWait = WaitForSingleObject(hSemaphore, INFINITE);
        }
        if (dwWait != WAIT_OBJECT_0) {
            fprintf(stderr, "error: failed to enter semaphore gate\n");
            return 1;
        }

        SetSharedMem(szDll);
    }

    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    BOOL bAttach;
    if (isdigit(argv[2][0])) {
        bAttach = TRUE;

        BOOL bRet;
        HANDLE hToken   = NULL;
        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
        if (!bRet) {
            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
            return 1;
        }

        LUID Luid;
        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
        if (!bRet) {
            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
            return 1;
        }

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = Luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
        if (!bRet) {
            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
            return 1;
        }

        DWORD dwDesiredAccess =
            PROCESS_CREATE_THREAD |
            PROCESS_QUERY_INFORMATION |
            PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_VM_OPERATION |
            PROCESS_VM_WRITE |
            PROCESS_VM_READ;
        DWORD dwProcessId = atol(argv[2]);
        hProcess = OpenProcess(
            dwDesiredAccess,
            FALSE /* bInheritHandle */,
            dwProcessId);
        if (!hProcess) {
            DWORD dwLastError = GetLastError();
            fprintf(stderr, "error: failed to open process %lu (%lu)\n", dwProcessId, dwLastError);
            return 1;
        }
    } else {
        bAttach = FALSE;
        std::string commandLine;
        char sep = 0;
        for (int i = 2; i < argc; ++i) {
            const char *arg = argv[i];

            if (sep) {
                commandLine.push_back(sep);
            }

            if (needsQuote(arg)) {
                quoteArg(commandLine, arg);
            } else {
                commandLine.append(arg);
            }

            sep = ' ';
        }

        STARTUPINFO startupInfo;
        memset(&startupInfo, 0, sizeof startupInfo);
        startupInfo.cb = sizeof startupInfo;

        // Create the process in suspended state
        if (!CreateProcessA(
               NULL,
               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
               0, // process attributes
               0, // thread attributes
               TRUE, // inherit handles
               CREATE_SUSPENDED,
               NULL, // environment
               NULL, // current directory
               &startupInfo,
               &processInfo)) {
            fprintf(stderr, "error: failed to execute %s\n", commandLine.c_str());
            return 1;
        }

        hProcess = processInfo.hProcess;
    }

    /*
     * XXX: Mixed architecture don't quite work.  See also
     * http://www.corsix.org/content/dll-injection-and-wow64
     */
    {
        typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
        PFNISWOW64PROCESS pfnIsWow64Process;
        pfnIsWow64Process = (PFNISWOW64PROCESS)
            GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
        if (pfnIsWow64Process) {
            BOOL isParentWow64 = FALSE;
            BOOL isChildWow64 = FALSE;
            if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) &&
                pfnIsWow64Process(hProcess, &isChildWow64) &&
                isParentWow64 != isChildWow64) {
                fprintf(stderr, "error: binaries mismatch: you need to use the "
#ifdef _WIN64
                        "32-bits"
#else
                        "64-bits"
#endif
                        " apitrace binaries to trace this application\n");
                TerminateProcess(hProcess, 1);
                return 1;
            }
        }
    }

    const char *szDllName;
    szDllName = "injectee.dll";

    char szDllPath[MAX_PATH];
    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
    getDirName(szDllPath);
    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);

    const char *szError = NULL;
    if (!injectDll(hProcess, szDllPath, &szError)) {
        fprintf(stderr, "error: %s\n", szError);
        TerminateProcess(hProcess, 1);
        return 1;
    }

    if (bAttach) {
        return 0;
    }

    // Start main process thread
    ResumeThread(processInfo.hThread);

    // Wait for it to finish
    WaitForSingleObject(hProcess, INFINITE);

    if (pSharedMem && !pSharedMem->bReplaced) {
        fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll);
    }

    DWORD exitCode = ~0;
    GetExitCodeProcess(hProcess, &exitCode);

    CloseHandle(hProcess);
    CloseHandle(processInfo.hThread);

    if (hSemaphore) {
        ReleaseSemaphore(hSemaphore, 1, NULL);
        CloseHandle(hSemaphore);
    }

    return (int)exitCode;
}
<|endoftext|>


<commit_before>/*
    Empath - Mailer for KDE

    Copyright 1999, 2000
        Rik Hemsley <rik@kde.org>
        Wilco Greven <j.w.greven@student.utwente.nl>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

// System includes
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

// KDE includes
#include <kuniqueapp.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kcmdlineargs.h>

// Local includes
#include "Empath.h"
#include "EmpathUI.h"

static const char* description=I18N_NOOP("Empath, the KDE Mail Client");
static const char* VERSION="0.0.1";

    int
main(int argc, char ** argv)
{
    KAboutData aboutData( "empath", I18N_NOOP("Empath"),
        VERSION, description, KAboutData::License_GPL,
        "(c) 1999-2000, The Empath Team");
    aboutData.addAuthor("Rik Hemsley",0, "rik@kde.org");
    aboutData.addAuthor("Wilco Greven",0, "j.w.greven@student.utwente.nl");
    KCmdLineArgs::init( argc, argv, &aboutData );

    // Don't do anything if we're being run as root.
    if (getuid() == 0 || geteuid() == 0) {
        fprintf(stderr, "DO NOT RUN GUI APPS AS ROOT !\n");
        return 1;
    }

    // Pick a sensible umask for everything Empath does.
    int prev_umask = umask(077);

#define DOSOMEDOSOMEDOSOME
#ifdef DOSOMEDOSOMEDOSOME

    if (!KUniqueApplication::start())
        exit(0);

    KUniqueApplication app;

#else

    KApplication app;

#endif

    // Create the kernel.
    Empath::start();

    // Create the user interface.
    EmpathUI * ui = new EmpathUI;

    // Attempt to get the UI up and running quickly.
    app.processEvents();

    // Initialise the kernel.
    empath->init();

    // Enter the event loop.
    int retval = app.exec();

    delete ui;
    ui = 0;

    empath->shutdown();

    // Restore umask.
    umask(prev_umask);

    return retval;
}

// vim:ts=4:sw=4:tw=78
<commit_msg>This one needed License_GPL changing to just GPL too<commit_after>/*
    Empath - Mailer for KDE

    Copyright 1999, 2000
        Rik Hemsley <rik@kde.org>
        Wilco Greven <j.w.greven@student.utwente.nl>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

// System includes
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

// KDE includes
#include <kuniqueapp.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kcmdlineargs.h>

// Local includes
#include "Empath.h"
#include "EmpathUI.h"

static const char* description=I18N_NOOP("Empath, the KDE Mail Client");
static const char* VERSION="0.0.1";

    int
main(int argc, char ** argv)
{
    KAboutData aboutData( "empath", I18N_NOOP("Empath"),
        VERSION, description, KAboutData::GPL,
        "(c) 1999-2000, The Empath Team");
    aboutData.addAuthor("Rik Hemsley",0, "rik@kde.org");
    aboutData.addAuthor("Wilco Greven",0, "j.w.greven@student.utwente.nl");
    KCmdLineArgs::init( argc, argv, &aboutData );

    // Don't do anything if we're being run as root.
    if (getuid() == 0 || geteuid() == 0) {
        fprintf(stderr, "DO NOT RUN GUI APPS AS ROOT !\n");
        return 1;
    }

    // Pick a sensible umask for everything Empath does.
    int prev_umask = umask(077);

#define DOSOMEDOSOMEDOSOME
#ifdef DOSOMEDOSOMEDOSOME

    if (!KUniqueApplication::start())
        exit(0);

    KUniqueApplication app;

#else

    KApplication app;

#endif

    // Create the kernel.
    Empath::start();

    // Create the user interface.
    EmpathUI * ui = new EmpathUI;

    // Attempt to get the UI up and running quickly.
    app.processEvents();

    // Initialise the kernel.
    empath->init();

    // Enter the event loop.
    int retval = app.exec();

    delete ui;
    ui = 0;

    empath->shutdown();

    // Restore umask.
    umask(prev_umask);

    return retval;
}

// vim:ts=4:sw=4:tw=78
<|endoftext|>


<commit_before>#include <string>
#include <memory>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>

#include "model/feature_cache.h"

using namespace std;

namespace redgiant {
class FeatureCacheTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(FeatureCacheTest);
  CPPUNIT_TEST(test_create_feature_space);
  CPPUNIT_TEST(test_create_feature);
  CPPUNIT_TEST(test_get_feature);
  CPPUNIT_TEST_SUITE_END();

public:
  FeatureCacheTest() = default;
  virtual ~FeatureCacheTest() = default;

protected:
  void test_create_feature_space() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::FeatureType::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::FeatureType::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::FeatureType::kInteger);

    CPPUNIT_ASSERT(!!space_a); // not null
    CPPUNIT_ASSERT(!!space_b); // not null
    CPPUNIT_ASSERT(!!space_c); // not null

    auto aa = cache->get_space("A");
    CPPUNIT_ASSERT(space_a == aa);
    CPPUNIT_ASSERT_EQUAL(1ULL, (unsigned long long)(aa->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("A"), aa->get_name());

    auto bb = cache->get_space("BB");
    CPPUNIT_ASSERT(space_b == bb);
    CPPUNIT_ASSERT_EQUAL(2ULL, (unsigned long long)(bb->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("BB"), bb->get_name());

    // replace "A"
    auto space_d = cache->create_space("A", 4, FeatureSpace::FeatureType::kString);
    auto dd = cache->get_space("A");
    CPPUNIT_ASSERT(!!space_d); // not null
    CPPUNIT_ASSERT(space_d == dd);
    CPPUNIT_ASSERT_EQUAL(4ULL, (unsigned long long)(dd->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("A"), dd->get_name());
  }

  void test_create_feature() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::FeatureType::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::FeatureType::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::FeatureType::kInteger);

    auto f1 = cache->create_or_get_feature("111", "A");
    auto f2 = cache->create_or_get_feature("xxx", space_b);
    auto f3 = cache->create_or_get_feature("yyy", space_c);

    CPPUNIT_ASSERT(!!f1); // not null
    CPPUNIT_ASSERT_EQUAL(string("111"), f1->get_key());
    CPPUNIT_ASSERT_EQUAL(111ULL, FeatureSpace::get_part_feature_id(f1->get_id()));

    CPPUNIT_ASSERT(!!f2); // not null
    CPPUNIT_ASSERT_EQUAL(string("xxx"), f2->get_key());
    CPPUNIT_ASSERT(f2->get_id() != FeatureSpace::kInvalidId);

    CPPUNIT_ASSERT(!f3); // null
  }

  void test_get_feature() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::kInteger);

    auto f1 = cache->create_or_get_feature("111", "A");
    auto f2 = cache->create_or_get_feature("xxx", space_b);
    auto f3 = cache->create_or_get_feature("222", space_c);
    auto f4 = cache->create_or_get_feature("222", "CCC");

    CPPUNIT_ASSERT(f3 == f4); // null
    CPPUNIT_ASSERT_EQUAL(string("222"), f4->get_key());
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(FeatureCacheTest);
} /* namespace redgiant */
<commit_msg>fix unit test<commit_after>#include <string>
#include <memory>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>

#include "model/feature_cache.h"

using namespace std;

namespace redgiant {
class FeatureCacheTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(FeatureCacheTest);
  CPPUNIT_TEST(test_create_feature_space);
  CPPUNIT_TEST(test_create_feature);
  CPPUNIT_TEST(test_get_feature);
  CPPUNIT_TEST_SUITE_END();

public:
  FeatureCacheTest() = default;
  virtual ~FeatureCacheTest() = default;

protected:
  void test_create_feature_space() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::FeatureType::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::FeatureType::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::FeatureType::kInteger);

    CPPUNIT_ASSERT(!!space_a); // not null
    CPPUNIT_ASSERT(!!space_b); // not null
    CPPUNIT_ASSERT(!!space_c); // not null

    auto aa = cache->get_space("A");
    CPPUNIT_ASSERT(space_a == aa);
    CPPUNIT_ASSERT_EQUAL(1ULL, (unsigned long long)(aa->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("A"), aa->get_name());

    auto bb = cache->get_space("BB");
    CPPUNIT_ASSERT(space_b == bb);
    CPPUNIT_ASSERT_EQUAL(2ULL, (unsigned long long)(bb->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("BB"), bb->get_name());

    // replace "A"
    auto space_d = cache->create_space("A", 4, FeatureSpace::FeatureType::kString);
    auto dd = cache->get_space("A");
    CPPUNIT_ASSERT(!!space_d); // not null
    CPPUNIT_ASSERT(space_d == dd);
    CPPUNIT_ASSERT_EQUAL(4ULL, (unsigned long long)(dd->get_id()));
    CPPUNIT_ASSERT_EQUAL(string("A"), dd->get_name());
  }

  void test_create_feature() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::FeatureType::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::FeatureType::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::FeatureType::kInteger);

    auto f1 = cache->create_or_get_feature("111", "A");
    auto f2 = cache->create_or_get_feature("xxx", space_b);
    auto f3 = cache->create_or_get_feature("yyy", space_c);

    CPPUNIT_ASSERT(!!f1); // not null
    CPPUNIT_ASSERT_EQUAL(string("111"), f1->get_key());
    CPPUNIT_ASSERT_EQUAL(111ULL, (unsigned long long)FeatureSpace::get_part_feature_id(f1->get_id()));

    CPPUNIT_ASSERT(!!f2); // not null
    CPPUNIT_ASSERT_EQUAL(string("xxx"), f2->get_key());
    CPPUNIT_ASSERT(f2->get_id() != FeatureSpace::kInvalidId);

    CPPUNIT_ASSERT(!f3); // null
  }

  void test_get_feature() {
    auto cache = std::unique_ptr<FeatureCache>(new FeatureCache());
    auto space_a = cache->create_space("A", 1, FeatureSpace::kInteger);
    auto space_b = cache->create_space("BB", 2, FeatureSpace::kString);
    auto space_c = cache->create_space("CCC", 3, FeatureSpace::kInteger);

    auto f1 = cache->create_or_get_feature("111", "A");
    auto f2 = cache->create_or_get_feature("xxx", space_b);
    auto f3 = cache->create_or_get_feature("222", space_c);
    auto f4 = cache->create_or_get_feature("222", "CCC");

    CPPUNIT_ASSERT(f3 == f4); // null
    CPPUNIT_ASSERT_EQUAL(string("222"), f4->get_key());
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(FeatureCacheTest);
} /* namespace redgiant */
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.cpp
 * @author Marek Kotewicz <marek@ethdev.com>
 * @date 2014
 */

// @debris disabled as tests fail with:
// unknown location(0): fatal error in "jsonrpc_setMining": std::exception: Exception -32003 : Client connector error: : libcurl error: 28
// /home/gav/Eth/cpp-ethereum/test/jsonrpc.cpp(169): last checkpoint
#if ETH_JSONRPC && 0

#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
//#include <json/json.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#include <set>
#include "JsonSpiritHeaders.h"
#include "TestHelper.h"
#include "webthreestubclient.h"

BOOST_AUTO_TEST_SUITE(jsonrpc)

using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;

WebThreeDirect* web3;
unique_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<WebThreeStubClient> jsonrpcClient;

struct Setup
{
	Setup()
	{
		static bool setup = false;
		if (setup)
			return;
		setup = true;

		dev::p2p::NetworkPreferences nprefs(30303, std::string(), false);
		web3 = new WebThreeDirect("Ethereum(++) tests", "", true, {"eth", "shh"}, nprefs);

		web3->setIdealPeerCount(5);
		web3->ethereum()->setForceMining(true);
		auto server = new jsonrpc::HttpServer(8080);
		jsonrpcServer = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(*server, *web3, {}));
		jsonrpcServer->setIdentities({});
		jsonrpcServer->StartListening();
		auto client = new jsonrpc::HttpClient("http://localhost:8080");
		jsonrpcClient = unique_ptr<WebThreeStubClient>(new WebThreeStubClient(*client));
	}
};

string fromAscii(string _s)
{
	bytes b = asBytes(_s);
	return "0x" + toHex(b);
}

BOOST_FIXTURE_TEST_SUITE(environment, Setup)

BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock)
{
	cnote << "Testing jsonrpc defaultBlock...";
	int defaultBlock = jsonrpcClient->eth_defaultBlock();
	BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault());
}

BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice)
{
	cnote << "Testing jsonrpc gasPrice...";
	string gasPrice = jsonrpcClient->eth_gasPrice();
	BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo));
}

BOOST_AUTO_TEST_CASE(jsonrpc_isListening)
{
	cnote << "Testing jsonrpc isListening...";

	web3->startNetwork();
	bool listeningOn = jsonrpcClient->eth_listening();
	BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted());

	web3->stopNetwork();
	bool listeningOff = jsonrpcClient->eth_listening();
	BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted());
}

BOOST_AUTO_TEST_CASE(jsonrpc_isMining)
{
	cnote << "Testing jsonrpc isMining...";

	web3->ethereum()->startMining();
	bool miningOn = jsonrpcClient->eth_mining();
	BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining());

	web3->ethereum()->stopMining();
	bool miningOff = jsonrpcClient->eth_mining();
	BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining());
}

BOOST_AUTO_TEST_CASE(jsonrpc_accounts)
{
	cnote << "Testing jsonrpc accounts...";
	std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()};
	jsonrpcServer->setAccounts(keys);
	Json::Value k = jsonrpcClient->eth_accounts();
	jsonrpcServer->setAccounts({});
	BOOST_CHECK_EQUAL(k.isArray(), true);
	BOOST_CHECK_EQUAL(k.size(),  keys.size());
	for (auto &i:k)
	{
		auto it = std::find_if(keys.begin(), keys.end(), [i](dev::KeyPair const& keyPair)
		{
			return jsToAddress(i.asString()) == keyPair.address();
		});
		BOOST_CHECK_EQUAL(it != keys.end(), true);
	}
}

BOOST_AUTO_TEST_CASE(jsonrpc_number)
{
	cnote << "Testing jsonrpc number2...";
	int number = jsonrpcClient->eth_number();
	BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1);
	dev::eth::mine(*(web3->ethereum()), 1);
	int numberAfter = jsonrpcClient->eth_number();
	BOOST_CHECK_EQUAL(number + 1, numberAfter);
	BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1);
}

BOOST_AUTO_TEST_CASE(jsonrpc_peerCount)
{
	cnote << "Testing jsonrpc peerCount...";
	int peerCount = jsonrpcClient->eth_peerCount();
	BOOST_CHECK_EQUAL(web3->peerCount(), peerCount);
}

BOOST_AUTO_TEST_CASE(jsonrpc_setListening)
{
	cnote << "Testing jsonrpc setListening...";

	jsonrpcClient->eth_setListening(true);
	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true);

	jsonrpcClient->eth_setListening(false);
	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false);
}

BOOST_AUTO_TEST_CASE(jsonrpc_setMining)
{
	cnote << "Testing jsonrpc setMining...";

	jsonrpcClient->eth_setMining(true);
	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true);

	jsonrpcClient->eth_setMining(false);
	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false);
}

BOOST_AUTO_TEST_CASE(jsonrpc_stateAt)
{
	cnote << "Testing jsonrpc stateAt...";
	dev::KeyPair key = KeyPair::create();
	auto address = key.address();
	string stateAt = jsonrpcClient->eth_stateAt(toJS(address), "0");
	BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt);
}

BOOST_AUTO_TEST_CASE(jsonrpc_transact)
{
	cnote << "Testing jsonrpc transact...";
	string coinbase = jsonrpcClient->eth_coinbase();
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());

	dev::KeyPair key = KeyPair::create();
	auto address = key.address();
	auto receiver = KeyPair::create();
	web3->ethereum()->setAddress(address);

	coinbase = jsonrpcClient->eth_coinbase();
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), address);

	jsonrpcServer->setAccounts({key});
	auto balance = web3->ethereum()->balanceAt(address, 0);
	string balanceString = jsonrpcClient->eth_balanceAt(toJS(address));
	double countAt = jsonrpcClient->eth_countAt(toJS(address));

	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
	BOOST_CHECK_EQUAL(countAt, 0);
	BOOST_CHECK_EQUAL(toJS(balance), balanceString);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "0");

	dev::eth::mine(*(web3->ethereum()), 1);
	balance = web3->ethereum()->balanceAt(address, 0);
	balanceString = jsonrpcClient->eth_balanceAt(toJS(address));

	BOOST_CHECK_EQUAL(toJS(balance), balanceString);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000");

	auto txAmount = balance / 2u;
	auto gasPrice = 10 * dev::eth::szabo;
	auto gas = dev::eth::c_txGas;

	Json::Value t;
	t["from"] = toJS(address);
	t["value"] = jsToDecimal(toJS(txAmount));
	t["to"] = toJS(receiver.address());
	t["data"] = toJS(bytes());
	t["gas"] = toJS(gas);
	t["gasPrice"] = toJS(gasPrice);

	jsonrpcClient->eth_transact(t);
	jsonrpcServer->setAccounts({});
	dev::eth::mine(*(web3->ethereum()), 1);

	countAt = jsonrpcClient->eth_countAt(toJS(address));
	auto balance2 = web3->ethereum()->balanceAt(receiver.address());
	string balanceString2 = jsonrpcClient->eth_balanceAt(toJS(receiver.address()));

	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
	BOOST_CHECK_EQUAL(countAt, 1);
	BOOST_CHECK_EQUAL(toJS(balance2), balanceString2);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString2), "750000000000000000");
	BOOST_CHECK_EQUAL(txAmount, balance2);
}

BOOST_AUTO_TEST_CASE(simple_contract)
{
	cnote << "Testing jsonrpc contract...";
	KeyPair kp = KeyPair::create();
	web3->ethereum()->setAddress(kp.address());
	jsonrpcServer->setAccounts({kp});

	dev::eth::mine(*(web3->ethereum()), 1);

	char const* sourceCode = "contract test {\n"
	"  function f(uint a) returns(uint d) { return a * 7; }\n"
	"}\n";

	string compiled = jsonrpcClient->eth_solidity(sourceCode);

	Json::Value create;
	create["code"] = compiled;
	string contractAddress = jsonrpcClient->eth_transact(create);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value call;
	call["to"] = contractAddress;
	call["data"] = "0x00000000000000000000000000000000000000000000000000000000000000001";
	string result = jsonrpcClient->eth_call(call);
	BOOST_CHECK_EQUAL(result, "0x0000000000000000000000000000000000000000000000000000000000000007");
}

BOOST_AUTO_TEST_CASE(contract_storage)
{
	cnote << "Testing jsonrpc contract storage...";
	KeyPair kp = KeyPair::create();
	web3->ethereum()->setAddress(kp.address());
	jsonrpcServer->setAccounts({kp});

	dev::eth::mine(*(web3->ethereum()), 1);

	char const* sourceCode = R"(
		contract test {
			uint hello;
			function writeHello(uint value)  returns(bool d){
				hello = value;
				return true;
			}
		}
	)";

	string compiled = jsonrpcClient->eth_solidity(sourceCode);

	Json::Value create;
	create["code"] = compiled;
	string contractAddress = jsonrpcClient->eth_transact(create);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value transact;
	transact["to"] = contractAddress;
	transact["data"] = "0x00000000000000000000000000000000000000000000000000000000000000003";
	jsonrpcClient->eth_transact(transact);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value storage = jsonrpcClient->eth_storageAt(contractAddress);
	BOOST_CHECK_EQUAL(storage.getMemberNames().size(), 1);
	// bracers are required, cause msvc couldnt handle this macro in for statement
	for (auto name: storage.getMemberNames())
	{
		BOOST_CHECK_EQUAL(storage[name].asString(), "0x03");
	}
}

BOOST_AUTO_TEST_CASE(sha3)
{
	cnote << "Testing jsonrpc sha3...";
	string testString = "multiply(uint256)";
	h256 expected = dev::sha3(testString);

	auto hexValue = fromAscii(testString);
	string result = jsonrpcClient->web3_sha3(hexValue);
	BOOST_CHECK_EQUAL(toJS(expected), result);
	BOOST_CHECK_EQUAL("0xc6888fa159d67f77c2f3d7a402e199802766bd7e8d4d1ecd2274fc920265d56a", result);
}

BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()

#endif
<commit_msg>removed CorsHTTPServer<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.cpp
 * @author Marek Kotewicz <marek@ethdev.com>
 * @date 2014
 */

// @debris disabled as tests fail with:
// unknown location(0): fatal error in "jsonrpc_setMining": std::exception: Exception -32003 : Client connector error: : libcurl error: 28
// /home/gav/Eth/cpp-ethereum/test/jsonrpc.cpp(169): last checkpoint
#if ETH_JSONRPC && 0

#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#include <set>
#include "JsonSpiritHeaders.h"
#include "TestHelper.h"
#include "webthreestubclient.h"

BOOST_AUTO_TEST_SUITE(jsonrpc)

using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;

WebThreeDirect* web3;
unique_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<WebThreeStubClient> jsonrpcClient;

struct Setup
{
	Setup()
	{
		static bool setup = false;
		if (setup)
			return;
		setup = true;

		dev::p2p::NetworkPreferences nprefs(30303, std::string(), false);
		web3 = new WebThreeDirect("Ethereum(++) tests", "", true, {"eth", "shh"}, nprefs);

		web3->setIdealPeerCount(5);
		web3->ethereum()->setForceMining(true);
		auto server = new jsonrpc::HttpServer(8080);
		jsonrpcServer = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(*server, *web3, {}));
		jsonrpcServer->setIdentities({});
		jsonrpcServer->StartListening();
		auto client = new jsonrpc::HttpClient("http://localhost:8080");
		jsonrpcClient = unique_ptr<WebThreeStubClient>(new WebThreeStubClient(*client));
	}
};

string fromAscii(string _s)
{
	bytes b = asBytes(_s);
	return "0x" + toHex(b);
}

BOOST_FIXTURE_TEST_SUITE(environment, Setup)

BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock)
{
	cnote << "Testing jsonrpc defaultBlock...";
	int defaultBlock = jsonrpcClient->eth_defaultBlock();
	BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault());
}

BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice)
{
	cnote << "Testing jsonrpc gasPrice...";
	string gasPrice = jsonrpcClient->eth_gasPrice();
	BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo));
}

BOOST_AUTO_TEST_CASE(jsonrpc_isListening)
{
	cnote << "Testing jsonrpc isListening...";

	web3->startNetwork();
	bool listeningOn = jsonrpcClient->eth_listening();
	BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted());

	web3->stopNetwork();
	bool listeningOff = jsonrpcClient->eth_listening();
	BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted());
}

BOOST_AUTO_TEST_CASE(jsonrpc_isMining)
{
	cnote << "Testing jsonrpc isMining...";

	web3->ethereum()->startMining();
	bool miningOn = jsonrpcClient->eth_mining();
	BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining());

	web3->ethereum()->stopMining();
	bool miningOff = jsonrpcClient->eth_mining();
	BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining());
}

BOOST_AUTO_TEST_CASE(jsonrpc_accounts)
{
	cnote << "Testing jsonrpc accounts...";
	std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()};
	jsonrpcServer->setAccounts(keys);
	Json::Value k = jsonrpcClient->eth_accounts();
	jsonrpcServer->setAccounts({});
	BOOST_CHECK_EQUAL(k.isArray(), true);
	BOOST_CHECK_EQUAL(k.size(),  keys.size());
	for (auto &i:k)
	{
		auto it = std::find_if(keys.begin(), keys.end(), [i](dev::KeyPair const& keyPair)
		{
			return jsToAddress(i.asString()) == keyPair.address();
		});
		BOOST_CHECK_EQUAL(it != keys.end(), true);
	}
}

BOOST_AUTO_TEST_CASE(jsonrpc_number)
{
	cnote << "Testing jsonrpc number2...";
	int number = jsonrpcClient->eth_number();
	BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1);
	dev::eth::mine(*(web3->ethereum()), 1);
	int numberAfter = jsonrpcClient->eth_number();
	BOOST_CHECK_EQUAL(number + 1, numberAfter);
	BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1);
}

BOOST_AUTO_TEST_CASE(jsonrpc_peerCount)
{
	cnote << "Testing jsonrpc peerCount...";
	int peerCount = jsonrpcClient->eth_peerCount();
	BOOST_CHECK_EQUAL(web3->peerCount(), peerCount);
}

BOOST_AUTO_TEST_CASE(jsonrpc_setListening)
{
	cnote << "Testing jsonrpc setListening...";

	jsonrpcClient->eth_setListening(true);
	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true);

	jsonrpcClient->eth_setListening(false);
	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false);
}

BOOST_AUTO_TEST_CASE(jsonrpc_setMining)
{
	cnote << "Testing jsonrpc setMining...";

	jsonrpcClient->eth_setMining(true);
	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true);

	jsonrpcClient->eth_setMining(false);
	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false);
}

BOOST_AUTO_TEST_CASE(jsonrpc_stateAt)
{
	cnote << "Testing jsonrpc stateAt...";
	dev::KeyPair key = KeyPair::create();
	auto address = key.address();
	string stateAt = jsonrpcClient->eth_stateAt(toJS(address), "0");
	BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt);
}

BOOST_AUTO_TEST_CASE(jsonrpc_transact)
{
	cnote << "Testing jsonrpc transact...";
	string coinbase = jsonrpcClient->eth_coinbase();
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());

	dev::KeyPair key = KeyPair::create();
	auto address = key.address();
	auto receiver = KeyPair::create();
	web3->ethereum()->setAddress(address);

	coinbase = jsonrpcClient->eth_coinbase();
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());
	BOOST_CHECK_EQUAL(jsToAddress(coinbase), address);

	jsonrpcServer->setAccounts({key});
	auto balance = web3->ethereum()->balanceAt(address, 0);
	string balanceString = jsonrpcClient->eth_balanceAt(toJS(address));
	double countAt = jsonrpcClient->eth_countAt(toJS(address));

	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
	BOOST_CHECK_EQUAL(countAt, 0);
	BOOST_CHECK_EQUAL(toJS(balance), balanceString);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "0");

	dev::eth::mine(*(web3->ethereum()), 1);
	balance = web3->ethereum()->balanceAt(address, 0);
	balanceString = jsonrpcClient->eth_balanceAt(toJS(address));

	BOOST_CHECK_EQUAL(toJS(balance), balanceString);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000");

	auto txAmount = balance / 2u;
	auto gasPrice = 10 * dev::eth::szabo;
	auto gas = dev::eth::c_txGas;

	Json::Value t;
	t["from"] = toJS(address);
	t["value"] = jsToDecimal(toJS(txAmount));
	t["to"] = toJS(receiver.address());
	t["data"] = toJS(bytes());
	t["gas"] = toJS(gas);
	t["gasPrice"] = toJS(gasPrice);

	jsonrpcClient->eth_transact(t);
	jsonrpcServer->setAccounts({});
	dev::eth::mine(*(web3->ethereum()), 1);

	countAt = jsonrpcClient->eth_countAt(toJS(address));
	auto balance2 = web3->ethereum()->balanceAt(receiver.address());
	string balanceString2 = jsonrpcClient->eth_balanceAt(toJS(receiver.address()));

	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
	BOOST_CHECK_EQUAL(countAt, 1);
	BOOST_CHECK_EQUAL(toJS(balance2), balanceString2);
	BOOST_CHECK_EQUAL(jsToDecimal(balanceString2), "750000000000000000");
	BOOST_CHECK_EQUAL(txAmount, balance2);
}

BOOST_AUTO_TEST_CASE(simple_contract)
{
	cnote << "Testing jsonrpc contract...";
	KeyPair kp = KeyPair::create();
	web3->ethereum()->setAddress(kp.address());
	jsonrpcServer->setAccounts({kp});

	dev::eth::mine(*(web3->ethereum()), 1);

	char const* sourceCode = "contract test {\n"
	"  function f(uint a) returns(uint d) { return a * 7; }\n"
	"}\n";

	string compiled = jsonrpcClient->eth_solidity(sourceCode);

	Json::Value create;
	create["code"] = compiled;
	string contractAddress = jsonrpcClient->eth_transact(create);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value call;
	call["to"] = contractAddress;
	call["data"] = "0x00000000000000000000000000000000000000000000000000000000000000001";
	string result = jsonrpcClient->eth_call(call);
	BOOST_CHECK_EQUAL(result, "0x0000000000000000000000000000000000000000000000000000000000000007");
}

BOOST_AUTO_TEST_CASE(contract_storage)
{
	cnote << "Testing jsonrpc contract storage...";
	KeyPair kp = KeyPair::create();
	web3->ethereum()->setAddress(kp.address());
	jsonrpcServer->setAccounts({kp});

	dev::eth::mine(*(web3->ethereum()), 1);

	char const* sourceCode = R"(
		contract test {
			uint hello;
			function writeHello(uint value)  returns(bool d){
				hello = value;
				return true;
			}
		}
	)";

	string compiled = jsonrpcClient->eth_solidity(sourceCode);

	Json::Value create;
	create["code"] = compiled;
	string contractAddress = jsonrpcClient->eth_transact(create);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value transact;
	transact["to"] = contractAddress;
	transact["data"] = "0x00000000000000000000000000000000000000000000000000000000000000003";
	jsonrpcClient->eth_transact(transact);
	dev::eth::mine(*(web3->ethereum()), 1);

	Json::Value storage = jsonrpcClient->eth_storageAt(contractAddress);
	BOOST_CHECK_EQUAL(storage.getMemberNames().size(), 1);
	// bracers are required, cause msvc couldnt handle this macro in for statement
	for (auto name: storage.getMemberNames())
	{
		BOOST_CHECK_EQUAL(storage[name].asString(), "0x03");
	}
}

BOOST_AUTO_TEST_CASE(sha3)
{
	cnote << "Testing jsonrpc sha3...";
	string testString = "multiply(uint256)";
	h256 expected = dev::sha3(testString);

	auto hexValue = fromAscii(testString);
	string result = jsonrpcClient->web3_sha3(hexValue);
	BOOST_CHECK_EQUAL(toJS(expected), result);
	BOOST_CHECK_EQUAL("0xc6888fa159d67f77c2f3d7a402e199802766bd7e8d4d1ecd2274fc920265d56a", result);
}

BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()

#endif
<|endoftext|>


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

#include <thrift/lib/cpp2/transport/http2/common/HTTP2RoutingHandler.h>

#include <proxygen/httpserver/HTTPServerAcceptor.h>
#include <proxygen/httpserver/HTTPServerOptions.h>
#include <proxygen/lib/http/session/HTTPDefaultSessionCodecFactory.h>
#include <proxygen/lib/http/session/HTTPDownstreamSession.h>
#include <proxygen/lib/http/session/HTTPSession.h>
#include <proxygen/lib/http/session/SimpleController.h>

#include <wangle/acceptor/ManagedConnection.h>

namespace apache {
namespace thrift {

namespace {

// Class for managing lifetime of objects supporting an HTTP2 session.
class HTTP2RoutingSessionManager
    : public proxygen::HTTPSession::EmptyInfoCallback {
 public:
  ~HTTP2RoutingSessionManager() = default;
  proxygen::HTTPDownstreamSession* CreateSession(
      proxygen::HTTPServerOptions* options,
      folly::AsyncTransportWrapper::UniquePtr sock,
      folly::SocketAddress* peerAddress,
      wangle::TransportInfo const& tinfo) {
    // Create the SimpleController
    auto ipConfig = proxygen::HTTPServer::IPConfig(
        *peerAddress, proxygen::HTTPServer::Protocol::HTTP2);
    auto acceptorConfig =
        proxygen::HTTPServerAcceptor::makeConfig(ipConfig, *options);
    serverAcceptor_ =
        proxygen::HTTPServerAcceptor::make(acceptorConfig, *options);
    controller_ = new proxygen::SimpleController(serverAcceptor_.get());

    // Get the HTTP2 Codec
    auto codecFactory =
        proxygen::HTTPDefaultSessionCodecFactory(acceptorConfig);
    auto h2codec =
        codecFactory.getCodec("h2", proxygen::TransportDirection::DOWNSTREAM);

    // Obtain the proper routing address
    folly::SocketAddress localAddress;
    try {
      sock->getLocalAddress(&localAddress);
    } catch (...) {
      VLOG(3) << "couldn't get local address for socket";
      localAddress = folly::SocketAddress("0.0.0.0", 0);
    }
    VLOG(4) << "Created new session for peer " << *peerAddress;

    // Create the DownstreamSession
    auto session = new proxygen::HTTPDownstreamSession(
        proxygen::WheelTimerInstance(std::chrono::milliseconds(5)),
        std::move(sock),
        localAddress,
        *peerAddress,
        controller_,
        std::move(h2codec),
        tinfo,
        this);
    /*
    if (acceptorConfig.maxConcurrentIncomingStreams) {
      session->setMaxConcurrentIncomingStreams(
          acceptorConfig.maxConcurrentIncomingStreams);
    }
    */
    // TODO: Improve the way max incoming streams is set
    session->setMaxConcurrentIncomingStreams(100000);

    // Set HTTP2 priorities flag on session object.
    session->setHTTP2PrioritiesEnabled(acceptorConfig.HTTP2PrioritiesEnabled);

    // Set flow control parameters.
    session->setFlowControl(
        acceptorConfig.initialReceiveWindow,
        acceptorConfig.receiveStreamWindowSize,
        acceptorConfig.receiveSessionWindowSize);
    if (acceptorConfig.writeBufferLimit > 0) {
      session->setWriteBufferLimit(acceptorConfig.writeBufferLimit);
    }

    return session;
  }

  void onDestroy(const proxygen::HTTPSession&) override {
    VLOG(4) << "HTTP2RoutingSessionManager::onDestroy";
    // Session destroyed, so self destroy.
    delete this;
  }

 private:
  // Supporting objects for HTTP2 session managed by the callback.
  std::unique_ptr<proxygen::HTTPServerAcceptor> serverAcceptor_;
  // The controller should only be destroyed once onDestroy is called.
  proxygen::SimpleController* controller_;
};

} // anonymous namespace

bool HTTP2RoutingHandler::canAcceptConnection(
    const std::vector<uint8_t>& bytes) {
  /*
   * HTTP/2.0 requests start with the following sequence:
   *   Octal: 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
   *  String: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
   *
   * For more, see: https://tools.ietf.org/html/rfc7540#section-3.5
   */
  if (bytes[0] == 0x50 && bytes[1] == 0x52 && bytes[2] == 0x49) {
    return true;
  }

  /*
   * HTTP requests start with the following sequence:
   *   Octal: "0x485454502f..."
   *  String: "HTTP/X.X"
   *
   * For more, see: https://tools.ietf.org/html/rfc2616#section-3
   */
  if (bytes[0] == 0x48 && bytes[1] == 0x54 && bytes[2] == 0x54) {
    return true;
  }

  return false;
}

bool HTTP2RoutingHandler::canAcceptEncryptedConnection(
    const std::string& protocolName) {
  return protocolName == "h2" || protocolName == "http";
}

void HTTP2RoutingHandler::handleConnection(
    wangle::ConnectionManager* connectionManager,
    folly::AsyncTransportWrapper::UniquePtr sock,
    folly::SocketAddress* peerAddress,
    wangle::TransportInfo const& tinfo) {
  // Create the DownstreamSession manager.
  std::unique_ptr<HTTP2RoutingSessionManager> sessionManager(
      new HTTP2RoutingSessionManager);
  // Create the DownstreamSession
  auto session = sessionManager->CreateSession(
      options_.get(), std::move(sock), peerAddress, tinfo);
  // Route the connection.
  connectionManager->addConnection(session);
  sessionManager.release();
  session->startNow();
}

} // namspace thrift
} // namespace apache
<commit_msg>Cleanup HTTPSession.h<commit_after>/*
 * Copyright 2004-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/lib/cpp2/transport/http2/common/HTTP2RoutingHandler.h>

#include <proxygen/httpserver/HTTPServerAcceptor.h>
#include <proxygen/httpserver/HTTPServerOptions.h>
#include <proxygen/lib/http/session/HTTPDefaultSessionCodecFactory.h>
#include <proxygen/lib/http/session/HTTPDownstreamSession.h>
#include <proxygen/lib/http/session/HTTPSession.h>
#include <proxygen/lib/http/session/SimpleController.h>

#include <wangle/acceptor/ManagedConnection.h>

namespace apache {
namespace thrift {

namespace {

// Class for managing lifetime of objects supporting an HTTP2 session.
class HTTP2RoutingSessionManager : public proxygen::EmptyInfoCallback {
 public:
  ~HTTP2RoutingSessionManager() = default;
  proxygen::HTTPDownstreamSession* CreateSession(
      proxygen::HTTPServerOptions* options,
      folly::AsyncTransportWrapper::UniquePtr sock,
      folly::SocketAddress* peerAddress,
      wangle::TransportInfo const& tinfo) {
    // Create the SimpleController
    auto ipConfig = proxygen::HTTPServer::IPConfig(
        *peerAddress, proxygen::HTTPServer::Protocol::HTTP2);
    auto acceptorConfig =
        proxygen::HTTPServerAcceptor::makeConfig(ipConfig, *options);
    serverAcceptor_ =
        proxygen::HTTPServerAcceptor::make(acceptorConfig, *options);
    controller_ = new proxygen::SimpleController(serverAcceptor_.get());

    // Get the HTTP2 Codec
    auto codecFactory =
        proxygen::HTTPDefaultSessionCodecFactory(acceptorConfig);
    auto h2codec =
        codecFactory.getCodec("h2", proxygen::TransportDirection::DOWNSTREAM);

    // Obtain the proper routing address
    folly::SocketAddress localAddress;
    try {
      sock->getLocalAddress(&localAddress);
    } catch (...) {
      VLOG(3) << "couldn't get local address for socket";
      localAddress = folly::SocketAddress("0.0.0.0", 0);
    }
    VLOG(4) << "Created new session for peer " << *peerAddress;

    // Create the DownstreamSession
    auto session = new proxygen::HTTPDownstreamSession(
        proxygen::WheelTimerInstance(std::chrono::milliseconds(5)),
        std::move(sock),
        localAddress,
        *peerAddress,
        controller_,
        std::move(h2codec),
        tinfo,
        this);
    /*
    if (acceptorConfig.maxConcurrentIncomingStreams) {
      session->setMaxConcurrentIncomingStreams(
          acceptorConfig.maxConcurrentIncomingStreams);
    }
    */
    // TODO: Improve the way max incoming streams is set
    session->setMaxConcurrentIncomingStreams(100000);

    // Set HTTP2 priorities flag on session object.
    session->setHTTP2PrioritiesEnabled(acceptorConfig.HTTP2PrioritiesEnabled);

    // Set flow control parameters.
    session->setFlowControl(
        acceptorConfig.initialReceiveWindow,
        acceptorConfig.receiveStreamWindowSize,
        acceptorConfig.receiveSessionWindowSize);
    if (acceptorConfig.writeBufferLimit > 0) {
      session->setWriteBufferLimit(acceptorConfig.writeBufferLimit);
    }

    return session;
  }

  void onDestroy(const proxygen::HTTPSession&) override {
    VLOG(4) << "HTTP2RoutingSessionManager::onDestroy";
    // Session destroyed, so self destroy.
    delete this;
  }

 private:
  // Supporting objects for HTTP2 session managed by the callback.
  std::unique_ptr<proxygen::HTTPServerAcceptor> serverAcceptor_;
  // The controller should only be destroyed once onDestroy is called.
  proxygen::SimpleController* controller_;
};

} // anonymous namespace

bool HTTP2RoutingHandler::canAcceptConnection(
    const std::vector<uint8_t>& bytes) {
  /*
   * HTTP/2.0 requests start with the following sequence:
   *   Octal: 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
   *  String: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
   *
   * For more, see: https://tools.ietf.org/html/rfc7540#section-3.5
   */
  if (bytes[0] == 0x50 && bytes[1] == 0x52 && bytes[2] == 0x49) {
    return true;
  }

  /*
   * HTTP requests start with the following sequence:
   *   Octal: "0x485454502f..."
   *  String: "HTTP/X.X"
   *
   * For more, see: https://tools.ietf.org/html/rfc2616#section-3
   */
  if (bytes[0] == 0x48 && bytes[1] == 0x54 && bytes[2] == 0x54) {
    return true;
  }

  return false;
}

bool HTTP2RoutingHandler::canAcceptEncryptedConnection(
    const std::string& protocolName) {
  return protocolName == "h2" || protocolName == "http";
}

void HTTP2RoutingHandler::handleConnection(
    wangle::ConnectionManager* connectionManager,
    folly::AsyncTransportWrapper::UniquePtr sock,
    folly::SocketAddress* peerAddress,
    wangle::TransportInfo const& tinfo) {
  // Create the DownstreamSession manager.
  std::unique_ptr<HTTP2RoutingSessionManager> sessionManager(
      new HTTP2RoutingSessionManager);
  // Create the DownstreamSession
  auto session = sessionManager->CreateSession(
      options_.get(), std::move(sock), peerAddress, tinfo);
  // Route the connection.
  connectionManager->addConnection(session);
  sessionManager.release();
  session->startNow();
}

} // namspace thrift
} // namespace apache
<|endoftext|>


<commit_before>/*
 * FogLAMP process class
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Massimiliano Pinto
 */

/**
 * FogLAMP process base class
 */
#include <iostream>
#include <logger.h>
#include <process.h>
#include <service_record.h>

#define LOG_SERVICE_NAME  "FogLAMP Process"

using namespace std;

// Destructor
FogLampProcess::~FogLampProcess()
{
	delete m_client;
	delete m_storage;
	delete m_logger;
}

// Constructor
FogLampProcess::FogLampProcess(int argc, char** argv) :
				m_stime(time(NULL)),
				m_argc(argc),
				m_arg_vals((const char**) argv)
{
	string myName = LOG_SERVICE_NAME;
	m_logger = new Logger(myName);

	try
	{
		m_core_mngt_host = getArgValue("--address=");
		m_core_mngt_port = atoi(getArgValue("--port=").c_str());
		m_name = getArgValue("--name=");
	}
	catch (exception e)
	{
		throw runtime_error(string("Error while parsing required options: ") + e.what());
	}

	if (m_core_mngt_host.empty())
	{
		throw runtime_error("Error: --address is not specified");
	}
	else if (m_core_mngt_port == 0)
	{
		throw runtime_error("Error: --port is not specified");
	}
	else if (m_name.empty())
	{
		throw runtime_error("Error: --name is not specified");
	}

	m_logger->setMinLevel("warning");	// Default to warnings, errors and fatal for log messages
	try
	{
		string minLogLevel = getArgValue("--loglevel=");
		m_logger->setMinLevel(minLogLevel);
	}
	catch (exception e)
	{
		throw runtime_error(string("Error while parsing optional options: ") + e.what());
	}

	// Connection to FogLamp core microservice
	m_client = new ManagementClient(m_core_mngt_host, m_core_mngt_port);

	// Storage layer handle
	ServiceRecord storageInfo("FogLAMP Storage");

	if (!m_client->getService(storageInfo))
	{
		string errMsg("Unable to find storage service at ");
		errMsg += m_core_mngt_host;
		errMsg += ':';
		errMsg += to_string(m_core_mngt_port);

		throw runtime_error(errMsg);
	}

	if (!(m_storage = new StorageClient(storageInfo.getAddress(),
					    storageInfo.getPort())))
	{
		string errMsg("Unable to connect to storage service at ");
		errMsg.append(storageInfo.getAddress());
		errMsg += ':';
		errMsg += to_string(storageInfo.getPort());

		throw runtime_error(errMsg);
	}
}

/**
 * Get command line argument value like "--xyx=ABC"
 * Argument name to pass is "--xyz="
 *
 * @param name    The argument name (--xyz=)
 * @return        The argument value if found or an emopty string
 */
string FogLampProcess::getArgValue(const string& name) const
{
	for (int i=1; i < m_argc; i++)
	{
		if (strncmp(m_arg_vals[i], name.c_str(), name.length()) == 0)
		{
			// Return the option value (after "--xyx=ABC"
			return string(m_arg_vals[i] + name.length());
		}
	}
	// Return empty string
	return string("");
}

/**
 * Return storage client
 */
StorageClient* FogLampProcess::getStorageClient() const
{
        return m_storage;
}

/**
 * Return management client
 */
ManagementClient* FogLampProcess::getManagementClient() const
{
	return m_client;
}

/**
 * Return Logger
 */
Logger *FogLampProcess::getLogger() const
{
	return m_logger;
}
<commit_msg>FOGL-2423 Fix settign log level via command line<commit_after>/*
 * FogLAMP process class
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Massimiliano Pinto
 */

/**
 * FogLAMP process base class
 */
#include <iostream>
#include <logger.h>
#include <process.h>
#include <service_record.h>

#define LOG_SERVICE_NAME  "FogLAMP Process"

using namespace std;

// Destructor
FogLampProcess::~FogLampProcess()
{
	delete m_client;
	delete m_storage;
	delete m_logger;
}

// Constructor
FogLampProcess::FogLampProcess(int argc, char** argv) :
				m_stime(time(NULL)),
				m_argc(argc),
				m_arg_vals((const char**) argv)
{
	string myName = LOG_SERVICE_NAME;
	m_logger = new Logger(myName);

	try
	{
		m_core_mngt_host = getArgValue("--address=");
		m_core_mngt_port = atoi(getArgValue("--port=").c_str());
		m_name = getArgValue("--name=");
	}
	catch (exception e)
	{
		throw runtime_error(string("Error while parsing required options: ") + e.what());
	}

	if (m_core_mngt_host.empty())
	{
		throw runtime_error("Error: --address is not specified");
	}
	else if (m_core_mngt_port == 0)
	{
		throw runtime_error("Error: --port is not specified");
	}
	else if (m_name.empty())
	{
		throw runtime_error("Error: --name is not specified");
	}

	m_logger->setMinLevel("warning");	// Default to warnings, errors and fatal for log messages
	try
	{
		string minLogLevel = getArgValue("--loglevel=");
		if (!minLogLevel.empty())
		{
			m_logger->setMinLevel(minLogLevel);
		}
	}
	catch (exception e)
	{
		throw runtime_error(string("Error while parsing optional options: ") + e.what());
	}

	// Connection to FogLamp core microservice
	m_client = new ManagementClient(m_core_mngt_host, m_core_mngt_port);

	// Storage layer handle
	ServiceRecord storageInfo("FogLAMP Storage");

	if (!m_client->getService(storageInfo))
	{
		string errMsg("Unable to find storage service at ");
		errMsg += m_core_mngt_host;
		errMsg += ':';
		errMsg += to_string(m_core_mngt_port);

		throw runtime_error(errMsg);
	}

	if (!(m_storage = new StorageClient(storageInfo.getAddress(),
					    storageInfo.getPort())))
	{
		string errMsg("Unable to connect to storage service at ");
		errMsg.append(storageInfo.getAddress());
		errMsg += ':';
		errMsg += to_string(storageInfo.getPort());

		throw runtime_error(errMsg);
	}
}

/**
 * Get command line argument value like "--xyx=ABC"
 * Argument name to pass is "--xyz="
 *
 * @param name    The argument name (--xyz=)
 * @return        The argument value if found or an emopty string
 */
string FogLampProcess::getArgValue(const string& name) const
{
	for (int i=1; i < m_argc; i++)
	{
		if (strncmp(m_arg_vals[i], name.c_str(), name.length()) == 0)
		{
			// Return the option value (after "--xyx=ABC"
			return string(m_arg_vals[i] + name.length());
		}
	}
	// Return empty string
	return string("");
}

/**
 * Return storage client
 */
StorageClient* FogLampProcess::getStorageClient() const
{
        return m_storage;
}

/**
 * Return management client
 */
ManagementClient* FogLampProcess::getManagementClient() const
{
	return m_client;
}

/**
 * Return Logger
 */
Logger *FogLampProcess::getLogger() const
{
	return m_logger;
}
<|endoftext|>


<commit_before>
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)

//#include "ctwin.h"
#endif

#include "global.h"
#include "ctexceptions.h"
#include "stringUtils.h"
#include "units.h"

#ifndef WIN32
#include "ctdir.h"
#endif

#include <fstream>
using namespace std;

//int writeToMatlab(const char* buf);

namespace Cantera {

    /**
     * Class to hold global data. Class Application is the top-level
     * class that stores data that should persist for the duration of
     * the process. The class should not be instantiated directly;
     * instead, it is instantiated as needed by the functions declared
     * here. At most one instance is created, and it is not destroyed
     * until the process terminates.
     */
    class Application {
    public:
        Application() : linelen(0), stop_on_error(false),
                        tmp_dir("/tmp") {}
        virtual ~Application(){}
        vector<string> inputDirs;
        vector<string> errorMessage;
        vector<string> warning;
        vector<string> errorRoutine;
        string msglog;
        size_t linelen;
        bool stop_on_error;
        //bool write_log_to_cout;
        //bool matlab;
        map<string, string>     options;
        string tmp_dir;
    };

    /// Returns a pointer to the one and only instance of Application
    Application* app();

    void setDefaultDirectories();

    static Application* __app = 0;
    Unit* Unit::__u = 0;

    static void appinit() {
        if (__app == 0) __app = new Application;
    }

    Application* app() {
        if (__app == 0) {
            __app = new Application;
            setDefaultDirectories();
        }
        return __app;
    }

    void setTmpDir(string tmp) { app()->tmp_dir = tmp; }
    string tmpDir() { appinit(); return app()->tmp_dir; }

    int nErrors() {return app()->errorMessage.size();}

    void popError() {
        appinit();
        if (nErrors() > 0) {
            __app->errorMessage.pop_back();
            __app->errorRoutine.pop_back();
        }
    }

    string lastErrorMessage() {
        appinit();
        if (nErrors() > 0)
            return "\nProcedure: "+__app->errorRoutine.back()+"\nError:   "+__app->errorMessage.back();
        else
            return "<no Cantera error>";
    }

    void showErrors(ostream& f) {
        appinit();
        int i = __app->errorMessage.size();
        if (i == 0) return;
        f << endl << endl;
        f << "************************************************" << endl;
        f << "                Cantera Error!                  " << endl;
        f << "************************************************" << endl << endl;
        int j;
        for (j = 0; j < i; j++) {
            f << endl;
            f << "Procedure: " << __app->errorRoutine[j] << endl;
            f << "Error:     " << __app->errorMessage[j] << endl;
        }
        f << endl << endl;
        __app->errorMessage.clear();
        __app->errorRoutine.clear();
        //if (__app->stop_on_error) exit(-1);
    }

    void setError(string r, string msg) {
        appinit();
        __app->errorMessage.push_back(msg);
        __app->errorRoutine.push_back(r);
    }

    /**
     * Set the default directories for input files. Four directories are
     * added to the search path used by findInputFile. These are
     * 'data', 'data/inputs', 'data/thermo', and
     * 'data/transport'. These names are for convenience only -
     * findInputFile searches all of them, independent of the type of
     * file. The location of the 'data' directory depends on how
     * environment variables are set. If CANTERA_DATA_DIR is set, then
     * this will be used instead of 'data'. In addition, if
     * WIN_CANTERA_ROOT or CANTERA_ROOT are set, then 'data' is
     * assumed to be a top-level subdirectory. WIN_CANTERA_ROOT should
     * only be set on PCs, and should be in 'DOS' format, for example
     * 'C:\CANTERA'. CANTERA_ROOT, on the other hand, should be in
     * unix-like format ('/home/usr/cantera'). This allows Cantera to
     * be built on PCs using a unix-like environment (Cygwin) and
     * compiler (g++), as well as using Win32 compilers.
     */
    void setDefaultDirectories() {
        appinit();
        vector<string>& dirs = __app->inputDirs;

        // always look in the local directory first
        dirs.push_back(".");

#ifdef WIN32
        /*
         * Under Windows, the Cantera setup utility puts data files in
         * a directory 'Cantera\data' below the one the environment
         * variable COMMONPROGRAMFILES points to. (This is usually
         * C:\Program Files\Common Files.) If this environment
         * variable is defined, then this directory is assumed to
         * exist and is added to the search path.
         */
        const char* comfiles = getenv("COMMONPROGRAMFILES");
        if (comfiles != 0) {
            string cfiles = string(comfiles);

            // remove quotes if necessary
            if (cfiles[0] == '\'')
                cfiles = cfiles.substr(1,1000);
            if (cfiles[cfiles.size()-1] == '\'') cfiles[cfiles.size()-1] = '\n';

            string datadir = string(comfiles) + "/Cantera/data";
            string tmpldir = string(comfiles) + "/Cantera/templates";
            dirs.push_back(datadir);
            dirs.push_back(tmpldir);
        }
#endif
        if (getenv("CANTERA_DATA") != 0) {
            string datadir = string(getenv("CANTERA_DATA"));
            dirs.push_back(datadir);
        }

        // CANTERA_ROOT is defined in file ctdir.h. This file is written
        // during the build process (unix), and points to the directory
        // specified by the 'prefix' option to 'configure', or else to
        // /usr/local/cantera. This will generally not be defined under
        // Windows.
#ifdef CANTERA_ROOT
	string datadir = string(CANTERA_ROOT) + "/data";
	dirs.push_back(datadir);
#endif
    }

    void addDirectory(string dir) {
        appinit();
        if (__app->inputDirs.size() == 0) setDefaultDirectories();
        __app->inputDirs.push_back(stripnonprint(dir));
    }

    /**
     *  findInputFile():
     *
     *    This routine will search for a file in the default
     *    locations specified for the application.
     *    See the routine setDefaultDirectories() listed above.
     *
     *    The default set of directories specified for the application
     *    will be searched if a '/' or an '\\' is not found in
     *    name. If either is found then a relative path name is
     *    presumed and the default directories are not searched.
     *
     *    The presence of the file is determined by whether the file
     *    can be opened for reading by the current user.
     *
     *    Return
     *    -------
     *      The absolute path name of the first matching
     *      file is returned. If a relative path name
     *      is indicated, the relative path name is returned.
     *
     *      If the file is not found, a message is written to
     *      stdout and  a CanteraError exception is thrown.
     */
    string findInputFile(string name) {
        appinit();
        int islash = name.find('/');
        int ibslash = name.find('\\');
        string inname;
        vector<string>& dirs = __app->inputDirs;
        if (dirs.size() == 0) setDefaultDirectories();

        int nd;
        if (islash < 0 && ibslash < 0) {
            nd = dirs.size();
            int i;
            inname = "";
            for (i = 0; i < nd; i++) {
                inname = dirs[i] + "/" + name;
                ifstream fin(inname.c_str());
                if (fin) {
                    fin.close();
                    return inname;
                }
            }
            string msg;
            msg = "\nInput file " + name
                 + " not found in director";
            msg += (nd == 1 ? "y " : "ies ");
            for (i = 0; i < nd; i++) {
                msg += "\n'" + dirs[i] + "'";
                if (i < nd-1) msg += ", ";
            }
            msg += "\n\n";
            msg += "To fix this problem, either:\n";
            msg += "    a) move the missing files into the local directory;\n";
            msg += "    b) define environment variable CANTERA_DATA to\n";
            msg += "         point to the directory containing the file.";
            throw CanteraError("findInputFile", msg);
            return "";
        }
        else {
            return name;
        }
    }

    //void setMatlabMode(bool m) {
    //    appinit();
    //    __app->matlab = m;
    //}

    //void write(const string& msg) {cout << msg;}
    //void write(const char* msg) {cout << msg;}

    void writelog(const char* msg) {writelog(string(msg));}
    //void getlog(string& s) {
    //    appinit();
    //    s = __app->msglog;
    //    //__app->msglog = "";
    //}
    //void clearlog() {
    //    __app->msglog = "";
    //}

    doublereal toSI(string unit) {
        doublereal f = Unit::units()->toSI(unit);
        if (f) return f;
        else return 1.0;
    }

    doublereal actEnergyToSI(string unit) {
        doublereal f = Unit::units()->actEnergyToSI(unit);
        if (f) return f;
        else return 1.0;
    }

    string canteraRoot() {
        char* ctroot = 0;
        ctroot = getenv("CANTERA_ROOT");
        if (ctroot != 0) { return string(ctroot); }
        else {
#ifdef CANTERA_ROOT
            return string(CANTERA_ROOT);
#else
            return "";
#endif
        }
    }
}

<commit_msg>added option to clear all entries in close_XML_File.<commit_after>
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)

//#include "ctwin.h"
#endif

#include "global.h"
#include "ctexceptions.h"
#include "stringUtils.h"
#include "units.h"
#include "xml.h"
#include "ctml.h"

#ifndef WIN32
#include "ctdir.h"
#endif

#include <fstream>
using namespace std;

//int writeToMatlab(const char* buf);

namespace Cantera {

    /**
     * Class to hold global data. Class Application is the top-level
     * class that stores data that should persist for the duration of
     * the process. The class should not be instantiated directly;
     * instead, it is instantiated as needed by the functions declared
     * here. At most one instance is created, and it is not destroyed
     * until the process terminates.
     */
    class Application {
    public:
        Application() : linelen(0), stop_on_error(false),
                        tmp_dir("/tmp") {}
        virtual ~Application(){}
        vector<string> inputDirs;
        vector<string> errorMessage;
        vector<string> warning;
        vector<string> errorRoutine;
        string msglog;
        size_t linelen;
        bool stop_on_error;
        //bool write_log_to_cout;
        //bool matlab;
        map<string, string>     options;
        string tmp_dir;
        map<string, XML_Node*> xmlfiles;
    };

    /// Returns a pointer to the one and only instance of Application
    Application* app();

    void setDefaultDirectories();

    static Application* __app = 0;
    Unit* Unit::__u = 0;

    static void appinit() {
        if (__app == 0) __app = new Application;
    }

    Application* app() {
        if (__app == 0) {
            __app = new Application;
            setDefaultDirectories();
        }
        return __app;
    }

    XML_Node* get_XML_File(string file) {
        if (app()->xmlfiles.find(file)
            == app()->xmlfiles.end()) {
            string path = findInputFile(file);

            /*
             * Check whether or not the file is XML. If not, it will
             * be first processed with the preprocessor.
             */
            string::size_type idot = path.rfind('.');
            string ext, ff;
            if (idot != string::npos) {
                ext = path.substr(idot, path.size());
            }
            if (ext != ".xml" && ext != ".ctml") {
                ctml::ct2ctml(path.c_str());
                ff = path.substr(0,idot) + ".xml";
            }
            else {
                ff = path;
            }
            ifstream s(ff.c_str());
            XML_Node* x = new XML_Node("doc");
            x->build(s);
            __app->xmlfiles[file] = x;
        }
        return __app->xmlfiles[file];
    }

    void close_XML_File(string file) {
        if (file == "all") {
            map<string, XML_Node*>::iterator
                b = app()->xmlfiles.begin(), e = app()->xmlfiles.end();
            for(; b != e; ++b) {
                delete b->second;
                __app->xmlfiles.erase(b->first);
            }
        }
        else if (app()->xmlfiles.find(file)
            != app()->xmlfiles.end()) {
            delete __app->xmlfiles[file];
            __app->xmlfiles.erase(file);
        }
    }

    void setTmpDir(string tmp) { app()->tmp_dir = tmp; }
    string tmpDir() { appinit(); return app()->tmp_dir; }

    int nErrors() {return app()->errorMessage.size();}

    void popError() {
        appinit();
        if (nErrors() > 0) {
            __app->errorMessage.pop_back();
            __app->errorRoutine.pop_back();
        }
    }

    string lastErrorMessage() {
        appinit();
        if (nErrors() > 0)
            return "\nProcedure: "+__app->errorRoutine.back()+"\nError:   "+__app->errorMessage.back();
        else
            return "<no Cantera error>";
    }

    void showErrors(ostream& f) {
        appinit();
        int i = __app->errorMessage.size();
        if (i == 0) return;
        f << endl << endl;
        f << "************************************************" << endl;
        f << "                Cantera Error!                  " << endl;
        f << "************************************************" << endl << endl;
        int j;
        for (j = 0; j < i; j++) {
            f << endl;
            f << "Procedure: " << __app->errorRoutine[j] << endl;
            f << "Error:     " << __app->errorMessage[j] << endl;
        }
        f << endl << endl;
        __app->errorMessage.clear();
        __app->errorRoutine.clear();
        //if (__app->stop_on_error) exit(-1);
    }

    void setError(string r, string msg) {
        appinit();
        __app->errorMessage.push_back(msg);
        __app->errorRoutine.push_back(r);
    }

    /**
     * Set the default directories for input files. Four directories are
     * added to the search path used by findInputFile. These are
     * 'data', 'data/inputs', 'data/thermo', and
     * 'data/transport'. These names are for convenience only -
     * findInputFile searches all of them, independent of the type of
     * file. The location of the 'data' directory depends on how
     * environment variables are set. If CANTERA_DATA_DIR is set, then
     * this will be used instead of 'data'. In addition, if
     * WIN_CANTERA_ROOT or CANTERA_ROOT are set, then 'data' is
     * assumed to be a top-level subdirectory. WIN_CANTERA_ROOT should
     * only be set on PCs, and should be in 'DOS' format, for example
     * 'C:\CANTERA'. CANTERA_ROOT, on the other hand, should be in
     * unix-like format ('/home/usr/cantera'). This allows Cantera to
     * be built on PCs using a unix-like environment (Cygwin) and
     * compiler (g++), as well as using Win32 compilers.
     */
    void setDefaultDirectories() {
        appinit();
        vector<string>& dirs = __app->inputDirs;

        // always look in the local directory first
        dirs.push_back(".");

#ifdef WIN32
        /*
         * Under Windows, the Cantera setup utility puts data files in
         * a directory 'Cantera\data' below the one the environment
         * variable COMMONPROGRAMFILES points to. (This is usually
         * C:\Program Files\Common Files.) If this environment
         * variable is defined, then this directory is assumed to
         * exist and is added to the search path.
         */
        const char* comfiles = getenv("COMMONPROGRAMFILES");
        if (comfiles != 0) {
            string cfiles = string(comfiles);

            // remove quotes if necessary
            if (cfiles[0] == '\'')
                cfiles = cfiles.substr(1,1000);
            if (cfiles[cfiles.size()-1] == '\'') cfiles[cfiles.size()-1] = '\n';

            string datadir = string(comfiles) + "/Cantera/data";
            string tmpldir = string(comfiles) + "/Cantera/templates";
            dirs.push_back(datadir);
            dirs.push_back(tmpldir);
        }
#endif
        if (getenv("CANTERA_DATA") != 0) {
            string datadir = string(getenv("CANTERA_DATA"));
            dirs.push_back(datadir);
        }

        // CANTERA_ROOT is defined in file ctdir.h. This file is written
        // during the build process (unix), and points to the directory
        // specified by the 'prefix' option to 'configure', or else to
        // /usr/local/cantera. This will generally not be defined under
        // Windows.
#ifdef CANTERA_ROOT
	string datadir = string(CANTERA_ROOT) + "/data";
	dirs.push_back(datadir);
#endif
    }

    void addDirectory(string dir) {
        appinit();
        if (__app->inputDirs.size() == 0) setDefaultDirectories();
        __app->inputDirs.push_back(stripnonprint(dir));
    }

    /**
     *  findInputFile():
     *
     *    This routine will search for a file in the default
     *    locations specified for the application.
     *    See the routine setDefaultDirectories() listed above.
     *
     *    The default set of directories specified for the application
     *    will be searched if a '/' or an '\\' is not found in
     *    name. If either is found then a relative path name is
     *    presumed and the default directories are not searched.
     *
     *    The presence of the file is determined by whether the file
     *    can be opened for reading by the current user.
     *
     *    Return
     *    -------
     *      The absolute path name of the first matching
     *      file is returned. If a relative path name
     *      is indicated, the relative path name is returned.
     *
     *      If the file is not found, a message is written to
     *      stdout and  a CanteraError exception is thrown.
     */
    string findInputFile(string name) {
        appinit();
        int islash = name.find('/');
        int ibslash = name.find('\\');
        string inname;
        vector<string>& dirs = __app->inputDirs;
        if (dirs.size() == 0) setDefaultDirectories();

        int nd;
        if (islash < 0 && ibslash < 0) {
            nd = dirs.size();
            int i;
            inname = "";
            for (i = 0; i < nd; i++) {
                inname = dirs[i] + "/" + name;
                ifstream fin(inname.c_str());
                if (fin) {
                    fin.close();
                    return inname;
                }
            }
            string msg;
            msg = "\nInput file " + name
                 + " not found in director";
            msg += (nd == 1 ? "y " : "ies ");
            for (i = 0; i < nd; i++) {
                msg += "\n'" + dirs[i] + "'";
                if (i < nd-1) msg += ", ";
            }
            msg += "\n\n";
            msg += "To fix this problem, either:\n";
            msg += "    a) move the missing files into the local directory;\n";
            msg += "    b) define environment variable CANTERA_DATA to\n";
            msg += "         point to the directory containing the file.";
            throw CanteraError("findInputFile", msg);
            return "";
        }
        else {
            return name;
        }
    }

    //void setMatlabMode(bool m) {
    //    appinit();
    //    __app->matlab = m;
    //}

    //void write(const string& msg) {cout << msg;}
    //void write(const char* msg) {cout << msg;}

    void writelog(const char* msg) {writelog(string(msg));}
    //void getlog(string& s) {
    //    appinit();
    //    s = __app->msglog;
    //    //__app->msglog = "";
    //}
    //void clearlog() {
    //    __app->msglog = "";
    //}

    doublereal toSI(string unit) {
        doublereal f = Unit::units()->toSI(unit);
        if (f) return f;
        else return 1.0;
    }

    doublereal actEnergyToSI(string unit) {
        doublereal f = Unit::units()->actEnergyToSI(unit);
        if (f) return f;
        else return 1.0;
    }

    string canteraRoot() {
        char* ctroot = 0;
        ctroot = getenv("CANTERA_ROOT");
        if (ctroot != 0) { return string(ctroot); }
        else {
#ifdef CANTERA_ROOT
            return string(CANTERA_ROOT);
#else
            return "";
#endif
        }
    }
}

<|endoftext|>