mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:arangodb/arangodb into devel
This commit is contained in:
commit
bcfb356e9e
|
@ -3,7 +3,7 @@ set -e
|
||||||
|
|
||||||
TAG=1
|
TAG=1
|
||||||
|
|
||||||
if [ "$1" == "--no-tag" ]; then
|
if [ "$1" == "--no-commit" ]; then
|
||||||
TAG=0
|
TAG=0
|
||||||
shift
|
shift
|
||||||
fi
|
fi
|
||||||
|
@ -32,9 +32,9 @@ VERSION_MINOR=`echo $VERSION | awk -F. '{print $2}'`
|
||||||
VERSION_REVISION=`echo $VERSION | awk -F. '{print $3}'`
|
VERSION_REVISION=`echo $VERSION | awk -F. '{print $3}'`
|
||||||
|
|
||||||
cat CMakeLists.txt \
|
cat CMakeLists.txt \
|
||||||
| sed -e "s~set(ARANGODB_VERSION_MAJOR.*~set(ARANGODB_VERSION_MAJOR \"$VERSION_MAJOR\")" \
|
| sed -e "s~set(ARANGODB_VERSION_MAJOR.*~set(ARANGODB_VERSION_MAJOR \"$VERSION_MAJOR\")~" \
|
||||||
| sed -e "s~set(ARANGODB_VERSION_MINOR.*~set(ARANGODB_VERSION_MINOR \"$VERSION_MINOR\")" \
|
| sed -e "s~set(ARANGODB_VERSION_MINOR.*~set(ARANGODB_VERSION_MINOR \"$VERSION_MINOR\")~" \
|
||||||
| sed -e "s~set(ARANGODB_VERSION_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")" \
|
| sed -e "s~set(ARANGODB_VERSION_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")~" \
|
||||||
> CMakeLists.txt.tmp
|
> CMakeLists.txt.tmp
|
||||||
|
|
||||||
mv CMakeLists.txt.tmp CMakeLists.txt
|
mv CMakeLists.txt.tmp CMakeLists.txt
|
||||||
|
@ -42,18 +42,22 @@ mv CMakeLists.txt.tmp CMakeLists.txt
|
||||||
CMAKE_CONFIGURE="-DUSE_MAINTAINER_MODE=ON"
|
CMAKE_CONFIGURE="-DUSE_MAINTAINER_MODE=ON"
|
||||||
|
|
||||||
if [ `uname` == "Darwin" ]; then
|
if [ `uname` == "Darwin" ]; then
|
||||||
CMAKE_CONFIGURE="${CMAKE_CONFIGURE} -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl"
|
CMAKE_CONFIGURE="${CMAKE_CONFIGURE} -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test 0 = 1; then
|
||||||
|
echo "COMPILING"
|
||||||
rm -rf build && mkdir build
|
rm -rf build && mkdir build
|
||||||
|
|
||||||
./scripts/jsint.sh
|
|
||||||
|
|
||||||
(
|
(
|
||||||
cd build
|
cd build
|
||||||
cmake .. ${CMAKE_CONFIGURE}
|
cmake .. ${CMAKE_CONFIGURE}
|
||||||
make -j 8
|
make -j 8
|
||||||
)
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "LINTING"
|
||||||
|
./utils/jslint.sh
|
||||||
|
|
||||||
git add -f \
|
git add -f \
|
||||||
README \
|
README \
|
||||||
|
@ -67,13 +71,13 @@ git add -f \
|
||||||
js/common/bootstrap/errors.js \
|
js/common/bootstrap/errors.js \
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
|
|
||||||
(
|
echo "SWAGGER"
|
||||||
cd build
|
./utils/generateSwagger.sh
|
||||||
make swagger
|
|
||||||
)
|
|
||||||
|
|
||||||
./scripts/generateExamples
|
echo "EXAMPLES"
|
||||||
|
./utils/generateExamples.sh
|
||||||
|
|
||||||
|
echo "GRUNT"
|
||||||
(
|
(
|
||||||
cd js/apps/system/_admin/aardvark/APP
|
cd js/apps/system/_admin/aardvark/APP
|
||||||
npm install --only=dev
|
npm install --only=dev
|
||||||
|
@ -82,6 +86,7 @@ git add -f \
|
||||||
|
|
||||||
git add -f Documentation/Examples/*.generated
|
git add -f Documentation/Examples/*.generated
|
||||||
|
|
||||||
|
echo "DOCUMENTATION"
|
||||||
cd Documentation/Books; make
|
cd Documentation/Books; make
|
||||||
|
|
||||||
case "$TAG" in
|
case "$TAG" in
|
||||||
|
@ -94,6 +99,8 @@ case "$TAG" in
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "$TAG" == "1" ]; then
|
if [ "$TAG" == "1" ]; then
|
||||||
|
echo "COMMIT"
|
||||||
|
|
||||||
git commit -m "release version $VERSION" -a
|
git commit -m "release version $VERSION" -a
|
||||||
git push
|
git push
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,16 @@
|
||||||
/// @author Kaveh Vahedipour
|
/// @author Kaveh Vahedipour
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "Rest/HttpRequest.h"
|
|
||||||
#include "Rest/Version.h"
|
|
||||||
#include "RestAgencyHandler.h"
|
#include "RestAgencyHandler.h"
|
||||||
|
|
||||||
#include "Agency/Agent.h"
|
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
#include <velocypack/Builder.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
#include "Agency/Agent.h"
|
||||||
|
#include "Basics/StaticStrings.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
|
#include "Rest/HttpRequest.h"
|
||||||
|
#include "Rest/Version.h"
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
|
|
||||||
|
@ -74,8 +74,7 @@ void RestAgencyHandler::redirectRequest(arangodb::consensus::id_t leaderId) {
|
||||||
std::string url = Endpoint::uriForm(
|
std::string url = Endpoint::uriForm(
|
||||||
_agent->config().endpoints.at(leaderId)) + _request->requestPath();
|
_agent->config().endpoints.at(leaderId)) + _request->requestPath();
|
||||||
createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT);
|
createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT);
|
||||||
static std::string const location = "location";
|
_response->setHeaderNC(StaticStrings::Location, url);
|
||||||
_response->setHeaderNC(location, url);
|
|
||||||
} catch (std::exception const& e) {
|
} catch (std::exception const& e) {
|
||||||
LOG_TOPIC(WARN, Logger::AGENCY) << e.what();
|
LOG_TOPIC(WARN, Logger::AGENCY) << e.what();
|
||||||
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
generateError(GeneralResponse::ResponseCode::SERVER_ERROR,
|
||||||
|
|
|
@ -84,7 +84,7 @@ HttpCommTask::HttpCommTask(HttpServer* server, TRI_socket_t socket,
|
||||||
<< _connectionInfo.clientPort;
|
<< _connectionInfo.clientPort;
|
||||||
|
|
||||||
// release the statistics object we got from the socket task first
|
// release the statistics object we got from the socket task first
|
||||||
// this is required at the moment for proper statistics calculation
|
// this is required at the moment for proper statistics calculation
|
||||||
connectionStatisticsAgentSetHttp();
|
connectionStatisticsAgentSetHttp();
|
||||||
ConnectionStatisticsAgent::release();
|
ConnectionStatisticsAgent::release();
|
||||||
|
|
||||||
|
@ -350,8 +350,10 @@ bool HttpCommTask::processRead() {
|
||||||
TRI_invalidatesocket(&_commSocket);
|
TRI_invalidatesocket(&_commSocket);
|
||||||
|
|
||||||
// might delete this
|
// might delete this
|
||||||
// note that as we closed the socket above, the response will not make it to
|
// note that as we closed the socket above, the response will not make
|
||||||
// the client! will result in a "Empty reply from server" error in curl etc.
|
// it to
|
||||||
|
// the client! will result in a "Empty reply from server" error in
|
||||||
|
// curl etc.
|
||||||
handleResponse(&response);
|
handleResponse(&response);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -536,14 +538,12 @@ bool HttpCommTask::processRead() {
|
||||||
else {
|
else {
|
||||||
HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED,
|
HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED,
|
||||||
compatibility);
|
compatibility);
|
||||||
static std::string const wwwAuthenticate = "www-authenticate";
|
|
||||||
|
|
||||||
if (sendWwwAuthenticateHeader()) {
|
if (sendWwwAuthenticateHeader()) {
|
||||||
static std::string const realm =
|
static std::string const realm =
|
||||||
"basic realm=\"" +
|
"basic realm=\"" +
|
||||||
_server->handlerFactory()->authenticationRealm(_request) + "\"";
|
_server->handlerFactory()->authenticationRealm(_request) + "\"";
|
||||||
|
|
||||||
response.setHeaderNC(wwwAuthenticate, realm);
|
response.setHeaderNC(StaticStrings::WwwAuthenticate, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearRequest();
|
clearRequest();
|
||||||
|
@ -608,32 +608,27 @@ void HttpCommTask::addResponse(HttpResponse* response) {
|
||||||
// access-control-allow-origin header now
|
// access-control-allow-origin header now
|
||||||
LOG(TRACE) << "handling CORS response";
|
LOG(TRACE) << "handling CORS response";
|
||||||
|
|
||||||
static std::string const accessControl = "access-control-expose-headers";
|
|
||||||
static std::string const exposedHeaders =
|
static std::string const exposedHeaders =
|
||||||
"etag, content-encoding, content-length, location, "
|
"etag, content-encoding, content-length, location, "
|
||||||
"server, x-arango-errors, x-arango-async-id";
|
"server, x-arango-errors, x-arango-async-id";
|
||||||
|
|
||||||
response->setHeaderNC(accessControl, exposedHeaders);
|
response->setHeaderNC(StaticStrings::AccessControlExposeHeaders,
|
||||||
|
exposedHeaders);
|
||||||
|
|
||||||
// send back original value of "Origin" header
|
// send back original value of "Origin" header
|
||||||
static std::string const accessOrigin = "access-control-allow-origin";
|
response->setHeaderNC(StaticStrings::AccessControlAllowOrigin, _origin);
|
||||||
|
|
||||||
response->setHeaderNC(accessOrigin, _origin);
|
|
||||||
|
|
||||||
// send back "Access-Control-Allow-Credentials" header
|
// send back "Access-Control-Allow-Credentials" header
|
||||||
static std::string const accessCredentials =
|
response->setHeaderNC(StaticStrings::AccessControlAllowCredentials,
|
||||||
"access-control-allow-credentials";
|
|
||||||
|
|
||||||
response->setHeaderNC(accessCredentials,
|
|
||||||
(_denyCredentials ? "false" : "true"));
|
(_denyCredentials ? "false" : "true"));
|
||||||
}
|
}
|
||||||
// CORS request handling EOF
|
// CORS request handling EOF
|
||||||
|
|
||||||
// set "connection" header
|
// set "connection" header
|
||||||
// keep-alive is the default
|
// keep-alive is the default
|
||||||
static std::string const connection = "connection";
|
response->setHeaderNC(
|
||||||
|
StaticStrings::Connection,
|
||||||
response->setHeaderNC(connection, (_closeRequested ? "Close" : "Keep-Alive"));
|
(_closeRequested ? StaticStrings::Close : StaticStrings::KeepAlive));
|
||||||
|
|
||||||
size_t const responseBodyLength = response->bodySize();
|
size_t const responseBodyLength = response->bodySize();
|
||||||
|
|
||||||
|
@ -780,40 +775,37 @@ void HttpCommTask::fillWriteBuffer() {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void HttpCommTask::processCorsOptions(uint32_t compatibility) {
|
void HttpCommTask::processCorsOptions(uint32_t compatibility) {
|
||||||
static std::string const allowedMethods = "DELETE, GET, HEAD, PATCH, POST, PUT";
|
static std::string const allowedMethods =
|
||||||
|
"DELETE, GET, HEAD, PATCH, POST, PUT";
|
||||||
|
|
||||||
HttpResponse response(GeneralResponse::ResponseCode::OK, compatibility);
|
HttpResponse response(GeneralResponse::ResponseCode::OK, compatibility);
|
||||||
|
|
||||||
static std::string const allow = "allow";
|
response.setHeaderNC(StaticStrings::Allow, allowedMethods);
|
||||||
response.setHeaderNC(allow, allowedMethods);
|
|
||||||
|
|
||||||
if (!_origin.empty()) {
|
if (!_origin.empty()) {
|
||||||
LOG(TRACE) << "got CORS preflight request";
|
LOG(TRACE) << "got CORS preflight request";
|
||||||
std::string const allowHeaders =
|
std::string const allowHeaders = StringUtils::trim(
|
||||||
StringUtils::trim(_request->header("access-control-request-headers"));
|
_request->header(StaticStrings::AccessControlRequestHeaders));
|
||||||
|
|
||||||
// send back which HTTP methods are allowed for the resource
|
// send back which HTTP methods are allowed for the resource
|
||||||
// we'll allow all
|
// we'll allow all
|
||||||
static std::string const accessControl = "access-control-allow-methods";
|
response.setHeaderNC(StaticStrings::AccessControlAllowMethods,
|
||||||
response.setHeaderNC(accessControl, allowedMethods);
|
allowedMethods);
|
||||||
|
|
||||||
if (!allowHeaders.empty()) {
|
if (!allowHeaders.empty()) {
|
||||||
// allow all extra headers the client requested
|
// allow all extra headers the client requested
|
||||||
// we don't verify them here. the worst that can happen is that the client
|
// we don't verify them here. the worst that can happen is that the client
|
||||||
// sends some broken headers and then later cannot access the data on the
|
// sends some broken headers and then later cannot access the data on the
|
||||||
// server. that's a client problem.
|
// server. that's a client problem.
|
||||||
static std::string const accessControl = "access-control-allow-headers";
|
response.setHeaderNC(StaticStrings::AccessControlAllowHeaders,
|
||||||
response.setHeaderNC(accessControl, allowHeaders);
|
allowHeaders);
|
||||||
|
|
||||||
LOG(TRACE) << "client requested validation of the following headers: "
|
LOG(TRACE) << "client requested validation of the following headers: "
|
||||||
<< allowHeaders;
|
<< allowHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set caching time (hard-coded value)
|
// set caching time (hard-coded value)
|
||||||
static std::string const accessAge = "access-control-max-age";
|
response.setHeaderNC(StaticStrings::AccessControlMaxAge, StaticStrings::N1800);
|
||||||
static std::string const maxAge = "1800";
|
|
||||||
|
|
||||||
response.setHeaderNC(accessAge, maxAge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearRequest();
|
clearRequest();
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "RestBaseHandler.h"
|
#include "RestBaseHandler.h"
|
||||||
|
|
||||||
#include "Basics/StaticStrings.h"
|
#include "Basics/StaticStrings.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
#include "Basics/VPackStringBufferAdapter.h"
|
#include "Basics/VPackStringBufferAdapter.h"
|
||||||
|
@ -149,7 +150,7 @@ void RestBaseHandler::dumpResponse(VPackSlice const& slice,
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool RestBaseHandler::returnVelocypack() const {
|
bool RestBaseHandler::returnVelocypack() const {
|
||||||
std::string const& result = _request->header(StaticStrings::AcceptHeader);
|
std::string const& result = _request->header(StaticStrings::Accept);
|
||||||
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
|
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,11 @@ HttpHandler::status_t RestVersionHandler::execute() {
|
||||||
Version::getVPack(result);
|
Version::getVPack(result);
|
||||||
|
|
||||||
if (application_features::ApplicationServer::server != nullptr) {
|
if (application_features::ApplicationServer::server != nullptr) {
|
||||||
auto server = application_features::ApplicationServer::server->getFeature<ServerFeature>("Server");
|
auto server = application_features::ApplicationServer::server
|
||||||
|
->getFeature<ServerFeature>("Server");
|
||||||
result.add("mode", VPackValue(server->operationModeString()));
|
result.add("mode", VPackValue(server->operationModeString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.close();
|
result.close();
|
||||||
}
|
}
|
||||||
result.close();
|
result.close();
|
||||||
|
|
|
@ -0,0 +1,309 @@
|
||||||
|
virtual void startupProgress() override final {
|
||||||
|
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void startupFinished() override final {
|
||||||
|
// startup finished - signalize we're running.
|
||||||
|
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void shutDownBegins() override final {
|
||||||
|
// startup finished - signalize we're running.
|
||||||
|
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR* lpszArgv) {
|
||||||
|
// register the service ctrl handler, lpszArgv[0] contains service name
|
||||||
|
ServiceStatus =
|
||||||
|
RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl);
|
||||||
|
|
||||||
|
// set start pending
|
||||||
|
SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000);
|
||||||
|
|
||||||
|
// and fire up the service
|
||||||
|
STARTUP_FUNCTION(dwArgc, lpszArgv);
|
||||||
|
|
||||||
|
// service has stopped
|
||||||
|
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
|
||||||
|
TRI_CloseWindowsEventlog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::startService(int argc, char** argv) {
|
||||||
|
SERVICE_TABLE_ENTRY ste[] = {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)ServiceMain},
|
||||||
|
{nullptr, nullptr}};
|
||||||
|
|
||||||
|
if (!StartServiceCtrlDispatcher(ste)) {
|
||||||
|
std::cerr << "FATAL: StartServiceCtrlDispatcher has failed with "
|
||||||
|
<< GetLastError() << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::installService() {
|
||||||
|
CHAR path[MAX_PATH];
|
||||||
|
|
||||||
|
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
|
||||||
|
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build command
|
||||||
|
std::string command;
|
||||||
|
|
||||||
|
command += "\"";
|
||||||
|
command += path;
|
||||||
|
command += "\"";
|
||||||
|
|
||||||
|
command += " --start-service";
|
||||||
|
|
||||||
|
// register service
|
||||||
|
InstallServiceCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::uninstallService(bool force) {
|
||||||
|
CHAR path[MAX_PATH] = "";
|
||||||
|
|
||||||
|
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
|
||||||
|
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "INFO: removing service '" << ServiceName << "'" << std::endl;
|
||||||
|
|
||||||
|
SC_HANDLE schSCManager =
|
||||||
|
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (schSCManager == 0) {
|
||||||
|
std::cerr << "FATAL: OpenSCManager failed with " << GetLastError()
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_HANDLE schService = OpenServiceA(
|
||||||
|
schSCManager, // SCManager database
|
||||||
|
ServiceName.c_str(), // name of service
|
||||||
|
DELETE |
|
||||||
|
SERVICE_QUERY_CONFIG); // first validate whether its us, then delete.
|
||||||
|
|
||||||
|
char serviceConfigMemory[8192]; // msdn says: 8k is enough.
|
||||||
|
DWORD bytesNeeded = 0;
|
||||||
|
if (QueryServiceConfig(schService,
|
||||||
|
(LPQUERY_SERVICE_CONFIGA)&serviceConfigMemory,
|
||||||
|
sizeof(serviceConfigMemory), &bytesNeeded)) {
|
||||||
|
QUERY_SERVICE_CONFIG* cfg = (QUERY_SERVICE_CONFIG*)&serviceConfigMemory;
|
||||||
|
|
||||||
|
std::string command = std::string("\"") + std::string(path) +
|
||||||
|
std::string("\" --start-service");
|
||||||
|
if (strcmp(cfg->lpBinaryPathName, command.c_str())) {
|
||||||
|
if (!force) {
|
||||||
|
std::cerr << "NOT removing service of other installation: "
|
||||||
|
<< cfg->lpBinaryPathName << " Our path is: " << path
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Removing service of other installation because of FORCE: "
|
||||||
|
<< cfg->lpBinaryPathName << "Our path is: " << path
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
|
||||||
|
if (schService == 0) {
|
||||||
|
std::cerr << "FATAL: OpenServiceA failed with " << GetLastError()
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DeleteService(schService)) {
|
||||||
|
std::cerr << "FATAL: DeleteService failed with " << GetLastError()
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(schService);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::serviceControlStart(bool waitForRunning) {
|
||||||
|
TRI_ERRORBUF;
|
||||||
|
SERVICE_STATUS_PROCESS ssp;
|
||||||
|
DWORD bytesNeeded;
|
||||||
|
|
||||||
|
SC_HANDLE schSCManager =
|
||||||
|
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (schSCManager == 0) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// Get a handle to the service.
|
||||||
|
auto arangoService = OpenService(
|
||||||
|
schSCManager, ServiceName.c_str(),
|
||||||
|
SERVICE_START | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
|
||||||
|
|
||||||
|
if (arangoService == nullptr) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the service is not already started.
|
||||||
|
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
||||||
|
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssp.dwCurrentState == SERVICE_RUNNING) {
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StartService(arangoService, 0, nullptr)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "StartService failed " << windowsErrorBuf << std::endl;
|
||||||
|
CloseServiceHandle(arangoService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the tick count and initial checkpoint.
|
||||||
|
ssp.dwCurrentState = SERVICE_START_PENDING;
|
||||||
|
|
||||||
|
while (WaitForRunning && ssp.dwCurrentState != SERVICE_START_PENDING) {
|
||||||
|
// we sleep 1 second before we re-check the status.
|
||||||
|
Sleep(1000);
|
||||||
|
|
||||||
|
// Check the status again.
|
||||||
|
|
||||||
|
if (!QueryServiceStatusEx(
|
||||||
|
arangoService,
|
||||||
|
SC_STATUS_PROCESS_INFO, // info level
|
||||||
|
(LPBYTE)&ssp, // address of structure
|
||||||
|
sizeof(SERVICE_STATUS_PROCESS), // size of structure
|
||||||
|
&bytesNeeded)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(arangoService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::serviceControlStop(bool waitForRunning) {
|
||||||
|
TRI_ERRORBUF;
|
||||||
|
SERVICE_STATUS_PROCESS ssp;
|
||||||
|
DWORD bytesNeeded;
|
||||||
|
|
||||||
|
SC_HANDLE schSCManager =
|
||||||
|
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
||||||
|
|
||||||
|
if (schSCManager == 0) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a handle to the service.
|
||||||
|
auto arangoService = OpenService(
|
||||||
|
schSCManager, ServiceName.c_str(),
|
||||||
|
SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
|
||||||
|
|
||||||
|
if (arangoService == nullptr) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the service is not already stopped.
|
||||||
|
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
||||||
|
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
||||||
|
<< std::endl;
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssp.dwCurrentState == SERVICE_STOPPED) {
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a stop code to the service.
|
||||||
|
if (!ControlService(arangoService, SERVICE_CONTROL_STOP,
|
||||||
|
(LPSERVICE_STATUS)&ssp)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
std::cerr << "ControlService failed with " << windowsErrorBuf << std::endl;
|
||||||
|
CloseServiceHandle(arangoService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) {
|
||||||
|
// we sleep 1 second before we re-check the status.
|
||||||
|
Sleep(1000);
|
||||||
|
|
||||||
|
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO,
|
||||||
|
(LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS),
|
||||||
|
&bytesNeeded)) {
|
||||||
|
TRI_SYSTEM_ERROR();
|
||||||
|
printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf);
|
||||||
|
CloseServiceHandle(arangoService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(arangoService);
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsService::checkService(int argc, char* argv[],
|
||||||
|
std::function<int(int, char**)> runServer) {
|
||||||
|
if (argc < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmd = argv[1];
|
||||||
|
|
||||||
|
if (cmd == "--install-service") {
|
||||||
|
installService(argc, argv);
|
||||||
|
}
|
||||||
|
else if (cmd == "--start-service") {
|
||||||
|
startService(runServer);
|
||||||
|
}
|
||||||
|
else if (cmd == "--servicectl-start") {
|
||||||
|
serviceControlStart(false);
|
||||||
|
}
|
||||||
|
else if (cmd == "--servicectl-start-wait") {
|
||||||
|
serviceControlStart(true);
|
||||||
|
}
|
||||||
|
else if (cmd == "--servicectl-stop") {
|
||||||
|
serviceControlStop(false);
|
||||||
|
}
|
||||||
|
else if (cmd == "--servicectl-stop-wait") {
|
||||||
|
serviceControlStop(true);
|
||||||
|
}
|
||||||
|
else if (cmd == "--uninstall-service") {
|
||||||
|
bool force = ((argc > 2) && !strcmp(argv[2], "--force"));
|
||||||
|
uninstallService(force);
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,7 +71,6 @@ static std::string FriendlyServiceName = "ArangoDB - the multi-model database";
|
||||||
static SERVICE_STATUS_HANDLE ServiceStatus;
|
static SERVICE_STATUS_HANDLE ServiceStatus;
|
||||||
|
|
||||||
// So we have a valid minidump area during startup:
|
// So we have a valid minidump area during startup:
|
||||||
static std::string miniDumpFilename = "c:\\arangodpanic.dmp";
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief installs arangod as service with command-line
|
/// @brief installs arangod as service with command-line
|
||||||
|
@ -123,259 +122,6 @@ static void InstallServiceCommand(std::string command) {
|
||||||
CloseServiceHandle(schService);
|
CloseServiceHandle(schService);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief installs a windows service
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void InstallService(int argc, char* argv[]) {
|
|
||||||
CHAR path[MAX_PATH];
|
|
||||||
|
|
||||||
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
|
|
||||||
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// build command
|
|
||||||
std::string command;
|
|
||||||
|
|
||||||
command += "\"";
|
|
||||||
command += path;
|
|
||||||
command += "\"";
|
|
||||||
|
|
||||||
command += " --start-service";
|
|
||||||
|
|
||||||
// register service
|
|
||||||
InstallServiceCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief deletes a windows service
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void DeleteService(int argc, char* argv[], bool force) {
|
|
||||||
CHAR path[MAX_PATH] = "";
|
|
||||||
|
|
||||||
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
|
|
||||||
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "INFO: removing service '" << ServiceName << "'" << std::endl;
|
|
||||||
|
|
||||||
SC_HANDLE schSCManager =
|
|
||||||
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
||||||
|
|
||||||
if (schSCManager == 0) {
|
|
||||||
std::cerr << "FATAL: OpenSCManager failed with " << GetLastError()
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SC_HANDLE schService = OpenServiceA(
|
|
||||||
schSCManager, // SCManager database
|
|
||||||
ServiceName.c_str(), // name of service
|
|
||||||
DELETE |
|
|
||||||
SERVICE_QUERY_CONFIG); // first validate whether its us, then delete.
|
|
||||||
|
|
||||||
char serviceConfigMemory[8192]; // msdn says: 8k is enough.
|
|
||||||
DWORD bytesNeeded = 0;
|
|
||||||
if (QueryServiceConfig(schService,
|
|
||||||
(LPQUERY_SERVICE_CONFIGA)&serviceConfigMemory,
|
|
||||||
sizeof(serviceConfigMemory), &bytesNeeded)) {
|
|
||||||
QUERY_SERVICE_CONFIG* cfg = (QUERY_SERVICE_CONFIG*)&serviceConfigMemory;
|
|
||||||
|
|
||||||
std::string command = std::string("\"") + std::string(path) +
|
|
||||||
std::string("\" --start-service");
|
|
||||||
if (strcmp(cfg->lpBinaryPathName, command.c_str())) {
|
|
||||||
if (!force) {
|
|
||||||
std::cerr << "NOT removing service of other installation: "
|
|
||||||
<< cfg->lpBinaryPathName << " Our path is: " << path
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Removing service of other installation because of FORCE: "
|
|
||||||
<< cfg->lpBinaryPathName << "Our path is: " << path
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
|
|
||||||
if (schService == 0) {
|
|
||||||
std::cerr << "FATAL: OpenServiceA failed with " << GetLastError()
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DeleteService(schService)) {
|
|
||||||
std::cerr << "FATAL: DeleteService failed with " << GetLastError()
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseServiceHandle(schService);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief Start the service and optionaly wait till its up & running
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void StartArangoService(bool WaitForRunning) {
|
|
||||||
TRI_ERRORBUF;
|
|
||||||
SERVICE_STATUS_PROCESS ssp;
|
|
||||||
DWORD bytesNeeded;
|
|
||||||
|
|
||||||
SC_HANDLE schSCManager =
|
|
||||||
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
||||||
|
|
||||||
if (schSCManager == 0) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
// Get a handle to the service.
|
|
||||||
auto arangoService = OpenService(
|
|
||||||
schSCManager, ServiceName.c_str(),
|
|
||||||
SERVICE_START | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
|
|
||||||
|
|
||||||
if (arangoService == nullptr) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the service is not already started.
|
|
||||||
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
|
||||||
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssp.dwCurrentState == SERVICE_RUNNING) {
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StartService(arangoService, 0, nullptr)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "StartService failed " << windowsErrorBuf << std::endl;
|
|
||||||
CloseServiceHandle(arangoService);
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the tick count and initial checkpoint.
|
|
||||||
ssp.dwCurrentState = SERVICE_START_PENDING;
|
|
||||||
|
|
||||||
while (WaitForRunning && ssp.dwCurrentState != SERVICE_START_PENDING) {
|
|
||||||
// we sleep 1 second before we re-check the status.
|
|
||||||
Sleep(1000);
|
|
||||||
|
|
||||||
// Check the status again.
|
|
||||||
|
|
||||||
if (!QueryServiceStatusEx(
|
|
||||||
arangoService,
|
|
||||||
SC_STATUS_PROCESS_INFO, // info level
|
|
||||||
(LPBYTE)&ssp, // address of structure
|
|
||||||
sizeof(SERVICE_STATUS_PROCESS), // size of structure
|
|
||||||
&bytesNeeded)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloseServiceHandle(arangoService);
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief Stop the service and optionaly wait till its all dead
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static void StopArangoService(bool WaitForShutdown) {
|
|
||||||
TRI_ERRORBUF;
|
|
||||||
|
|
||||||
SERVICE_STATUS_PROCESS ssp;
|
|
||||||
DWORD bytesNeeded;
|
|
||||||
|
|
||||||
SC_HANDLE schSCManager =
|
|
||||||
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
||||||
|
|
||||||
if (schSCManager == 0) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a handle to the service.
|
|
||||||
auto arangoService = OpenService(
|
|
||||||
schSCManager, ServiceName.c_str(),
|
|
||||||
SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
|
|
||||||
|
|
||||||
if (arangoService == nullptr) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the service is not already stopped.
|
|
||||||
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
|
||||||
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
|
|
||||||
<< std::endl;
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssp.dwCurrentState == SERVICE_STOPPED) {
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a stop code to the service.
|
|
||||||
if (!ControlService(arangoService, SERVICE_CONTROL_STOP,
|
|
||||||
(LPSERVICE_STATUS)&ssp)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
std::cerr << "ControlService failed with " << windowsErrorBuf << std::endl;
|
|
||||||
CloseServiceHandle(arangoService);
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) {
|
|
||||||
// we sleep 1 second before we re-check the status.
|
|
||||||
Sleep(1000);
|
|
||||||
|
|
||||||
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO,
|
|
||||||
(LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS),
|
|
||||||
&bytesNeeded)) {
|
|
||||||
TRI_SYSTEM_ERROR();
|
|
||||||
printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf);
|
|
||||||
CloseServiceHandle(arangoService);
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseServiceHandle(arangoService);
|
|
||||||
CloseServiceHandle(schSCManager);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief flips the status for a service
|
/// @brief flips the status for a service
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -452,57 +198,6 @@ static void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <DbgHelp.h>
|
|
||||||
LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS* e) {
|
|
||||||
#if ARANGODB_ENABLE_BACKTRACE
|
|
||||||
|
|
||||||
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
|
|
||||||
LOG_FATAL_WINDOWS("Unhandled exception: %d",
|
|
||||||
(int)e->ExceptionRecord->ExceptionCode);
|
|
||||||
} else {
|
|
||||||
LOG_FATAL_WINDOWS("Unhandled exception without ExceptionCode!");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string bt;
|
|
||||||
TRI_GetBacktrace(bt);
|
|
||||||
std::cerr << bt << std::endl;
|
|
||||||
LOG_FATAL_WINDOWS(bt.c_str());
|
|
||||||
|
|
||||||
HANDLE hFile =
|
|
||||||
CreateFile(miniDumpFilename.c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
|
||||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
||||||
|
|
||||||
if (hFile == INVALID_HANDLE_VALUE) {
|
|
||||||
LOG_FATAL_WINDOWS("could not open minidump file : %lu", GetLastError());
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
|
||||||
exceptionInfo.ThreadId = GetCurrentThreadId();
|
|
||||||
exceptionInfo.ExceptionPointers = e;
|
|
||||||
exceptionInfo.ClientPointers = FALSE;
|
|
||||||
|
|
||||||
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
|
||||||
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory |
|
|
||||||
MiniDumpScanMemory | MiniDumpWithFullMemory),
|
|
||||||
e ? &exceptionInfo : nullptr, nullptr, nullptr);
|
|
||||||
|
|
||||||
if (hFile) {
|
|
||||||
CloseHandle(hFile);
|
|
||||||
hFile = nullptr;
|
|
||||||
}
|
|
||||||
LOG_FATAL_WINDOWS("wrote minidump: %s", miniDumpFilename.c_str());
|
|
||||||
#endif
|
|
||||||
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
|
|
||||||
LOG_FATAL_WINDOWS("Unhandled exception: %d - will crash now.",
|
|
||||||
(int)e->ExceptionRecord->ExceptionCode);
|
|
||||||
} else {
|
|
||||||
LOG_FATAL_WINDOWS(
|
|
||||||
"Unhandled exception without ExceptionCode - will crash now.!");
|
|
||||||
}
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief starts server as service
|
/// @brief starts server as service
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -511,73 +206,9 @@ class WindowsArangoServer : public ArangoServer {
|
||||||
private:
|
private:
|
||||||
DWORD _progress;
|
DWORD _progress;
|
||||||
|
|
||||||
#if 0
|
|
||||||
// TODO doesn't work that way.
|
|
||||||
protected:
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
|
|
||||||
/// really up and running.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
virtual void startupProgress() override final {
|
|
||||||
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
|
|
||||||
/// really up and running.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
virtual void startupFinished() override final {
|
|
||||||
// startup finished - signalize we're running.
|
|
||||||
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief wrap ArangoDB server so we can properly emmit a status on shutdown
|
|
||||||
/// starting
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
virtual void shutDownBegins() override final {
|
|
||||||
// startup finished - signalize we're running.
|
|
||||||
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
public:
|
|
||||||
WindowsArangoServer(int argc, char** argv) : ArangoServer(argc, argv) {
|
|
||||||
_progress = 2;
|
|
||||||
miniDumpFilename = TRI_GetTempPath();
|
|
||||||
|
|
||||||
miniDumpFilename +=
|
|
||||||
"\\minidump_" + std::to_string(GetCurrentProcessId()) + ".dmp";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ARGC;
|
static int ARGC;
|
||||||
static char** ARGV;
|
static char** ARGV;
|
||||||
|
|
||||||
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR* lpszArgv) {
|
|
||||||
if (!TRI_InitWindowsEventLog()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// register the service ctrl handler, lpszArgv[0] contains service name
|
|
||||||
ServiceStatus =
|
|
||||||
RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl);
|
|
||||||
|
|
||||||
// set start pending
|
|
||||||
SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000);
|
|
||||||
|
|
||||||
IsRunning = true;
|
|
||||||
ArangoInstance = new WindowsArangoServer(ARGC, ARGV);
|
|
||||||
ArangoInstance->setMode(ArangoServer::ServerMode::MODE_SERVICE);
|
|
||||||
|
|
||||||
ArangoInstance->start();
|
|
||||||
IsRunning = false;
|
|
||||||
|
|
||||||
// service has stopped
|
|
||||||
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
|
|
||||||
TRI_CloseWindowsEventlog();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief parse windows specific commandline options
|
/// @brief parse windows specific commandline options
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -627,26 +258,6 @@ bool TRI_ParseMoreArgs(int argc, char* argv[]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief start the windows service
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void TRI_StartService(int argc, char* argv[]) {
|
|
||||||
// create and start an ArangoDB server
|
|
||||||
|
|
||||||
SERVICE_TABLE_ENTRY ste[] = {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)ServiceMain},
|
|
||||||
{nullptr, nullptr}};
|
|
||||||
|
|
||||||
ARGC = argc;
|
|
||||||
ARGV = argv;
|
|
||||||
|
|
||||||
if (!StartServiceCtrlDispatcher(ste)) {
|
|
||||||
std::cerr << "FATAL: StartServiceCtrlDispatcher has failed with "
|
|
||||||
<< GetLastError() << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -68,26 +68,13 @@
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::wal;
|
using namespace arangodb::wal;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief Hooks for OS-Specific functions
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// YYY #warning TODO
|
|
||||||
#if 0
|
#if 0
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
extern bool TRI_ParseMoreArgs(int argc, char* argv[]);
|
WindowsService WINDOWS_SERVICE;
|
||||||
extern void TRI_StartService(int argc, char* argv[]);
|
|
||||||
#else
|
|
||||||
bool TRI_ParseMoreArgs(int argc, char* argv[]) { return false; }
|
|
||||||
void TRI_StartService(int argc, char* argv[]) {}
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
static int runServer(int argc, char** argv) {
|
||||||
/// @brief creates an application server
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
ArangoGlobalContext context(argc, argv);
|
ArangoGlobalContext context(argc, argv);
|
||||||
context.installSegv();
|
context.installSegv();
|
||||||
context.maskAllSignals();
|
context.maskAllSignals();
|
||||||
|
@ -100,6 +87,45 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
application_features::ApplicationServer server(options);
|
application_features::ApplicationServer server(options);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef _WIN32
|
||||||
|
application_features::ProgressHandler reporter{
|
||||||
|
[](application_features::ServerState state) {
|
||||||
|
switch (_state) {
|
||||||
|
case ServerState::IN_WAIT:
|
||||||
|
WINDOWS_SERVICE.startupFinished();
|
||||||
|
break;
|
||||||
|
case ServerState::IN_STOP:
|
||||||
|
server.shutdownBegins();
|
||||||
|
break;
|
||||||
|
case ServerState::IN_COLLECT_OPTIONS:
|
||||||
|
case ServerState::IN_VALIDATE_OPTIONS:
|
||||||
|
case ServerState::IN_PREPARE:
|
||||||
|
case ServerState::IN_START:
|
||||||
|
WINDOWS_SERVICE.startupProgress();
|
||||||
|
break;
|
||||||
|
case ServerState::UNINITIALIZED:
|
||||||
|
case ServerState::STOPPED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](application_features::ServerState state, std::string const& name) {
|
||||||
|
switch (_state) {
|
||||||
|
case ServerState::IN_COLLECT_OPTIONS:
|
||||||
|
case ServerState::IN_VALIDATE_OPTIONS:
|
||||||
|
case ServerState::IN_PREPARE:
|
||||||
|
case ServerState::IN_START:
|
||||||
|
WINDOWS_SERVICE.startupProgress();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
server.addReporter(reporter);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<std::string> nonServerFeatures = {
|
std::vector<std::string> nonServerFeatures = {
|
||||||
"Action", "Affinity", "Agency",
|
"Action", "Affinity", "Agency",
|
||||||
"Cluster", "Daemon", "Dispatcher",
|
"Cluster", "Daemon", "Dispatcher",
|
||||||
|
@ -175,35 +201,12 @@ int main(int argc, char* argv[]) {
|
||||||
return context.exit(ret);
|
return context.exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// YYY #warning TODO
|
int main(int argc, char* argv[]) {
|
||||||
#if 0
|
#if 0
|
||||||
|
#ifdef _WIN32
|
||||||
// windows only
|
WINDOWS_SERVICE.serviceStart(argc, argv, runServer);
|
||||||
bool const startAsService = TRI_ParseMoreArgs(argc, argv);
|
|
||||||
|
|
||||||
// initialize sub-systems
|
|
||||||
if (startAsService) {
|
|
||||||
TRI_StartService(argc, argv);
|
|
||||||
} else {
|
|
||||||
ArangoInstance = new ArangoServer(argc, argv);
|
|
||||||
res = ArangoInstance->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ArangoInstance != nullptr) {
|
|
||||||
try {
|
|
||||||
delete ArangoInstance;
|
|
||||||
} catch (...) {
|
|
||||||
// caught an error during shutdown
|
|
||||||
res = EXIT_FAILURE;
|
|
||||||
|
|
||||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
|
||||||
std::cerr << "Caught an exception during shutdown" << std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
ArangoInstance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// shutdown sub-systems
|
|
||||||
return context.exit(ret);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return runServer(argc, argv);
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
|
|
||||||
|
// constants
|
||||||
|
std::string const StaticStrings::N1800("1800");
|
||||||
|
|
||||||
// system attribute names
|
// system attribute names
|
||||||
std::string const StaticStrings::IdString("_id");
|
std::string const StaticStrings::IdString("_id");
|
||||||
std::string const StaticStrings::KeyString("_key");
|
std::string const StaticStrings::KeyString("_key");
|
||||||
|
@ -32,8 +35,21 @@ std::string const StaticStrings::FromString("_from");
|
||||||
std::string const StaticStrings::ToString("_to");
|
std::string const StaticStrings::ToString("_to");
|
||||||
|
|
||||||
// HTTP headers
|
// HTTP headers
|
||||||
std::string const StaticStrings::AcceptHeader("accept");
|
std::string const StaticStrings::Accept("accept");
|
||||||
|
std::string const StaticStrings::AccessControlAllowCredentials("access-control-allow-credentials");
|
||||||
|
std::string const StaticStrings::AccessControlAllowHeaders("access-control-allow-headers");
|
||||||
|
std::string const StaticStrings::AccessControlAllowMethods("access-control-allow-methods");
|
||||||
|
std::string const StaticStrings::AccessControlAllowOrigin("access-control-allow-origin");
|
||||||
|
std::string const StaticStrings::AccessControlExposeHeaders("access-control-expose-headers");
|
||||||
|
std::string const StaticStrings::AccessControlMaxAge("access-control-max-age");
|
||||||
|
std::string const StaticStrings::AccessControlRequestHeaders("access-control-request-headers");
|
||||||
|
std::string const StaticStrings::Allow("allow");
|
||||||
|
std::string const StaticStrings::Close("Close");
|
||||||
|
std::string const StaticStrings::Connection("connection");
|
||||||
std::string const StaticStrings::ContentTypeHeader("content-type");
|
std::string const StaticStrings::ContentTypeHeader("content-type");
|
||||||
|
std::string const StaticStrings::KeepAlive("Close");
|
||||||
|
std::string const StaticStrings::Location("location");
|
||||||
|
std::string const StaticStrings::WwwAuthenticate("www-authenticate");
|
||||||
|
|
||||||
// mime types
|
// mime types
|
||||||
std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8");
|
std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8");
|
||||||
|
|
|
@ -28,7 +28,11 @@
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
class StaticStrings {
|
class StaticStrings {
|
||||||
StaticStrings() = delete;
|
StaticStrings() = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// constants
|
||||||
|
static std::string const N1800;
|
||||||
|
|
||||||
// system attribute names
|
// system attribute names
|
||||||
static std::string const IdString;
|
static std::string const IdString;
|
||||||
static std::string const KeyString;
|
static std::string const KeyString;
|
||||||
|
@ -37,8 +41,21 @@ class StaticStrings {
|
||||||
static std::string const ToString;
|
static std::string const ToString;
|
||||||
|
|
||||||
// HTTP headers
|
// HTTP headers
|
||||||
static std::string const AcceptHeader;
|
static std::string const Accept;
|
||||||
|
static std::string const AccessControlAllowCredentials;
|
||||||
|
static std::string const AccessControlAllowHeaders;
|
||||||
|
static std::string const AccessControlAllowMethods;
|
||||||
|
static std::string const AccessControlAllowOrigin;
|
||||||
|
static std::string const AccessControlExposeHeaders;
|
||||||
|
static std::string const AccessControlMaxAge;
|
||||||
|
static std::string const AccessControlRequestHeaders;
|
||||||
|
static std::string const Allow;
|
||||||
|
static std::string const Close;
|
||||||
|
static std::string const Connection;
|
||||||
static std::string const ContentTypeHeader;
|
static std::string const ContentTypeHeader;
|
||||||
|
static std::string const KeepAlive;
|
||||||
|
static std::string const Location;
|
||||||
|
static std::string const WwwAuthenticate;
|
||||||
|
|
||||||
// mime types
|
// mime types
|
||||||
static std::string const MimeTypeVPack;
|
static std::string const MimeTypeVPack;
|
||||||
|
|
|
@ -127,7 +127,7 @@ function main(argv) {
|
||||||
serverArgs["javascript.app-path"] = fs.join(tmpDataDir, "apps");
|
serverArgs["javascript.app-path"] = fs.join(tmpDataDir, "apps");
|
||||||
serverArgs["javascript.startup-directory"] = "js";
|
serverArgs["javascript.startup-directory"] = "js";
|
||||||
serverArgs["log.file"] = fs.join(tmpDataDir, "log");
|
serverArgs["log.file"] = fs.join(tmpDataDir, "log");
|
||||||
serverArgs["server.disable-authentication"] = "true";
|
serverArgs["server.authentication"] = "false";
|
||||||
serverArgs["server.endpoint"] = serverEndpoint;
|
serverArgs["server.endpoint"] = serverEndpoint;
|
||||||
serverArgs["server.threads"] = "3";
|
serverArgs["server.threads"] = "3";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue