2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-07-30 15:22:07 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "PaymentGateService.h"
|
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winsvc.h>
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define SERVICE_NAME "Payment Gate"
|
|
|
|
|
|
|
|
PaymentGateService* ppg;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
SERVICE_STATUS_HANDLE serviceStatusHandle;
|
|
|
|
|
|
|
|
std::string GetLastErrorMessage(DWORD errorMessageID)
|
|
|
|
{
|
|
|
|
LPSTR messageBuffer = nullptr;
|
|
|
|
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, errorMessageID, 0, (LPSTR)&messageBuffer, 0, NULL);
|
|
|
|
|
|
|
|
std::string message(messageBuffer, size);
|
|
|
|
|
|
|
|
LocalFree(messageBuffer);
|
|
|
|
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __stdcall serviceHandler(DWORD fdwControl) {
|
|
|
|
if (fdwControl == SERVICE_CONTROL_STOP) {
|
|
|
|
Logging::LoggerRef log(ppg->getLogger(), "serviceHandler");
|
2015-10-01 15:27:18 +00:00
|
|
|
log(Logging::INFO, Logging::BRIGHT_YELLOW) << "Stop signal caught";
|
2015-07-30 15:22:07 +00:00
|
|
|
|
|
|
|
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_STOP_PENDING, 0, NO_ERROR, 0, 0, 0 };
|
|
|
|
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
|
|
|
|
|
|
|
ppg->stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __stdcall serviceMain(DWORD dwArgc, char **lpszArgv) {
|
|
|
|
Logging::LoggerRef logRef(ppg->getLogger(), "WindowsService");
|
|
|
|
|
|
|
|
serviceStatusHandle = RegisterServiceCtrlHandler("PaymentGate", serviceHandler);
|
|
|
|
if (serviceStatusHandle == NULL) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make RegisterServiceCtrlHandler call: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_START_PENDING, 0, NO_ERROR, 0, 1, 3000 };
|
|
|
|
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_RUNNING, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0 };
|
|
|
|
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
ppg->run();
|
|
|
|
} catch (std::exception& ex) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Error occurred: " << ex.what();
|
2015-07-30 15:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0 };
|
|
|
|
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int daemonize() {
|
|
|
|
pid_t pid;
|
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
if (pid < 0)
|
|
|
|
return pid;
|
|
|
|
|
|
|
|
if (pid > 0)
|
|
|
|
return pid;
|
|
|
|
|
|
|
|
if (setsid() < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
signal(SIGCHLD, SIG_IGN);
|
|
|
|
signal(SIGHUP, SIG_IGN);
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
if (pid < 0)
|
|
|
|
return pid;
|
|
|
|
|
|
|
|
if (pid > 0)
|
|
|
|
return pid;
|
|
|
|
|
|
|
|
umask(0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int runDaemon() {
|
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
SERVICE_TABLE_ENTRY serviceTable[] {
|
|
|
|
{ "Payment Gate", serviceMain },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
2015-10-01 15:27:18 +00:00
|
|
|
Logging::LoggerRef logRef(ppg->getLogger(), "RunService");
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
if (StartServiceCtrlDispatcher(serviceTable) != TRUE) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't start service: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::INFO) << "Service stopped";
|
2015-07-30 15:22:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int daemonResult = daemonize();
|
|
|
|
if (daemonResult > 0) {
|
|
|
|
//parent
|
|
|
|
return 0;
|
|
|
|
} else if (daemonResult < 0) {
|
2015-10-01 15:27:18 +00:00
|
|
|
//error occurred
|
2015-07-30 15:22:07 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ppg->run();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int registerService() {
|
|
|
|
#ifdef WIN32
|
|
|
|
Logging::LoggerRef logRef(ppg->getLogger(), "ServiceRegistrator");
|
|
|
|
|
|
|
|
char pathBuff[MAX_PATH];
|
|
|
|
std::string modulePath;
|
|
|
|
SC_HANDLE scManager = NULL;
|
|
|
|
SC_HANDLE scService = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (GetModuleFileName(NULL, pathBuff, ARRAYSIZE(pathBuff)) == 0) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "GetModuleFileName failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
modulePath.assign(pathBuff);
|
|
|
|
|
|
|
|
std::string moduleDir = modulePath.substr(0, modulePath.find_last_of('\\') + 1);
|
|
|
|
modulePath += " --config=" + moduleDir + "payment_service.conf -d";
|
|
|
|
|
|
|
|
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
|
|
|
if (scManager == NULL) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
scService = CreateService(scManager, SERVICE_NAME, NULL, SERVICE_QUERY_STATUS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
|
|
|
|
SERVICE_ERROR_NORMAL, modulePath.c_str(), NULL, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (scService == NULL) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "CreateService failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
logRef(Logging::INFO) << "Service is registered successfully";
|
|
|
|
logRef(Logging::INFO) << "Please make sure " << moduleDir + "payment_service.conf" << " exists";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scManager) {
|
|
|
|
CloseServiceHandle(scManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scService) {
|
|
|
|
CloseServiceHandle(scService);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int unregisterService() {
|
|
|
|
#ifdef WIN32
|
|
|
|
Logging::LoggerRef logRef(ppg->getLogger(), "ServiceDeregistrator");
|
|
|
|
|
|
|
|
SC_HANDLE scManager = NULL;
|
|
|
|
SC_HANDLE scService = NULL;
|
|
|
|
SERVICE_STATUS ssSvcStatus = { };
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
|
|
if (scManager == NULL) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
scService = OpenService(scManager, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
|
|
|
|
if (scService == NULL) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenService failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ControlService(scService, SERVICE_CONTROL_STOP, &ssSvcStatus)) {
|
|
|
|
logRef(Logging::INFO) << "Stopping " << SERVICE_NAME;
|
|
|
|
Sleep(1000);
|
|
|
|
|
|
|
|
while (QueryServiceStatus(scService, &ssSvcStatus)) {
|
|
|
|
if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) {
|
|
|
|
logRef(Logging::INFO) << "Waiting...";
|
|
|
|
Sleep(1000);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) {
|
|
|
|
logRef(Logging::INFO) << SERVICE_NAME << " is stopped";
|
|
|
|
} else {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << SERVICE_NAME << " failed to stop" << std::endl;
|
2015-07-30 15:22:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DeleteService(scService)) {
|
2015-10-01 15:27:18 +00:00
|
|
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "DeleteService failed with error: " << GetLastErrorMessage(GetLastError());
|
2015-07-30 15:22:07 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
logRef(Logging::INFO) << SERVICE_NAME << " is removed";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scManager) {
|
|
|
|
CloseServiceHandle(scManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scService) {
|
|
|
|
CloseServiceHandle(scService);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
PaymentGateService pg;
|
|
|
|
ppg = &pg;
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (!pg.init(argc, argv)) {
|
|
|
|
return 0; //help message requested or so
|
|
|
|
}
|
|
|
|
|
|
|
|
Logging::LoggerRef(pg.getLogger(), "main")(Logging::INFO) << "PaymentService " << " v" << PROJECT_VERSION_LONG;
|
|
|
|
|
|
|
|
const auto& config = pg.getConfig();
|
|
|
|
|
2015-12-09 13:19:03 +00:00
|
|
|
if (config.gateConfiguration.generateNewContainer) {
|
2015-07-30 15:22:07 +00:00
|
|
|
System::Dispatcher d;
|
|
|
|
generateNewWallet(pg.getCurrency(), pg.getWalletConfig(), pg.getLogger(), d);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.gateConfiguration.registerService) {
|
|
|
|
return registerService();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.gateConfiguration.unregisterService) {
|
|
|
|
return unregisterService();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.gateConfiguration.daemonize) {
|
|
|
|
if (runDaemon() != 0) {
|
|
|
|
throw std::runtime_error("Failed to start daemon");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pg.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (PaymentService::ConfigurationError& ex) {
|
|
|
|
std::cerr << "Configuration error: " << ex.what() << std::endl;
|
|
|
|
return 1;
|
|
|
|
} catch (std::exception& ex) {
|
|
|
|
std::cerr << "Fatal error: " << ex.what() << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|