<commit_before>#include <webkit2/webkit-web-extension.h>
#include <JavaScriptCore/JavaScript.h>
#include <string.h>
#include <soup.h>
#include "utils.h"

static WebKitWebExtension* extension;

static guint idLogHandler = 0;
static guint idSendRequestHandler = 0;
static guint idPageCreatedHandler = 0;

static gboolean web_page_send_request(WebKitWebPage* page, WebKitURIRequest* request, WebKitURIResponse* redirected_response, gpointer data) {
	gchar* eventName = (gchar*)data;
	const char* uri = webkit_uri_request_get_uri(request);
	JSValueRef result;
	gboolean hasHandler = FALSE;
	JSGlobalContextRef jsContext = webkit_frame_get_javascript_context_for_script_world(
		webkit_web_page_get_main_frame(page),
		webkit_script_world_get_default()
	);

	const char* funcStr = g_strconcat("window.request_", eventName, NULL);

	JSStringRef funcScript = JSStringCreateWithUTF8CString(g_strconcat("!!", funcStr, NULL));
	result = JSEvaluateScript(
		jsContext,
		funcScript,
		NULL, // JSObjectRef thisObject
		NULL, // JSStringRef sourceURL
		0, // int startingLineNumber
		NULL  // JSValueRef* exception
	);
	if (JSValueIsBoolean(jsContext, result)) {
		hasHandler = JSValueToBoolean(jsContext, result);
	} else {
		g_warning("Error while checking if request function handler exist");
	}

	if (hasHandler == FALSE) {
		g_message("No request handler available to check %s", uri);
		return FALSE;
	}

	const char* scriptStr = g_strconcat(funcStr, "(\"", uri, "\")", NULL);
	JSStringRef script = JSStringCreateWithUTF8CString(scriptStr);

	result = JSEvaluateScript(
		jsContext,
		script,
		NULL, // JSObjectRef thisObject
		NULL, // JSStringRef sourceURL
		0, // int startingLineNumber
		NULL  // JSValueRef* exception
	);

	if (JSValueIsBoolean(jsContext, result)) {
		if (JSValueToBoolean(jsContext, result)) {
			// go through
			g_message("accept %s", uri);
		} else {
			g_message("reject %s", uri);
			webkit_uri_request_set_uri(request, g_strconcat("#", uri, NULL));
		}
	} else if (JSValueIsString(jsContext, result)) {
		JSStringRef js_str_value = JSValueToStringCopy(jsContext, result, NULL);
		gsize str_length = JSStringGetMaximumUTF8CStringSize(js_str_value);
		gchar* str_value = (gchar*)g_malloc(str_length);
		JSStringGetUTF8CString(js_str_value, str_value, str_length);
		JSStringRelease(js_str_value);
		g_message("rewrite %s to %s", uri, str_value);
		webkit_uri_request_set_uri(request, str_value);
		g_free(str_value);
	} else {
		// no return value - meaning ignore the request
		g_message("ignore %s", uri);
		soup_message_headers_replace(
			webkit_uri_request_get_http_headers(request),
			"X-Ignore",
			"1"
		);
	}

	return FALSE;
}

static void web_page_created_callback(WebKitWebExtension* ext, WebKitWebPage* web_page, gpointer data) {
	if (idSendRequestHandler > 0) {
		g_signal_handler_disconnect(web_page, idSendRequestHandler);
		idSendRequestHandler = 0;
	}
	idSendRequestHandler = g_signal_connect(web_page, "send-request", G_CALLBACK(web_page_send_request), data);
}

static void ttyLog(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) {
	FILE* ftty = fopen("/dev/tty", "a");
	if (ftty == NULL) {
		return;
	}
	fprintf(ftty, "%s\n", message);
	fclose(ftty);
}

extern "C" {
	G_MODULE_EXPORT void webkit_web_extension_initialize_with_user_data(WebKitWebExtension* ext, const GVariant* constData) {
		extension = ext;
		idLogHandler = g_log_set_handler(
			NULL,
			G_LOG_LEVEL_WARNING, // production setting
			// G_LOG_LEVEL_MASK, // debug setting
			ttyLog,
			NULL
		);
		gchar* eventName;
		g_variant_get((GVariant*)constData, "(s)", &eventName);
		idPageCreatedHandler = g_signal_connect(extension, "page-created", G_CALLBACK(web_page_created_callback), eventName);
	}
}

static void __attribute__((destructor))
Webkit_Web_extension_shutdown (void) {
	g_log_remove_handler(NULL, idLogHandler);

	if (idPageCreatedHandler > 0) {
		g_signal_handler_disconnect(extension, idPageCreatedHandler);
		idPageCreatedHandler = 0;
	}
	g_object_unref(extension);
	extension = NULL;
}
<commit_msg>Little renaming and debug log in extension<commit_after>#include <webkit2/webkit-web-extension.h>
#include <JavaScriptCore/JavaScript.h>
#include <string.h>
#include <soup.h>
#include "utils.h"

static WebKitWebExtension* extension;

static guint idLogHandler = 0;
static guint idSendRequestHandler = 0;
static guint idPageCreatedHandler = 0;

static gboolean web_page_send_request(WebKitWebPage* page, WebKitURIRequest* request, WebKitURIResponse* redirected_response, gpointer data) {
	gchar* eventName = (gchar*)data;
	const char* uri = webkit_uri_request_get_uri(request);
	JSValueRef result;
	gboolean hasHandler = FALSE;
	JSGlobalContextRef jsContext = webkit_frame_get_javascript_context_for_script_world(
		webkit_web_page_get_main_frame(page),
		webkit_script_world_get_default()
	);

	const char* funcStr = g_strconcat("window.request_", eventName, NULL);

	JSStringRef funcScript = JSStringCreateWithUTF8CString(g_strconcat("!!", funcStr, NULL));
	result = JSEvaluateScript(
		jsContext,
		funcScript,
		NULL, // JSObjectRef thisObject
		NULL, // JSStringRef sourceURL
		0, // int startingLineNumber
		NULL  // JSValueRef* exception
	);
	if (JSValueIsBoolean(jsContext, result)) {
		hasHandler = JSValueToBoolean(jsContext, result);
	} else {
		g_warning("Error while checking if request function handler exist");
	}

	if (hasHandler == FALSE) {
		g_message("No request handler available to check %s", uri);
		return FALSE;
	}

	const char* scriptStr = g_strconcat(funcStr, "(\"", uri, "\")", NULL);
	JSStringRef script = JSStringCreateWithUTF8CString(scriptStr);

	result = JSEvaluateScript(
		jsContext,
		script,
		NULL, // JSObjectRef thisObject
		NULL, // JSStringRef sourceURL
		0, // int startingLineNumber
		NULL  // JSValueRef* exception
	);

	if (JSValueIsBoolean(jsContext, result)) {
		if (JSValueToBoolean(jsContext, result)) {
			// go through
			g_message("accept %s", uri);
		} else {
			g_message("reject %s", uri);
			webkit_uri_request_set_uri(request, g_strconcat("#", uri, NULL));
		}
	} else if (JSValueIsString(jsContext, result)) {
		JSStringRef js_str_value = JSValueToStringCopy(jsContext, result, NULL);
		gsize str_length = JSStringGetMaximumUTF8CStringSize(js_str_value);
		gchar* str_value = (gchar*)g_malloc(str_length);
		JSStringGetUTF8CString(js_str_value, str_value, str_length);
		JSStringRelease(js_str_value);
		g_message("rewrite %s to %s", uri, str_value);
		webkit_uri_request_set_uri(request, str_value);
		g_free(str_value);
	} else {
		// no return value - meaning ignore the request
		g_message("ignore %s", uri);
		soup_message_headers_replace(
			webkit_uri_request_get_http_headers(request),
			"X-Ignore",
			"1"
		);
	}

	return FALSE;
}

static void web_page_created_callback(WebKitWebExtension* ext, WebKitWebPage* web_page, gpointer data) {
	if (idSendRequestHandler > 0) {
		g_signal_handler_disconnect(web_page, idSendRequestHandler);
		idSendRequestHandler = 0;
	}
	idSendRequestHandler = g_signal_connect(web_page, "send-request", G_CALLBACK(web_page_send_request), data);
}

static void ttyLog(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) {
	FILE* ftty = fopen("/dev/tty", "a");
	if (ftty == NULL) {
		return;
	}
	fprintf(ftty, "%s\n", message);
	fclose(ftty);
}

extern "C" {
	G_MODULE_EXPORT void webkit_web_extension_initialize_with_user_data(WebKitWebExtension* ext, const GVariant* constData) {
		extension = ext;
		idLogHandler = g_log_set_handler(
			NULL,
			G_LOG_LEVEL_WARNING, // production setting
			// G_LOG_LEVEL_MASK, // debug setting
			ttyLog,
			NULL
		);
		gchar* eventName;
		g_variant_get((GVariant*)constData, "(s)", &eventName);
		idPageCreatedHandler = g_signal_connect(extension, "page-created", G_CALLBACK(web_page_created_callback), eventName);
	}
}

static void __attribute__((destructor))
webkit_web_extension_destroy (void) {
	g_message("extension destroyed");
	g_log_remove_handler(NULL, idLogHandler);

	if (idPageCreatedHandler > 0) {
		g_signal_handler_disconnect(extension, idPageCreatedHandler);
		idPageCreatedHandler = 0;
	}
	g_object_unref(extension);
	extension = NULL;
}
<|endoftext|>


<commit_before>#include <nan.h>

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

#include <list>

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

#include <sstream>

#include <vector>

#include <iostream>
#include <fstream>
using namespace std;

using namespace v8;
using namespace node;

BOOL IsTaskbarWindow(HWND hwnd) {
  if (IsWindowVisible(hwnd) && GetParent(hwnd) == 0) {
    bool bNoOwner = (GetWindow(hwnd, GW_OWNER) == 0);
    int lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
    if (!bNoOwner) return FALSE;
    if ((((lExStyle & WS_EX_TOOLWINDOW) == 0)))
    {
        return TRUE;
    }
  }

  return FALSE;
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
  if (!IsTaskbarWindow(hwnd)) {
    return TRUE;
  }

  std::list<Local<Object>> *windows = (std::list<Local<Object>>*)lParam;
  Local<Object> obj = NanNew<Object>();

  DWORD processID;
  char title[1024];
  DWORD threadID = GetWindowThreadProcessId(hwnd, &processID);
  GetWindowText(hwnd, title, sizeof(title));

  obj->Set(NanNew<String>("threadID"), NanNew<Number>((unsigned int)threadID));
  obj->Set(NanNew<String>("processID"), NanNew<Number>((unsigned int)processID));
  obj->Set(NanNew<String>("handle"), NanNew<Number>((unsigned int)hwnd));
  obj->Set(NanNew<String>("title"), NanNew<String>(title));

  (*windows).push_back(obj);
  return TRUE;
}

NAN_METHOD(GetAll) {
  NanScope();

  std::list<Local<Object>> windows;

  EnumWindows(EnumWindowsProc, (LPARAM)&windows);

  Local<Array> returnValue = NanNew<Array>();

  int i = 0;
  for (std::list<Local<Object>>::iterator it=windows.begin(); it != windows.end(); ++it) {
      returnValue->Set(i, *it);
      i++;
  }

  NanReturnValue(returnValue);
}

NAN_METHOD(GetCurrent) {
  NanScope();

  Local<Object> returnValue = NanNew<Object>();

  returnValue->Set(NanNew<String>("processID"), NanNew<Number>((unsigned int)  GetCurrentProcessId()));

  NanReturnValue(returnValue);
}

NAN_METHOD(GetTitle) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  char title[1024];
  GetWindowText(hwnd, title, sizeof(title));

  NanReturnValue(NanNew<String>(title));
  // If hebrew is not working
  //NanReturnValue(NanNew(*NanAsciiString(title)));
}

NAN_METHOD(Minimize) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_MINIMIZE);
}

NAN_METHOD(Show) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_SHOW);
}

NAN_METHOD(Maximize) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_MAXIMIZE);
}

NAN_METHOD(IsForeground) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  NanReturnValue(GetForegroundWindow() == hwnd ? NanTrue() : NanFalse());
}

NAN_METHOD(IsMinimized) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  NanReturnValue(IsIconic(hwnd) ? NanTrue() : NanFalse());
}

NAN_METHOD(SetTopMost) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
}

NAN_METHOD(Close) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_HIDE);
}

NAN_METHOD(Restore) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_RESTORE);
}

NAN_METHOD(SetToForeground) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, 4);
  SetForegroundWindow(hwnd);
}

NAN_METHOD(Activate) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();
  int result;

  if (hwnd != GetForegroundWindow()) {
    DWORD lForeThreadID = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    DWORD lThisThreadID = GetWindowThreadProcessId(hwnd, NULL);

    if (lForeThreadID != lThisThreadID) {
      AttachThreadInput(lForeThreadID, lThisThreadID, TRUE);
      result = SetForegroundWindow(hwnd);
      AttachThreadInput(lForeThreadID, lThisThreadID, FALSE);
    } else {
      result = SetForegroundWindow(hwnd);
    }

    if (IsIconic(hwnd)) {
      ShowWindow(hwnd, SW_RESTORE);
    } else {
      ShowWindow(hwnd, SW_SHOW);
    }
  }
}

void init(Handle<Object> exports) {
  exports->Set(NanNew<String>("getAll"),
    NanNew<FunctionTemplate>(GetAll)->GetFunction());

  exports->Set(NanNew<String>("getTitle"),
    NanNew<FunctionTemplate>(GetTitle)->GetFunction());

  exports->Set(NanNew<String>("setToForeground"),
    NanNew<FunctionTemplate>(SetToForeground)->GetFunction());

  exports->Set(NanNew<String>("minimize"),
    NanNew<FunctionTemplate>(Minimize)->GetFunction());

  exports->Set(NanNew<String>("activate"),
    NanNew<FunctionTemplate>(Activate)->GetFunction());

  exports->Set(NanNew<String>("restore"),
    NanNew<FunctionTemplate>(Restore)->GetFunction());

  exports->Set(NanNew<String>("show"),
    NanNew<FunctionTemplate>(Show)->GetFunction());

  exports->Set(NanNew<String>("maximize"),
    NanNew<FunctionTemplate>(Maximize)->GetFunction());

  exports->Set(NanNew<String>("isForeground"),
    NanNew<FunctionTemplate>(IsForeground)->GetFunction());

  exports->Set(NanNew<String>("isMinimized"),
    NanNew<FunctionTemplate>(IsMinimized)->GetFunction());

  exports->Set(NanNew<String>("setTopMost"),
    NanNew<FunctionTemplate>(SetTopMost)->GetFunction());

  exports->Set(NanNew<String>("close"),
    NanNew<FunctionTemplate>(Close)->GetFunction());

  exports->Set(NanNew<String>("getCurrent"),
    NanNew<FunctionTemplate>(GetCurrent)->GetFunction());
}

NODE_MODULE(windows, init)<commit_msg>removed restore<commit_after>#include <nan.h>

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

#include <list>

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

#include <sstream>

#include <vector>

#include <iostream>
#include <fstream>
using namespace std;

using namespace v8;
using namespace node;

BOOL IsTaskbarWindow(HWND hwnd) {
  if (IsWindowVisible(hwnd) && GetParent(hwnd) == 0) {
    bool bNoOwner = (GetWindow(hwnd, GW_OWNER) == 0);
    int lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
    if (!bNoOwner) return FALSE;
    if ((((lExStyle & WS_EX_TOOLWINDOW) == 0)))
    {
        return TRUE;
    }
  }

  return FALSE;
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
  if (!IsTaskbarWindow(hwnd)) {
    return TRUE;
  }

  std::list<Local<Object>> *windows = (std::list<Local<Object>>*)lParam;
  Local<Object> obj = NanNew<Object>();

  DWORD processID;
  char title[1024];
  DWORD threadID = GetWindowThreadProcessId(hwnd, &processID);
  GetWindowText(hwnd, title, sizeof(title));

  obj->Set(NanNew<String>("threadID"), NanNew<Number>((unsigned int)threadID));
  obj->Set(NanNew<String>("processID"), NanNew<Number>((unsigned int)processID));
  obj->Set(NanNew<String>("handle"), NanNew<Number>((unsigned int)hwnd));
  obj->Set(NanNew<String>("title"), NanNew<String>(title));

  (*windows).push_back(obj);
  return TRUE;
}

NAN_METHOD(GetAll) {
  NanScope();

  std::list<Local<Object>> windows;

  EnumWindows(EnumWindowsProc, (LPARAM)&windows);

  Local<Array> returnValue = NanNew<Array>();

  int i = 0;
  for (std::list<Local<Object>>::iterator it=windows.begin(); it != windows.end(); ++it) {
      returnValue->Set(i, *it);
      i++;
  }

  NanReturnValue(returnValue);
}

NAN_METHOD(GetCurrent) {
  NanScope();

  Local<Object> returnValue = NanNew<Object>();

  returnValue->Set(NanNew<String>("processID"), NanNew<Number>((unsigned int)  GetCurrentProcessId()));

  NanReturnValue(returnValue);
}

NAN_METHOD(GetTitle) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  char title[1024];
  GetWindowText(hwnd, title, sizeof(title));

  NanReturnValue(NanNew<String>(title));
  // If hebrew is not working
  //NanReturnValue(NanNew(*NanAsciiString(title)));
}

NAN_METHOD(Minimize) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_MINIMIZE);
}

NAN_METHOD(Show) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_SHOW);
}

NAN_METHOD(Maximize) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_MAXIMIZE);
}

NAN_METHOD(IsForeground) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  NanReturnValue(GetForegroundWindow() == hwnd ? NanTrue() : NanFalse());
}

NAN_METHOD(IsMinimized) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  NanReturnValue(IsIconic(hwnd) ? NanTrue() : NanFalse());
}

NAN_METHOD(SetTopMost) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
}

NAN_METHOD(Close) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, SW_HIDE);
}

NAN_METHOD(SetToForeground) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();

  ShowWindow(hwnd, 4);
  SetForegroundWindow(hwnd);
}

NAN_METHOD(Activate) {
  NanScope();

  HWND hwnd = (HWND)args[0]->Uint32Value();
  int result;

  if (hwnd != GetForegroundWindow()) {
    DWORD lForeThreadID = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    DWORD lThisThreadID = GetWindowThreadProcessId(hwnd, NULL);

    if (lForeThreadID != lThisThreadID) {
      AttachThreadInput(lForeThreadID, lThisThreadID, TRUE);
      result = SetForegroundWindow(hwnd);
      AttachThreadInput(lForeThreadID, lThisThreadID, FALSE);
    } else {
      result = SetForegroundWindow(hwnd);
    }

    if (IsIconic(hwnd)) {
      ShowWindow(hwnd, SW_RESTORE);
    } else {
      ShowWindow(hwnd, SW_SHOW);
    }
  }
}

void init(Handle<Object> exports) {
  exports->Set(NanNew<String>("getAll"),
    NanNew<FunctionTemplate>(GetAll)->GetFunction());

  exports->Set(NanNew<String>("getTitle"),
    NanNew<FunctionTemplate>(GetTitle)->GetFunction());

  exports->Set(NanNew<String>("setToForeground"),
    NanNew<FunctionTemplate>(SetToForeground)->GetFunction());

  exports->Set(NanNew<String>("minimize"),
    NanNew<FunctionTemplate>(Minimize)->GetFunction());

  exports->Set(NanNew<String>("activate"),
    NanNew<FunctionTemplate>(Activate)->GetFunction());

  exports->Set(NanNew<String>("show"),
    NanNew<FunctionTemplate>(Show)->GetFunction());

  exports->Set(NanNew<String>("maximize"),
    NanNew<FunctionTemplate>(Maximize)->GetFunction());

  exports->Set(NanNew<String>("isForeground"),
    NanNew<FunctionTemplate>(IsForeground)->GetFunction());

  exports->Set(NanNew<String>("isMinimized"),
    NanNew<FunctionTemplate>(IsMinimized)->GetFunction());

  exports->Set(NanNew<String>("setTopMost"),
    NanNew<FunctionTemplate>(SetTopMost)->GetFunction());

  exports->Set(NanNew<String>("close"),
    NanNew<FunctionTemplate>(Close)->GetFunction());

  exports->Set(NanNew<String>("getCurrent"),
    NanNew<FunctionTemplate>(GetCurrent)->GetFunction());
}

NODE_MODULE(windows, init)<|endoftext|>


<commit_before>// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.

#include "caf/net/middleman.hpp"

#include "caf/actor_system_config.hpp"
#include "caf/detail/set_thread_name.hpp"
#include "caf/expected.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/net/basp/ec.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/middleman_backend.hpp"
#include "caf/raise_error.hpp"
#include "caf/sec.hpp"
#include "caf/send.hpp"
#include "caf/uri.hpp"

namespace caf::net {

void middleman::init_global_meta_objects() {
  caf::init_global_meta_objects<id_block::net_module>();
}

middleman::middleman(actor_system& sys) : sys_(sys), mpx_(this) {
  // nop
}

middleman::~middleman() {
  // nop
}

void middleman::start() {
  if (!get_or(config(), "caf.middleman.manual-multiplexing", false)) {
    mpx_thread_ = std::thread{[this] {
      CAF_SET_LOGGER_SYS(&sys_);
      detail::set_thread_name("caf.net.mpx");
      sys_.thread_started();
      mpx_.set_thread_id();
      mpx_.run();
      sys_.thread_terminates();
    }};
  }
}

void middleman::stop() {
  for (const auto& backend : backends_)
    backend->stop();
  mpx_.shutdown();
  if (mpx_thread_.joinable())
    mpx_thread_.join();
  else
    mpx_.run();
}

void middleman::init(actor_system_config& cfg) {
  if (auto err = mpx_.init()) {
    CAF_LOG_ERROR("mpx_.init() failed: " << err);
    CAF_RAISE_ERROR("mpx_.init() failed");
  }
  if (auto node_uri = get_if<uri>(&cfg, "caf.middleman.this-node")) {
    auto this_node = make_node_id(std::move(*node_uri));
    sys_.node_.swap(this_node);
  } else {
    // CAF_RAISE_ERROR("no valid entry for caf.middleman.this-node found");
  }
  for (auto& backend : backends_)
    if (auto err = backend->init()) {
      CAF_LOG_ERROR("failed to initialize backend: " << err);
      CAF_RAISE_ERROR("failed to initialize backend");
    }
}

middleman::module::id_t middleman::id() const {
  return module::network_manager;
}

void* middleman::subtype_ptr() {
  return this;
}

void middleman::add_module_options(actor_system_config& cfg) {
  config_option_adder{cfg.custom_options(), "caf.middleman"}
    .add<std::vector<std::string>>("app-identifiers",
                                   "valid application identifiers of this node")
    .add<uri>("this-node", "locator of this CAF node")
    .add<size_t>("max-consecutive-reads",
                 "max. number of consecutive reads per broker")
    .add<bool>("manual-multiplexing",
               "disables background activity of the multiplexer")
    .add<size_t>("workers", "number of deserialization workers")
    .add<std::string>("network-backend", "legacy option");
}

expected<endpoint_manager_ptr> middleman::connect(const uri& locator) {
  if (auto ptr = backend(locator.scheme()))
    return ptr->get_or_connect(locator);
  else
    return basp::ec::invalid_scheme;
}

void middleman::resolve(const uri& locator, const actor& listener) {
  auto ptr = backend(locator.scheme());
  if (ptr != nullptr)
    ptr->resolve(locator, listener);
  else
    anon_send(listener, error{basp::ec::invalid_scheme});
}

middleman_backend* middleman::backend(string_view scheme) const noexcept {
  auto predicate = [&](const middleman_backend_ptr& ptr) {
    return ptr->id() == scheme;
  };
  auto i = std::find_if(backends_.begin(), backends_.end(), predicate);
  if (i != backends_.end())
    return i->get();
  return nullptr;
}

expected<uint16_t> middleman::port(string_view scheme) const {
  if (auto ptr = backend(scheme))
    return ptr->port();
  else
    return basp::ec::invalid_scheme;
}

} // namespace caf::net
<commit_msg>Add compatibility options and fix test setup<commit_after>// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.

#include "caf/net/middleman.hpp"

#include "caf/actor_system_config.hpp"
#include "caf/detail/set_thread_name.hpp"
#include "caf/expected.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/net/basp/ec.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/middleman_backend.hpp"
#include "caf/raise_error.hpp"
#include "caf/sec.hpp"
#include "caf/send.hpp"
#include "caf/uri.hpp"

namespace caf::net {

void middleman::init_global_meta_objects() {
  caf::init_global_meta_objects<id_block::net_module>();
}

middleman::middleman(actor_system& sys) : sys_(sys), mpx_(this) {
  // nop
}

middleman::~middleman() {
  // nop
}

void middleman::start() {
  if (!get_or(config(), "caf.middleman.manual-multiplexing", false)) {
    mpx_thread_ = std::thread{[this] {
      CAF_SET_LOGGER_SYS(&sys_);
      detail::set_thread_name("caf.net.mpx");
      sys_.thread_started();
      mpx_.set_thread_id();
      mpx_.run();
      sys_.thread_terminates();
    }};
  } else {
    mpx_.set_thread_id();
  }
}

void middleman::stop() {
  for (const auto& backend : backends_)
    backend->stop();
  mpx_.shutdown();
  if (mpx_thread_.joinable())
    mpx_thread_.join();
  else
    mpx_.run();
}

void middleman::init(actor_system_config& cfg) {
  if (auto err = mpx_.init()) {
    CAF_LOG_ERROR("mpx_.init() failed: " << err);
    CAF_RAISE_ERROR("mpx_.init() failed");
  }
  if (auto node_uri = get_if<uri>(&cfg, "caf.middleman.this-node")) {
    auto this_node = make_node_id(std::move(*node_uri));
    sys_.node_.swap(this_node);
  } else {
    // CAF_RAISE_ERROR("no valid entry for caf.middleman.this-node found");
  }
  for (auto& backend : backends_)
    if (auto err = backend->init()) {
      CAF_LOG_ERROR("failed to initialize backend: " << err);
      CAF_RAISE_ERROR("failed to initialize backend");
    }
}

middleman::module::id_t middleman::id() const {
  return module::network_manager;
}

void* middleman::subtype_ptr() {
  return this;
}

void middleman::add_module_options(actor_system_config& cfg) {
  config_option_adder{cfg.custom_options(), "caf.middleman"}
    .add<std::vector<std::string>>("app-identifiers",
                                   "valid application identifiers of this node")
    .add<uri>("this-node", "locator of this CAF node")
    .add<size_t>("max-consecutive-reads",
                 "max. number of consecutive reads per broker")
    .add<bool>("manual-multiplexing",
               "disables background activity of the multiplexer")
    .add<size_t>("workers", "number of deserialization workers")
    .add<timespan>("heartbeat-interval", "interval of heartbeat messages")
    .add<timespan>("connection-timeout",
                   "max. time between messages before declaring a node dead "
                   "(disabled if 0, ignored if heartbeats are disabled)")
    .add<std::string>("network-backend", "legacy option");
}

expected<endpoint_manager_ptr> middleman::connect(const uri& locator) {
  if (auto ptr = backend(locator.scheme()))
    return ptr->get_or_connect(locator);
  else
    return basp::ec::invalid_scheme;
}

void middleman::resolve(const uri& locator, const actor& listener) {
  auto ptr = backend(locator.scheme());
  if (ptr != nullptr)
    ptr->resolve(locator, listener);
  else
    anon_send(listener, error{basp::ec::invalid_scheme});
}

middleman_backend* middleman::backend(string_view scheme) const noexcept {
  auto predicate = [&](const middleman_backend_ptr& ptr) {
    return ptr->id() == scheme;
  };
  auto i = std::find_if(backends_.begin(), backends_.end(), predicate);
  if (i != backends_.end())
    return i->get();
  return nullptr;
}

expected<uint16_t> middleman::port(string_view scheme) const {
  if (auto ptr = backend(scheme))
    return ptr->port();
  else
    return basp::ec::invalid_scheme;
}

} // namespace caf::net
<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <exception>
#include "config.hpp"
#include "exceptions.hpp"
#include "misc.hpp"
#include <cstddef>
#include "macros.hpp"

namespace lua {
namespace LuaHelpers {

template<typename T> void luaPush(lua_State* state, T param);
template<> inline void luaPush<std::string>(lua_State* state, std::string param) { lua_pushstring(state, param.c_str()); }
template<> inline void luaPush<std::nullptr_t>(lua_State* state, std::nullptr_t) { lua_pushnil(state); }
LUA_PUSH_HELPER(lua_pushboolean, bool)
LUA_PUSH_HELPER(lua_pushinteger, int)
LUA_PUSH_HELPER(lua_pushinteger, long long)
LUA_PUSH_HELPER(lua_pushinteger, long)
LUA_PUSH_HELPER(lua_pushlightuserdata, void*)
LUA_PUSH_HELPER(lua_pushnumber, double)
LUA_PUSH_HELPER(lua_pushnumber, float)
LUA_PUSH_HELPER(lua_pushnumber, long double)
LUA_PUSH_HELPER(lua_pushstring, char const*)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned int)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned long long)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned long)

template<typename T>
T luaGet(lua_State* state, int index);
LUA_GET_HELPER(lua_toboolean, lua_isboolean, bool)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, int)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, long long)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, long)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, double)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, float)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, long double)
LUA_GET_HELPER(lua_tostring, lua_isstring, const char*)
LUA_GET_HELPER(lua_tostring, lua_isstring, std::string)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned int)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned long long)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned long)
LUA_GET_HELPER(lua_touserdata, lua_islightuserdata, void*)

inline lua_State* pushArguments(lua_State* state) { return state; }

/**
 * @brief A helper to create lua_State* objects from arguments
 */
template<typename T>
inline lua_State* pushArguments(lua_State* state, T a) {
    LuaHelpers::luaPush<T>(state, a);
    return state;
}

/**
 * @brief A helper to create lua_State* objects from arguments
 */
template<typename T, typename... Args>
inline lua_State* pushArguments(lua_State* state, T a, Args... rest) {
    LuaHelpers::luaPush<T>(state, a);
    pushArguments(state, rest...);
    return state;
}

template<std::size_t Index, typename T>
inline typename std::enable_if<Index >= std::tuple_size<T>::value, void>::type
forEach(lua_State*, T&) {}

template<std::size_t Index = 0, typename T>
inline typename std::enable_if<Index < std::tuple_size<T>::value, void>::type
forEach(lua_State* lua, T& t) {
    std::get<Index>(t) = luaGet<typename std::tuple_element<Index, T>::type>
        (lua, 0 - static_cast<int>(std::tuple_size<T>::value) + static_cast<int>(Index));
    if (Index < std::tuple_size<T>::value) {
        forEach<Index + 1>(lua, t);
    }
}

inline std::size_t getToStack(lua_State* lua, const std::string& var) {
    auto splits = misc::split(var, '.');
    std::size_t pushes = 0;

    auto err = [&](std::size_t index) -> bool {
        auto err = lua_isnil(lua, -1) || lua_isnone(lua, -1);
        if (err) {
            std::string joined = splits[0];
            for (std::size_t i = 1; i < index; ++i) { joined += '.' + splits[i]; }
            throw exceptions::NoSuchKey("Error! No such field: " + joined);
        }
        pushes += 1;
        return err;
    };

    lua_getglobal(lua, splits[0].c_str());
    if (err(0)) { return pushes; }

    for (std::size_t i = 1; i < splits.size(); ++i) {
        lua_getfield(lua, -1, splits[i].c_str());
        if (err(i)) { return pushes; }
    }
    return pushes;
}

inline void popStack(lua_State* lua, int amount) {
    lua_pop(lua, amount);
}

} // namespace LuaHelpers
} // namespace lua
<commit_msg>bugfixes<commit_after>#pragma once

#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <exception>
#include "config.hpp"
#include "exceptions.hpp"
#include "misc.hpp"
#include <cstddef>
#include "macros.hpp"

namespace lua {
namespace LuaHelpers {

template<typename T> void luaPush(lua_State*, T);

template<> inline void luaPush<std::string>(lua_State* state, std::string param) { lua_pushstring(state, param.c_str()); }
template<> inline void luaPush<std::nullptr_t>(lua_State* state, std::nullptr_t) { lua_pushnil(state); }
LUA_PUSH_HELPER(lua_pushboolean, bool)
LUA_PUSH_HELPER(lua_pushinteger, int)
LUA_PUSH_HELPER(lua_pushinteger, long long)
LUA_PUSH_HELPER(lua_pushinteger, long)
LUA_PUSH_HELPER(lua_pushlightuserdata, void*)
LUA_PUSH_HELPER(lua_pushnumber, double)
LUA_PUSH_HELPER(lua_pushnumber, float)
LUA_PUSH_HELPER(lua_pushnumber, long double)
LUA_PUSH_HELPER(lua_pushstring, char const*)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned int)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned long long)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned long)
LUA_PUSH_HELPER(lua_pushunsigned, unsigned char)

template<typename T>
T luaGet(lua_State* state, int index);
LUA_GET_HELPER(lua_toboolean, lua_isboolean, bool)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, int)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, long long)
LUA_GET_HELPER(lua_tointeger, lua_isnumber, long)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, double)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, float)
LUA_GET_HELPER(lua_tonumber, lua_isnumber, long double)
LUA_GET_HELPER(lua_tostring, lua_isstring, const char*)
LUA_GET_HELPER(lua_tostring, lua_isstring, std::string)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned int)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned long long)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned long)
LUA_GET_HELPER(lua_tounsigned, lua_isnumber, unsigned char)
LUA_GET_HELPER(lua_touserdata, lua_islightuserdata, void*)

inline lua_State* pushArguments(lua_State* state) { return state; }

/**
 * @brief A helper to create lua_State* objects from arguments
 */
template<typename T>
inline lua_State* pushArguments(lua_State* state, T a) {
    LuaHelpers::luaPush<T>(state, a);
    return state;
}

/**
 * @brief A helper to create lua_State* objects from arguments
 */
template<typename T, typename... Args>
inline lua_State* pushArguments(lua_State* state, T a, Args... rest) {
    LuaHelpers::luaPush<T>(state, a);
    pushArguments(state, rest...);
    return state;
}

template<std::size_t Index, typename T>
inline typename std::enable_if<Index >= std::tuple_size<T>::value, void>::type
forEach(lua_State*, T&) {}

template<std::size_t Index = 0, typename T>
inline typename std::enable_if<Index < std::tuple_size<T>::value, void>::type
forEach(lua_State* lua, T& t) {
    std::get<Index>(t) = luaGet<typename std::tuple_element<Index, T>::type>
        (lua, 0 - static_cast<int>(std::tuple_size<T>::value) + static_cast<int>(Index));
    if (Index < std::tuple_size<T>::value) {
        forEach<Index + 1>(lua, t);
    }
}

inline std::size_t getToStack(lua_State* lua, const std::string& var) {
    auto splits = misc::split(var, '.');
    std::size_t pushes = 0;

    auto err = [&](std::size_t index) -> bool {
        auto err = lua_isnil(lua, -1) || lua_isnone(lua, -1);
        if (err) {
            std::string joined = splits[0];
            for (std::size_t i = 1; i < index; ++i) { joined += '.' + splits[i]; }
            throw exceptions::NoSuchKey("Error! No such field: " + joined);
        }
        pushes += 1;
        return err;
    };

    lua_getglobal(lua, splits[0].c_str());
    if (err(0)) { return pushes; }

    for (std::size_t i = 1; i < splits.size(); ++i) {
        lua_getfield(lua, -1, splits[i].c_str());
        if (err(i)) { return pushes; }
    }
    return pushes;
}

inline void popStack(lua_State* lua, int amount) {
    lua_pop(lua, amount);
}

} // namespace LuaHelpers
} // namespace lua
<|endoftext|>


<commit_before>#include "screenshot_maker.h"

#include <QFileInfo>
#include <QProcess>
#include <QDate>
#include <QTime>

#include <windows.h>
#include <winuser.h>

#pragma comment(lib, "user32.lib")

namespace NQtScreen {

static bool IsOs64Bit() {
#if defined(_WIN64)
    return true;
#elif defined(_WIN32)
    BOOL res = false;
    IsWow64Process(GetCurrentProcess(), &res);
    return res;
#else
    return false;
#endif
}

static bool IsProcess64Bit(uint32_t pid) {
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
    BOOL res = false;
    IsWow64Process(processHandle, &res);
    return !res;
}

static QString GetFullPath(const QString& path) {
    QFileInfo checkFile(path);
    return checkFile.absoluteFilePath();
}

static bool FileExists(const QString& path) {
    QFileInfo checkFile(path);
    return checkFile.exists() && checkFile.isFile();
}

bool TScreenShotMaker::GetOffsets(TInjectorHelpInfo& offsets, const QString& helperExe) {
    QProcess helper32;
    QStringList args;
    args.push_back("offsets");
    helper32.start(helperExe, args);
    if (!helper32.waitForStarted()) {
        WriteLog(LL_Error, "failed to execute helper " + helperExe);
        return false;
    }
    QByteArray data;
    while (helper32.waitForReadyRead()) {
        data.append(helper32.readAll());
    }
    QList<QByteArray> lines = data.split('\n');
    if (lines.size() < 4) {
        WriteLog(LL_Error, "wrong output for helper " + helperExe);
        return false;
    }
    offsets.DX8PresentOffset = lines[0].trimmed().toInt();
    offsets.DX9PresentOffset = lines[1].trimmed().toInt();
    offsets.DX9PresentExOffset = lines[2].trimmed().toInt();
    offsets.DXGIPresentOffset = lines[3].trimmed().toInt();
    WriteLog(LL_Info, "offsets for " + helperExe);
    WriteLog(LL_Info, QString("DX8PresentOffset: %1").arg(offsets.DX8PresentOffset));
    WriteLog(LL_Info, QString("DX9PresentOffset: %1").arg(offsets.DX9PresentOffset));
    WriteLog(LL_Info, QString("DX9PresentExOffset: %1").arg(offsets.DX9PresentExOffset));
    WriteLog(LL_Info, QString("DXGIPresentOffset: %1").arg(offsets.DXGIPresentOffset));
    return true;
}

static bool InjectDll(uint32_t processId, const QString& helperExe, const QString& dll) {
    QProcess helper32;
    QStringList args;
    args.push_back("inject");
    args.push_back(QString::number(processId));
    args.push_back(dll);
    helper32.start(helperExe, args);
    helper32.waitForStarted();
    QByteArray data;
    while (helper32.waitForReadyRead()) {
        data.append(helper32.readAll());
    }
    return helper32.exitCode() == 0;
}

TScreenShotMaker::TScreenShotMaker(const TScreenShotMakerConfig& config)
    : Config(config)
    , MakingScreen(false)
    , FullScreenProcessID(0)
    , ProcessDetectedCounter(0)
    , IsOs64(IsOs64Bit())
{
    Initialized = false;
    WriteLog(LL_Info, "Starting LibQtScreen");
    if (!FileExists(config.DLL32Path) ||
        !FileExists(config.DLL64Path))
    {
        WriteLog(LL_Error, "libqtscreen32.dll or libqtscreen64.dll not found");
        return;
    }

    if (!FileExists(config.Helper32Path) ||
        !FileExists(config.Helper64Path))
    {
        WriteLog(LL_Error, "helper32.exe or helper64.exe not found");
        return;
    }

    if (!GetOffsets(InjectorHelpInfo32, config.Helper32Path)) {
        return;
    }

    if (!GetOffsets(InjectorHelpInfo64, config.Helper64Path)) {
        return;
    }

    connect(&Server, &QLocalServer::newConnection, [this] {
        Connections.emplace_back(new TClient(this, Server.nextPendingConnection()));
        TClient* client = Connections.back().get();
        connect(client, &TClient::OnScreenshotReady, [this, client] {
            if (!MakingScreen) {
                return;
            }
            LastScreenshot = client->GetLastScreenshot();
            MakingScreen = false;
            TimeoutTimer.stop();
            emit OnScreenshotReady();
        });
        connect(client, &TClient::OnFailed, [this] {
            CheckFailedScreens();
        });
    });

    connect(&TimeoutTimer, &QTimer::timeout, [this] {
        TimeoutTimer.stop();
        MakingScreen = false;
        emit OnFailed();
    });

    Server.setSocketOptions(QLocalServer::WorldAccessOption);
    if (!Server.listen("libqtscreen")) {
        WriteLog(LL_Error, "failed to listen named pipe libqtscreen - may be there is another libqtscreen server");
        return;
    }
    Initialized = true;
    WriteLog(LL_Info, "Successfuly initialized!");
    startTimer(500);
}

bool TScreenShotMaker::IsInitialized() const {
    return Initialized;
}

void TScreenShotMaker::MakeScreenshot(uint64_t pid) {
    if (!Initialized) {
        WriteLog(LL_Warning, "failed to make screenshot: not initialized");
        emit OnFailed();
        return;
    }

    if (Connections.size() == 0) {
        WriteLog(LL_Warning, "failed to make screenshot: missing any connected dll");
        emit OnFailed();
        return;
    }

    if (!FullScreenProcessID && !pid) {
        WriteLog(LL_Warning, "failed to make screenshot: no fullscreen app detected");
        emit OnFailed();
        return;
    }
    for (auto&& cli: Connections) {
        if (cli->GetInfo().PID == FullScreenProcessID ||
            cli->GetInfo().PID == pid)
        {
            MakingScreen = true;
            TimeoutTimer.start(1000);
            WriteLog(LL_Info, QString("making screenshot of process %1").arg(cli->GetInfo().PID));
            cli->MakeScreenshot();
            return;
        }
    }
    WriteLog(LL_Warning, "failed to make screenshot: missing connection to required process");
    emit OnFailed();
}

QImage TScreenShotMaker::GetLastScreenshot() {
    return LastScreenshot;
}

bool TScreenShotMaker::InjectToPID(uint64_t PID) {
    if (InjectedPIDs.find(PID) != InjectedPIDs.end()) {
        WriteLog(LL_Info, QString("already injected to %1").arg(PID));
        return true;
    }

    bool injected = false;
    if (IsOs64 && IsProcess64Bit(PID)) {
        injected = InjectDll(PID, Config.Helper64Path, GetFullPath(Config.DLL64Path));
    } else {
        injected = InjectDll(PID, Config.Helper32Path, GetFullPath(Config.DLL32Path));
    }
    if (injected) {
        WriteLog(LL_Info, QString("successfully injected to %1").arg(PID));
    } else {
        WriteLog(LL_Warning, QString("failed to inject to %1").arg(PID));
    }
    return injected;
}

void TScreenShotMaker::timerEvent(QTimerEvent*) {
    RemoveInactiveConnections();
    if (Config.AutoInjectToFullscreen) {
        InjectAll();
    }
}

void TScreenShotMaker::InjectAll() {
    HWND window = GetForegroundWindow();
    if (!window) {
        FullScreenProcessID = 0;
        return;
    }
    RECT rect;
    if (!GetWindowRect(window, &rect)) {
        FullScreenProcessID = 0;
        return;
    }

    DWORD styles = GetWindowLongPtr(window, GWL_STYLE);
    if ((styles & WS_MAXIMIZE) && (styles & WS_BORDER)) {
        FullScreenProcessID = 0;
        return;
    }

    MONITORINFO lpmi = {0};
    HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
    if (!monitor) {
        FullScreenProcessID = 0;
        return;
    }
    lpmi.cbSize = sizeof(lpmi);
    if (!GetMonitorInfoA(monitor, &lpmi)) {
        FullScreenProcessID = 0;
        return;
    }

    if (rect.left != lpmi.rcMonitor.left ||
        rect.right != lpmi.rcMonitor.right ||
        rect.bottom != lpmi.rcMonitor.bottom ||
        rect.top != lpmi.rcMonitor.top)
    {
        FullScreenProcessID = 0;
        return;
    }

    DWORD pid = 0;
    GetWindowThreadProcessId(window, &pid);
    if (!pid) {
        FullScreenProcessID = 0;
        return;
    }

    if (pid != FullScreenProcessID) {
        ProcessDetectedCounter = 0;
    }

    FullScreenProcessID = pid;

    ProcessDetectedCounter += 1;

    //   Give some time to process to initialize
    // and to connect to ourselv if we already injected
    if (ProcessDetectedCounter > 3) {
        InjectToPID(pid);
        // Next inject retry in 30 seconds
        ProcessDetectedCounter = -60;
    }
}

void TScreenShotMaker::RemoveInactiveConnections() {
    std::vector<TClientRef> newConnections;
    InjectedPIDs.clear();
    for (auto&& c: Connections) {
        if (c->IsActive()) {
            newConnections.push_back(c);
            if (c->GetInfo().PID) {
                InjectedPIDs.insert(uint64_t(c->GetInfo().PID));
            }
        }
    }
    Connections.swap(newConnections);
}

void TScreenShotMaker::CheckFailedScreens() {
    if (!MakingScreen) {
        return;
    }
    bool anyInProgress = false;
    for (auto&& c: Connections) {
        if (!c->IsScreenFailed()) {
            anyInProgress = true;
        }
    }
    if (!anyInProgress) {
        MakingScreen = false;
        TimeoutTimer.stop();
        emit OnFailed();
    }
}

void TScreenShotMaker::WriteLog(ELogLevel logLevel, const QString& message) {
    if (!Config.LogOutput || logLevel < Config.LogLevel) {
        return;
    }
    QString level;
    switch (logLevel) {
    case LL_Info:
        level = "INFO";
        break;
    case LL_Warning:
        level = "WARNING";
        break;
    case LL_Error:
        level = "ERROR";
        break;
    default:
        break;
    }
    QString msg = "[" + QDate::currentDate().toString("dd.MM.yy") + " " + QTime::currentTime().toString() + " " + level + "] " + message;
    (*Config.LogOutput) << msg << "\n";
    Config.LogOutput->flush();
}

} // NQtScreen
<commit_msg>More logs<commit_after>#include "screenshot_maker.h"

#include <QFileInfo>
#include <QProcess>
#include <QDate>
#include <QTime>

#include <windows.h>
#include <winuser.h>

#pragma comment(lib, "user32.lib")

namespace NQtScreen {

static bool IsOs64Bit() {
#if defined(_WIN64)
    return true;
#elif defined(_WIN32)
    BOOL res = false;
    IsWow64Process(GetCurrentProcess(), &res);
    return res;
#else
    return false;
#endif
}

static bool IsProcess64Bit(uint32_t pid) {
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
    BOOL res = false;
    IsWow64Process(processHandle, &res);
    return !res;
}

static QString GetFullPath(const QString& path) {
    QFileInfo checkFile(path);
    return checkFile.absoluteFilePath();
}

static bool FileExists(const QString& path) {
    QFileInfo checkFile(path);
    return checkFile.exists() && checkFile.isFile();
}

bool TScreenShotMaker::GetOffsets(TInjectorHelpInfo& offsets, const QString& helperExe) {
    QProcess helper32;
    QStringList args;
    args.push_back("offsets");
    helper32.start(helperExe, args);
    if (!helper32.waitForStarted()) {
        WriteLog(LL_Error, "failed to execute helper " + helperExe);
        return false;
    }
    QByteArray data;
    while (helper32.waitForReadyRead()) {
        data.append(helper32.readAll());
    }
    QList<QByteArray> lines = data.split('\n');
    if (lines.size() < 4) {
        WriteLog(LL_Error, "wrong output for helper " + helperExe);
        return false;
    }
    offsets.DX8PresentOffset = lines[0].trimmed().toInt();
    offsets.DX9PresentOffset = lines[1].trimmed().toInt();
    offsets.DX9PresentExOffset = lines[2].trimmed().toInt();
    offsets.DXGIPresentOffset = lines[3].trimmed().toInt();
    WriteLog(LL_Info, "offsets for " + helperExe);
    WriteLog(LL_Info, QString("DX8PresentOffset: %1").arg(offsets.DX8PresentOffset));
    WriteLog(LL_Info, QString("DX9PresentOffset: %1").arg(offsets.DX9PresentOffset));
    WriteLog(LL_Info, QString("DX9PresentExOffset: %1").arg(offsets.DX9PresentExOffset));
    WriteLog(LL_Info, QString("DXGIPresentOffset: %1").arg(offsets.DXGIPresentOffset));
    return true;
}

static bool InjectDll(uint32_t processId, const QString& helperExe, const QString& dll) {
    QProcess helper32;
    QStringList args;
    args.push_back("inject");
    args.push_back(QString::number(processId));
    args.push_back(dll);
    helper32.start(helperExe, args);
    helper32.waitForStarted();
    QByteArray data;
    while (helper32.waitForReadyRead()) {
        data.append(helper32.readAll());
    }
    return helper32.exitCode() == 0;
}

TScreenShotMaker::TScreenShotMaker(const TScreenShotMakerConfig& config)
    : Config(config)
    , MakingScreen(false)
    , FullScreenProcessID(0)
    , ProcessDetectedCounter(0)
    , IsOs64(IsOs64Bit())
{
    Initialized = false;
    WriteLog(LL_Info, "Starting LibQtScreen");
    if (!FileExists(config.DLL32Path) ||
        !FileExists(config.DLL64Path))
    {
        WriteLog(LL_Error, "libqtscreen32.dll or libqtscreen64.dll not found");
        return;
    }

    if (!FileExists(config.Helper32Path) ||
        !FileExists(config.Helper64Path))
    {
        WriteLog(LL_Error, "helper32.exe or helper64.exe not found");
        return;
    }

    if (!GetOffsets(InjectorHelpInfo32, config.Helper32Path)) {
        return;
    }

    if (!GetOffsets(InjectorHelpInfo64, config.Helper64Path)) {
        return;
    }

    connect(&Server, &QLocalServer::newConnection, [this] {
        WriteLog(LL_Info, "new connection");
        Connections.emplace_back(new TClient(this, Server.nextPendingConnection()));
        TClient* client = Connections.back().get();
        connect(client, &TClient::OnScreenshotReady, [this, client] {
            if (!MakingScreen) {
                WriteLog(LL_Warning, "screenshot received after timeout");
                return;
            }
            LastScreenshot = client->GetLastScreenshot();
            MakingScreen = false;
            TimeoutTimer.stop();
            WriteLog(LL_Info, "screenshot successful");
            emit OnScreenshotReady();
        });
        connect(client, &TClient::OnFailed, [this] {
            CheckFailedScreens();
        });
    });

    connect(&TimeoutTimer, &QTimer::timeout, [this] {
        TimeoutTimer.stop();
        MakingScreen = false;
        WriteLog(LL_Warning, "failed to make screenshot: time out");
        emit OnFailed();
    });

    Server.setSocketOptions(QLocalServer::WorldAccessOption);
    if (!Server.listen("libqtscreen")) {
        WriteLog(LL_Error, "failed to listen named pipe libqtscreen - may be there is another libqtscreen server");
        return;
    }
    Initialized = true;
    WriteLog(LL_Info, "Successfuly initialized!");
    startTimer(500);
}

bool TScreenShotMaker::IsInitialized() const {
    return Initialized;
}

void TScreenShotMaker::MakeScreenshot(uint64_t pid) {
    if (!Initialized) {
        WriteLog(LL_Warning, "failed to make screenshot: not initialized");
        emit OnFailed();
        return;
    }

    if (Connections.size() == 0) {
        WriteLog(LL_Warning, "failed to make screenshot: missing any connected dll");
        emit OnFailed();
        return;
    }

    if (!FullScreenProcessID && !pid) {
        WriteLog(LL_Warning, "failed to make screenshot: no fullscreen app detected");
        emit OnFailed();
        return;
    }
    for (auto&& cli: Connections) {
        if (cli->GetInfo().PID == FullScreenProcessID ||
            cli->GetInfo().PID == pid)
        {
            MakingScreen = true;
            TimeoutTimer.start(1000);
            WriteLog(LL_Info, QString("making screenshot of process %1").arg(cli->GetInfo().PID));
            cli->MakeScreenshot();
            return;
        }
    }
    WriteLog(LL_Warning, "failed to make screenshot: missing connection to required process");
    emit OnFailed();
}

QImage TScreenShotMaker::GetLastScreenshot() {
    return LastScreenshot;
}

bool TScreenShotMaker::InjectToPID(uint64_t PID) {
    if (InjectedPIDs.find(PID) != InjectedPIDs.end()) {
        WriteLog(LL_Info, QString("already injected to %1").arg(PID));
        return true;
    }

    bool injected = false;
    if (IsOs64 && IsProcess64Bit(PID)) {
        injected = InjectDll(PID, Config.Helper64Path, GetFullPath(Config.DLL64Path));
    } else {
        injected = InjectDll(PID, Config.Helper32Path, GetFullPath(Config.DLL32Path));
    }
    if (injected) {
        WriteLog(LL_Info, QString("successfully injected to %1").arg(PID));
    } else {
        WriteLog(LL_Warning, QString("failed to inject to %1").arg(PID));
    }
    return injected;
}

void TScreenShotMaker::timerEvent(QTimerEvent*) {
    RemoveInactiveConnections();
    if (Config.AutoInjectToFullscreen) {
        InjectAll();
    }
}

void TScreenShotMaker::InjectAll() {
    HWND window = GetForegroundWindow();
    if (!window) {
        FullScreenProcessID = 0;
        return;
    }
    RECT rect;
    if (!GetWindowRect(window, &rect)) {
        FullScreenProcessID = 0;
        return;
    }

    DWORD styles = GetWindowLongPtr(window, GWL_STYLE);
    if ((styles & WS_MAXIMIZE) && (styles & WS_BORDER)) {
        FullScreenProcessID = 0;
        return;
    }

    MONITORINFO lpmi = {0};
    HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
    if (!monitor) {
        FullScreenProcessID = 0;
        return;
    }
    lpmi.cbSize = sizeof(lpmi);
    if (!GetMonitorInfoA(monitor, &lpmi)) {
        FullScreenProcessID = 0;
        return;
    }

    if (rect.left != lpmi.rcMonitor.left ||
        rect.right != lpmi.rcMonitor.right ||
        rect.bottom != lpmi.rcMonitor.bottom ||
        rect.top != lpmi.rcMonitor.top)
    {
        FullScreenProcessID = 0;
        return;
    }

    DWORD pid = 0;
    GetWindowThreadProcessId(window, &pid);
    if (!pid) {
        FullScreenProcessID = 0;
        return;
    }

    if (pid != FullScreenProcessID) {
        ProcessDetectedCounter = 0;
    }

    FullScreenProcessID = pid;

    ProcessDetectedCounter += 1;

    //   Give some time to process to initialize
    // and to connect to ourselv if we already injected
    if (ProcessDetectedCounter > 3) {
        InjectToPID(pid);
        // Next inject retry in 30 seconds
        ProcessDetectedCounter = -60;
    }
}

void TScreenShotMaker::RemoveInactiveConnections() {
    std::vector<TClientRef> newConnections;
    std::set<uint32_t> prevPids;
    InjectedPIDs.swap(prevPids);
    for (auto&& c: Connections) {
        if (c->IsActive()) {
            newConnections.push_back(c);
            if (c->GetInfo().PID) {
                if (prevPids.find(c->GetInfo().PID) == prevPids.end()) {
                    WriteLog(LL_Info, QString("injected dll with pid %1 sent initial info").arg(c->GetInfo().PID));
                }
                InjectedPIDs.insert(uint64_t(c->GetInfo().PID));
            }
        } else {
            WriteLog(LL_Info, QString("injected dll with pid %1 disconnected").arg(c->GetInfo().PID));
        }
    }
    Connections.swap(newConnections);
}

void TScreenShotMaker::CheckFailedScreens() {
    if (!MakingScreen) {
        return;
    }
    bool anyInProgress = false;
    for (auto&& c: Connections) {
        if (!c->IsScreenFailed()) {
            anyInProgress = true;
        }
    }
    if (!anyInProgress) {
        MakingScreen = false;
        TimeoutTimer.stop();
        WriteLog(LL_Warning, "failed to make screenshot: injected dll was unable to make screenshot");
        emit OnFailed();
    }
}

void TScreenShotMaker::WriteLog(ELogLevel logLevel, const QString& message) {
    if (!Config.LogOutput || logLevel < Config.LogLevel) {
        return;
    }
    QString level;
    switch (logLevel) {
    case LL_Info:
        level = "INFO";
        break;
    case LL_Warning:
        level = "WARNING";
        break;
    case LL_Error:
        level = "ERROR";
        break;
    default:
        break;
    }
    QString msg = "[" + QDate::currentDate().toString("dd.MM.yy") + " " + QTime::currentTime().toString() + " " + level + "] " + message;
    (*Config.LogOutput) << msg << "\n";
    Config.LogOutput->flush();
}

} // NQtScreen
<|endoftext|>


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

using namespace graphene::chain;
using namespace boost::multiprecision;

share_type asset_lock_data_object::get_profit(share_type tolocking_balance,uint32_t lock_period,const database &_db)const
{
	return (asset(tolocking_balance, asset_id)*_get_interest(lock_period, _db) - asset(tolocking_balance, asset_id)).amount;
}

Interest asset_lock_data_object::_get_interest(uint32_t lock_period,const database &_db)const{

   asset_object target_asset_obj=asset_id(_db);
   int32_t lock_days=lock_period/FCC_INTEREST_DAY;
   share_type max_to_deposit_balance_year = target_asset_obj.dynamic_data(_db).current_supply - (lock_coin_day / coin_day(FCC_INTEREST_YEAR)).value.to_uint64();
   asset  base_asset(FCC_INTEREST_BASE_SUPPLY, asset_id);

   static Interest top_of_interest = Interest();

   if (top_of_interest == Interest()) // yet not calculated
   {
	   asset result = base_asset;
	   for (uint32_t i = 0; i<FCC_INTEREST_DAYS_YEAR; i++)
	   {
		   result = result*nominal_interest_perday;
	   }
	   top_of_interest = Interest(base_asset, result);
   }

   auto result = base_asset;
   for (uint32_t i = 0; i<lock_days; i++)
   {
	   result = result*nominal_interest_perday;
   }

   int32_t pecent_of_year = (lock_days - FCC_INTEREST_DAYS_YEAR)*GRAPHENE_100_PERCENT / FCC_INTEREST_DAYS_YEAR;

   int64_t reward_rate = GRAPHENE_100_PERCENT + pecent_of_year * reward_coefficient / GRAPHENE_100_PERCENT;

   uint128_t pre_profile = uint128_t((result - base_asset).amount.value)*uint128_t(reward_rate) / GRAPHENE_100_PERCENT;

   auto actual_profile = pre_profile * interest_pool.value / (asset(max_to_deposit_balance_year, asset_id) * top_of_interest).amount.value;

   asset res_asset = asset(actual_profile.convert_to<uint64_t>(), asset_id) + base_asset;

   return Interest(base_asset,res_asset);
}

share_type asset_bitasset_data_object::max_force_settlement_volume(share_type current_supply) const
{
   if( options.maximum_force_settlement_volume == 0 )
      return 0;
   if( options.maximum_force_settlement_volume == GRAPHENE_100_PERCENT )
      return current_supply + force_settled_volume;

   fc::uint128 volume = current_supply.value + force_settled_volume.value;
   volume *= options.maximum_force_settlement_volume;
   volume /= GRAPHENE_100_PERCENT;
   return volume.to_uint64();
}

void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point_sec current_time)
{
   current_feed_publication_time = current_time;
   vector<std::reference_wrapper<const price_feed>> current_feeds;
   for( const pair<account_id_type, pair<time_point_sec,price_feed>>& f : feeds )
   {
      if( (current_time - f.second.first).to_seconds() < options.feed_lifetime_sec &&
          f.second.first != time_point_sec() )
      {
         current_feeds.emplace_back(f.second.second);
         current_feed_publication_time = std::min(current_feed_publication_time, f.second.first);
      }
   }

   // If there are no valid feeds, or the number available is less than the minimum to calculate a median...
   if( current_feeds.size() < options.minimum_feeds )
   {
      //... don't calculate a median, and set a null feed
      current_feed_publication_time = current_time;
      current_feed = price_feed();
      return;
   }
   if( current_feeds.size() == 1 )
   {
      current_feed = std::move(current_feeds.front());
      return;
   }

   // *** Begin Median Calculations ***
   price_feed median_feed;
   const auto median_itr = current_feeds.begin() + current_feeds.size() / 2;
#define CALCULATE_MEDIAN_VALUE(r, data, field_name) \
   std::nth_element( current_feeds.begin(), median_itr, current_feeds.end(), \
                     [](const price_feed& a, const price_feed& b) { \
      return a.field_name < b.field_name; \
   }); \
   median_feed.field_name = median_itr->get().field_name;

   BOOST_PP_SEQ_FOR_EACH( CALCULATE_MEDIAN_VALUE, ~, GRAPHENE_PRICE_FEED_FIELDS )
#undef CALCULATE_MEDIAN_VALUE
   // *** End Median Calculations ***

   current_feed = median_feed;
}

asset asset_object::amount_from_string(string amount_string) const
{ try {
   bool negative_found = false;
   bool decimal_found = false;
   for( const char c : amount_string )
   {
      if( isdigit( c ) )
         continue;

      if( c == '-' && !negative_found )
      {
         negative_found = true;
         continue;
      }

      if( c == '.' && !decimal_found )
      {
         decimal_found = true;
         continue;
      }

      FC_THROW( (amount_string) );
   }

   share_type satoshis = 0;

   share_type scaled_precision = asset::scaled_precision( precision );

   const auto decimal_pos = amount_string.find( '.' );
   const string lhs = amount_string.substr( negative_found, decimal_pos );
   if( !lhs.empty() )
      satoshis += fc::safe<int64_t>(std::stoll(lhs)) *= scaled_precision;

   if( decimal_found )
   {
      const size_t max_rhs_size = std::to_string( scaled_precision.value ).substr( 1 ).size();

      string rhs = amount_string.substr( decimal_pos + 1 );
      FC_ASSERT( rhs.size() <= max_rhs_size );

      while( rhs.size() < max_rhs_size )
         rhs += '0';

      if( !rhs.empty() )
         satoshis += std::stoll( rhs );
   }

   FC_ASSERT( satoshis <= GRAPHENE_MAX_SHARE_SUPPLY );

   if( negative_found )
      satoshis *= -1;

   return amount(satoshis);
   } FC_CAPTURE_AND_RETHROW( (amount_string) ) }

string asset_object::amount_to_string(share_type amount) const
{
   share_type scaled_precision = 1;
   for( uint8_t i = 0; i < precision; ++i )
      scaled_precision *= 10;
   assert(scaled_precision > 0);

   string result = fc::to_string(amount.value / scaled_precision.value);
   auto decimals = amount.value % scaled_precision.value;
   if( decimals )
      result += "." + fc::to_string(scaled_precision.value + decimals).erase(0,1);
   return result;
}
<commit_msg>fix reduce bug<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/database.hpp>

using namespace graphene::chain;
using namespace boost::multiprecision;

share_type asset_lock_data_object::get_profit(share_type tolocking_balance,uint32_t lock_period,const database &_db)const
{
	return (asset(tolocking_balance, asset_id)*_get_interest(lock_period, _db) - asset(tolocking_balance, asset_id)).amount;
}

Interest asset_lock_data_object::_get_interest(uint32_t lock_period,const database &_db)const{

   asset_object target_asset_obj=asset_id(_db);
   int32_t lock_days=lock_period/FCC_INTEREST_DAY;
   share_type max_to_deposit_balance_year = target_asset_obj.dynamic_data(_db).current_supply - (lock_coin_day / coin_day(FCC_INTEREST_YEAR)).value.to_uint64();
   asset  base_asset(FCC_INTEREST_BASE_SUPPLY, asset_id);

   static Interest top_of_interest = Interest();

   if (top_of_interest == Interest()) // yet not calculated
   {
	   asset result = base_asset;
	   for (uint32_t i = 0; i<FCC_INTEREST_DAYS_YEAR; i++)
	   {
		   result = result*nominal_interest_perday;
	   }
	   top_of_interest = Interest(base_asset, result);
   }

   auto result = base_asset;
   for (uint32_t i = 0; i<lock_days; i++)
   {
	   result = result*nominal_interest_perday;
   }

   int32_t pecent_of_year = (lock_days - FCC_INTEREST_DAYS_YEAR)*GRAPHENE_100_PERCENT / FCC_INTEREST_DAYS_YEAR;

   int64_t reward_rate = GRAPHENE_100_PERCENT + pecent_of_year * reward_coefficient / GRAPHENE_100_PERCENT;

   uint128_t pre_profile = uint128_t((result - base_asset).amount.value)*uint128_t(reward_rate) / GRAPHENE_100_PERCENT;

   uint128_t max_need_pool;
   {
      uint128_t quote=uint128_t(top_of_interest.quote.amount.value);
      uint128_t base=uint128_t(top_of_interest.base.amount.value);
      uint128_t max_to_deposit=uint128_t(max_to_deposit_balance_year.value);

      FC_ASSERT(quote>=base," year interest  must >1");       // quote>base ,don`t worry overflow

      max_need_pool=(quote*max_to_deposit)/base-max_to_deposit;
   }

   auto actual_profile = pre_profile * uint128_t(interest_pool.value) / max_need_pool;

   asset res_asset = asset(actual_profile.convert_to<uint64_t>(), asset_id) + base_asset;

   return Interest(base_asset,res_asset);
}

share_type asset_bitasset_data_object::max_force_settlement_volume(share_type current_supply) const
{
   if( options.maximum_force_settlement_volume == 0 )
      return 0;
   if( options.maximum_force_settlement_volume == GRAPHENE_100_PERCENT )
      return current_supply + force_settled_volume;

   fc::uint128 volume = current_supply.value + force_settled_volume.value;
   volume *= options.maximum_force_settlement_volume;
   volume /= GRAPHENE_100_PERCENT;
   return volume.to_uint64();
}

void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point_sec current_time)
{
   current_feed_publication_time = current_time;
   vector<std::reference_wrapper<const price_feed>> current_feeds;
   for( const pair<account_id_type, pair<time_point_sec,price_feed>>& f : feeds )
   {
      if( (current_time - f.second.first).to_seconds() < options.feed_lifetime_sec &&
          f.second.first != time_point_sec() )
      {
         current_feeds.emplace_back(f.second.second);
         current_feed_publication_time = std::min(current_feed_publication_time, f.second.first);
      }
   }

   // If there are no valid feeds, or the number available is less than the minimum to calculate a median...
   if( current_feeds.size() < options.minimum_feeds )
   {
      //... don't calculate a median, and set a null feed
      current_feed_publication_time = current_time;
      current_feed = price_feed();
      return;
   }
   if( current_feeds.size() == 1 )
   {
      current_feed = std::move(current_feeds.front());
      return;
   }

   // *** Begin Median Calculations ***
   price_feed median_feed;
   const auto median_itr = current_feeds.begin() + current_feeds.size() / 2;
#define CALCULATE_MEDIAN_VALUE(r, data, field_name) \
   std::nth_element( current_feeds.begin(), median_itr, current_feeds.end(), \
                     [](const price_feed& a, const price_feed& b) { \
      return a.field_name < b.field_name; \
   }); \
   median_feed.field_name = median_itr->get().field_name;

   BOOST_PP_SEQ_FOR_EACH( CALCULATE_MEDIAN_VALUE, ~, GRAPHENE_PRICE_FEED_FIELDS )
#undef CALCULATE_MEDIAN_VALUE
   // *** End Median Calculations ***

   current_feed = median_feed;
}

asset asset_object::amount_from_string(string amount_string) const
{ try {
   bool negative_found = false;
   bool decimal_found = false;
   for( const char c : amount_string )
   {
      if( isdigit( c ) )
         continue;

      if( c == '-' && !negative_found )
      {
         negative_found = true;
         continue;
      }

      if( c == '.' && !decimal_found )
      {
         decimal_found = true;
         continue;
      }

      FC_THROW( (amount_string) );
   }

   share_type satoshis = 0;

   share_type scaled_precision = asset::scaled_precision( precision );

   const auto decimal_pos = amount_string.find( '.' );
   const string lhs = amount_string.substr( negative_found, decimal_pos );
   if( !lhs.empty() )
      satoshis += fc::safe<int64_t>(std::stoll(lhs)) *= scaled_precision;

   if( decimal_found )
   {
      const size_t max_rhs_size = std::to_string( scaled_precision.value ).substr( 1 ).size();

      string rhs = amount_string.substr( decimal_pos + 1 );
      FC_ASSERT( rhs.size() <= max_rhs_size );

      while( rhs.size() < max_rhs_size )
         rhs += '0';

      if( !rhs.empty() )
         satoshis += std::stoll( rhs );
   }

   FC_ASSERT( satoshis <= GRAPHENE_MAX_SHARE_SUPPLY );

   if( negative_found )
      satoshis *= -1;

   return amount(satoshis);
   } FC_CAPTURE_AND_RETHROW( (amount_string) ) }

string asset_object::amount_to_string(share_type amount) const
{
   share_type scaled_precision = 1;
   for( uint8_t i = 0; i < precision; ++i )
      scaled_precision *= 10;
   assert(scaled_precision > 0);

   string result = fc::to_string(amount.value / scaled_precision.value);
   auto decimals = amount.value % scaled_precision.value;
   if( decimals )
      result += "." + fc::to_string(scaled_precision.value + decimals).erase(0,1);
   return result;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 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 "httprpc.h"

#include "base58.h"
#include "chainparams.h"
#include "httpserver.h"
#include "rpc/protocol.h"
#include "rpc/server.h"
#include "random.h"
#include "sync.h"
#include "util.h"
#include "utilstrencodings.h"
#include "ui_interface.h"
#include "crypto/hmac_sha256.h"
#include <stdio.h>
#include "utilstrencodings.h"

#include <boost/algorithm/string.hpp> // boost::trim
#include <boost/foreach.hpp> //BOOST_FOREACH

/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
 * re-lock the wellet.
 */
class HTTPRPCTimer : public RPCTimerBase
{
public:
    HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
        ev(eventBase, false, func)
    {
        struct timeval tv;
        tv.tv_sec = millis/1000;
        tv.tv_usec = (millis%1000)*1000;
        ev.trigger(&tv);
    }
private:
    HTTPEvent ev;
};

class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
    HTTPRPCTimerInterface(struct event_base* base) : base(base)
    {
    }
    const char* Name()
    {
        return "HTTP";
    }
    RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
    {
        return new HTTPRPCTimer(base, func, millis);
    }
private:
    struct event_base* base;
};

/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;

static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
    // Send error reply from json-rpc error object
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
    int code = find_value(objError, "code").get_int();

    if (code == RPC_INVALID_REQUEST)
        nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND)
        nStatus = HTTP_NOT_FOUND;

    std::string strReply = JSONRPCReply(NullUniValue, objError, id);

    req->WriteHeader("Content-Type", "application/json");
    req->WriteReply(nStatus, strReply);
}

//This function checks username and password against -rpcauth
//entries from config file.
static bool multiUserAuthorized(std::string strUserPass)
{
    if (strUserPass.find(":") == std::string::npos) {
        return false;
    }
    std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
    std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);

    if (mapMultiArgs.count("-rpcauth") > 0) {
        //Search for multi-user login/pass "rpcauth" from config
        BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
        {
            std::vector<std::string> vFields;
            boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
            if (vFields.size() != 3) {
                //Incorrect formatting in config file
                continue;
            }

            std::string strName = vFields[0];
            if (!TimingResistantEqual(strName, strUser)) {
                continue;
            }

            std::string strSalt = vFields[1];
            std::string strHash = vFields[2];

            unsigned int KEY_SIZE = 32;
            unsigned char *out = new unsigned char[KEY_SIZE];

            CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
            std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
            std::string strHashFromPass = HexStr(hexvec);

            if (TimingResistantEqual(strHashFromPass, strHash)) {
                return true;
            }
        }
    }
    return false;
}

static bool RPCAuthorized(const std::string& strAuth)
{
    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
        return false;
    if (strAuth.substr(0, 6) != "Basic ")
        return false;
    std::string strUserPass64 = strAuth.substr(6);
    boost::trim(strUserPass64);
    std::string strUserPass = DecodeBase64(strUserPass64);

    //Check if authorized under single-user field
    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
        return true;
    }
    return multiUserAuthorized(strUserPass);
}

static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
{
    // JSONRPC handles only POST
    if (req->GetRequestMethod() != HTTPRequest::POST) {
        req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
        return false;
    }
    // Check authorization
    std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
    if (!authHeader.first) {
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    if (!RPCAuthorized(authHeader.second)) {
        LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());

        /* Deter brute-forcing
           If this results in a DoS the user really
           shouldn't have their RPC port exposed. */
        MilliSleep(250);

        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    JSONRequest jreq;
    try {
        // Parse request
        UniValue valRequest;
        if (!valRequest.read(req->ReadBody()))
            throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");

        std::string strReply;
        // singleton request
        if (valRequest.isObject()) {
            jreq.parse(valRequest);

            UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);

            // Send reply
            strReply = JSONRPCReply(result, NullUniValue, jreq.id);

        // array of requests
        } else if (valRequest.isArray())
            strReply = JSONRPCExecBatch(valRequest.get_array());
        else
            throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

        req->WriteHeader("Content-Type", "application/json");
        req->WriteReply(HTTP_OK, strReply);
    } catch (const UniValue& objError) {
        JSONErrorReply(req, objError, jreq.id);
        return false;
    } catch (const std::exception& e) {
        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
        return false;
    }
    return true;
}

static bool InitRPCAuthentication()
{
    if (mapArgs["-rpcpassword"] == "")
    {
        LogPrintf("No rpcpassword set - using random cookie authentication\n");
        if (!GenerateAuthCookie(&strRPCUserColonPass)) {
            uiInterface.ThreadSafeMessageBox(
                _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
                "", CClientUIInterface::MSG_ERROR);
            return false;
        }
    } else {
        LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.");
        strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
    }
    return true;
}

bool StartHTTPRPC()
{
    LogPrint("rpc", "Starting HTTP RPC server\n");
    if (!InitRPCAuthentication())
        return false;

    RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);

    assert(EventBase());
    httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
    RPCSetTimerInterface(httpRPCTimerInterface);
    return true;
}

void InterruptHTTPRPC()
{
    LogPrint("rpc", "Interrupting HTTP RPC server\n");
}

void StopHTTPRPC()
{
    LogPrint("rpc", "Stopping HTTP RPC server\n");
    UnregisterHTTPHandler("/", true);
    if (httpRPCTimerInterface) {
        RPCUnsetTimerInterface(httpRPCTimerInterface);
        delete httpRPCTimerInterface;
        httpRPCTimerInterface = 0;
    }
}
<commit_msg>rpc: Add WWW-Authenticate header to 401 response<commit_after>// Copyright (c) 2015 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 "httprpc.h"

#include "base58.h"
#include "chainparams.h"
#include "httpserver.h"
#include "rpc/protocol.h"
#include "rpc/server.h"
#include "random.h"
#include "sync.h"
#include "util.h"
#include "utilstrencodings.h"
#include "ui_interface.h"
#include "crypto/hmac_sha256.h"
#include <stdio.h>
#include "utilstrencodings.h"

#include <boost/algorithm/string.hpp> // boost::trim
#include <boost/foreach.hpp> //BOOST_FOREACH

/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";

/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
 * re-lock the wellet.
 */
class HTTPRPCTimer : public RPCTimerBase
{
public:
    HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
        ev(eventBase, false, func)
    {
        struct timeval tv;
        tv.tv_sec = millis/1000;
        tv.tv_usec = (millis%1000)*1000;
        ev.trigger(&tv);
    }
private:
    HTTPEvent ev;
};

class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
    HTTPRPCTimerInterface(struct event_base* base) : base(base)
    {
    }
    const char* Name()
    {
        return "HTTP";
    }
    RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
    {
        return new HTTPRPCTimer(base, func, millis);
    }
private:
    struct event_base* base;
};

/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;

static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
    // Send error reply from json-rpc error object
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
    int code = find_value(objError, "code").get_int();

    if (code == RPC_INVALID_REQUEST)
        nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND)
        nStatus = HTTP_NOT_FOUND;

    std::string strReply = JSONRPCReply(NullUniValue, objError, id);

    req->WriteHeader("Content-Type", "application/json");
    req->WriteReply(nStatus, strReply);
}

//This function checks username and password against -rpcauth
//entries from config file.
static bool multiUserAuthorized(std::string strUserPass)
{
    if (strUserPass.find(":") == std::string::npos) {
        return false;
    }
    std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
    std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);

    if (mapMultiArgs.count("-rpcauth") > 0) {
        //Search for multi-user login/pass "rpcauth" from config
        BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
        {
            std::vector<std::string> vFields;
            boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
            if (vFields.size() != 3) {
                //Incorrect formatting in config file
                continue;
            }

            std::string strName = vFields[0];
            if (!TimingResistantEqual(strName, strUser)) {
                continue;
            }

            std::string strSalt = vFields[1];
            std::string strHash = vFields[2];

            unsigned int KEY_SIZE = 32;
            unsigned char *out = new unsigned char[KEY_SIZE];

            CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
            std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
            std::string strHashFromPass = HexStr(hexvec);

            if (TimingResistantEqual(strHashFromPass, strHash)) {
                return true;
            }
        }
    }
    return false;
}

static bool RPCAuthorized(const std::string& strAuth)
{
    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
        return false;
    if (strAuth.substr(0, 6) != "Basic ")
        return false;
    std::string strUserPass64 = strAuth.substr(6);
    boost::trim(strUserPass64);
    std::string strUserPass = DecodeBase64(strUserPass64);

    //Check if authorized under single-user field
    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
        return true;
    }
    return multiUserAuthorized(strUserPass);
}

static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
{
    // JSONRPC handles only POST
    if (req->GetRequestMethod() != HTTPRequest::POST) {
        req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
        return false;
    }
    // Check authorization
    std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
    if (!authHeader.first) {
        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    if (!RPCAuthorized(authHeader.second)) {
        LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());

        /* Deter brute-forcing
           If this results in a DoS the user really
           shouldn't have their RPC port exposed. */
        MilliSleep(250);

        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    JSONRequest jreq;
    try {
        // Parse request
        UniValue valRequest;
        if (!valRequest.read(req->ReadBody()))
            throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");

        std::string strReply;
        // singleton request
        if (valRequest.isObject()) {
            jreq.parse(valRequest);

            UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);

            // Send reply
            strReply = JSONRPCReply(result, NullUniValue, jreq.id);

        // array of requests
        } else if (valRequest.isArray())
            strReply = JSONRPCExecBatch(valRequest.get_array());
        else
            throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

        req->WriteHeader("Content-Type", "application/json");
        req->WriteReply(HTTP_OK, strReply);
    } catch (const UniValue& objError) {
        JSONErrorReply(req, objError, jreq.id);
        return false;
    } catch (const std::exception& e) {
        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
        return false;
    }
    return true;
}

static bool InitRPCAuthentication()
{
    if (mapArgs["-rpcpassword"] == "")
    {
        LogPrintf("No rpcpassword set - using random cookie authentication\n");
        if (!GenerateAuthCookie(&strRPCUserColonPass)) {
            uiInterface.ThreadSafeMessageBox(
                _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
                "", CClientUIInterface::MSG_ERROR);
            return false;
        }
    } else {
        LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.");
        strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
    }
    return true;
}

bool StartHTTPRPC()
{
    LogPrint("rpc", "Starting HTTP RPC server\n");
    if (!InitRPCAuthentication())
        return false;

    RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);

    assert(EventBase());
    httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
    RPCSetTimerInterface(httpRPCTimerInterface);
    return true;
}

void InterruptHTTPRPC()
{
    LogPrint("rpc", "Interrupting HTTP RPC server\n");
}

void StopHTTPRPC()
{
    LogPrint("rpc", "Stopping HTTP RPC server\n");
    UnregisterHTTPHandler("/", true);
    if (httpRPCTimerInterface) {
        RPCUnsetTimerInterface(httpRPCTimerInterface);
        delete httpRPCTimerInterface;
        httpRPCTimerInterface = 0;
    }
}
<|endoftext|>