diff --git a/Installation/release.sh b/Installation/release.sh index 0d0faf860a..03c2ddd764 100755 --- a/Installation/release.sh +++ b/Installation/release.sh @@ -3,7 +3,7 @@ set -e TAG=1 -if [ "$1" == "--no-tag" ]; then +if [ "$1" == "--no-commit" ]; then TAG=0 shift fi @@ -32,9 +32,9 @@ VERSION_MINOR=`echo $VERSION | awk -F. '{print $2}'` VERSION_REVISION=`echo $VERSION | awk -F. '{print $3}'` cat CMakeLists.txt \ - | 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_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")" \ + | 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_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")~" \ > CMakeLists.txt.tmp mv CMakeLists.txt.tmp CMakeLists.txt @@ -42,18 +42,22 @@ mv CMakeLists.txt.tmp CMakeLists.txt CMAKE_CONFIGURE="-DUSE_MAINTAINER_MODE=ON" 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 +if test 0 = 1; then +echo "COMPILING" rm -rf build && mkdir build -./scripts/jsint.sh - ( cd build cmake .. ${CMAKE_CONFIGURE} make -j 8 ) +fi + +echo "LINTING" +./utils/jslint.sh git add -f \ README \ @@ -67,13 +71,13 @@ git add -f \ js/common/bootstrap/errors.js \ CMakeLists.txt -( - cd build - make swagger -) +echo "SWAGGER" +./utils/generateSwagger.sh -./scripts/generateExamples +echo "EXAMPLES" +./utils/generateExamples.sh +echo "GRUNT" ( cd js/apps/system/_admin/aardvark/APP npm install --only=dev @@ -82,6 +86,7 @@ git add -f \ git add -f Documentation/Examples/*.generated +echo "DOCUMENTATION" cd Documentation/Books; make case "$TAG" in @@ -94,6 +99,8 @@ case "$TAG" in esac if [ "$TAG" == "1" ]; then + echo "COMMIT" + git commit -m "release version $VERSION" -a git push diff --git a/arangod/Agency/RestAgencyHandler.cpp b/arangod/Agency/RestAgencyHandler.cpp index 8f0e1b4505..8695a41250 100644 --- a/arangod/Agency/RestAgencyHandler.cpp +++ b/arangod/Agency/RestAgencyHandler.cpp @@ -21,16 +21,16 @@ /// @author Kaveh Vahedipour //////////////////////////////////////////////////////////////////////////////// -#include "Rest/HttpRequest.h" -#include "Rest/Version.h" #include "RestAgencyHandler.h" -#include "Agency/Agent.h" - #include #include +#include "Agency/Agent.h" +#include "Basics/StaticStrings.h" #include "Logger/Logger.h" +#include "Rest/HttpRequest.h" +#include "Rest/Version.h" using namespace arangodb; @@ -74,8 +74,7 @@ void RestAgencyHandler::redirectRequest(arangodb::consensus::id_t leaderId) { std::string url = Endpoint::uriForm( _agent->config().endpoints.at(leaderId)) + _request->requestPath(); createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT); - static std::string const location = "location"; - _response->setHeaderNC(location, url); + _response->setHeaderNC(StaticStrings::Location, url); } catch (std::exception const& e) { LOG_TOPIC(WARN, Logger::AGENCY) << e.what(); generateError(GeneralResponse::ResponseCode::SERVER_ERROR, diff --git a/arangod/HttpServer/HttpCommTask.cpp b/arangod/HttpServer/HttpCommTask.cpp index 14da224d74..01e642ac2a 100644 --- a/arangod/HttpServer/HttpCommTask.cpp +++ b/arangod/HttpServer/HttpCommTask.cpp @@ -84,7 +84,7 @@ HttpCommTask::HttpCommTask(HttpServer* server, TRI_socket_t socket, << _connectionInfo.clientPort; // 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(); ConnectionStatisticsAgent::release(); @@ -350,8 +350,10 @@ bool HttpCommTask::processRead() { TRI_invalidatesocket(&_commSocket); // might delete this - // note that as we closed the socket above, the response will not make it to - // the client! will result in a "Empty reply from server" error in curl etc. + // note that as we closed the socket above, the response will not make + // it to + // the client! will result in a "Empty reply from server" error in + // curl etc. handleResponse(&response); return false; @@ -536,14 +538,12 @@ bool HttpCommTask::processRead() { else { HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED, compatibility); - static std::string const wwwAuthenticate = "www-authenticate"; - if (sendWwwAuthenticateHeader()) { static std::string const realm = "basic realm=\"" + _server->handlerFactory()->authenticationRealm(_request) + "\""; - response.setHeaderNC(wwwAuthenticate, realm); + response.setHeaderNC(StaticStrings::WwwAuthenticate, realm); } clearRequest(); @@ -608,32 +608,27 @@ void HttpCommTask::addResponse(HttpResponse* response) { // access-control-allow-origin header now LOG(TRACE) << "handling CORS response"; - static std::string const accessControl = "access-control-expose-headers"; static std::string const exposedHeaders = "etag, content-encoding, content-length, location, " "server, x-arango-errors, x-arango-async-id"; - response->setHeaderNC(accessControl, exposedHeaders); + response->setHeaderNC(StaticStrings::AccessControlExposeHeaders, + exposedHeaders); // send back original value of "Origin" header - static std::string const accessOrigin = "access-control-allow-origin"; - - response->setHeaderNC(accessOrigin, _origin); + response->setHeaderNC(StaticStrings::AccessControlAllowOrigin, _origin); // send back "Access-Control-Allow-Credentials" header - static std::string const accessCredentials = - "access-control-allow-credentials"; - - response->setHeaderNC(accessCredentials, + response->setHeaderNC(StaticStrings::AccessControlAllowCredentials, (_denyCredentials ? "false" : "true")); } // CORS request handling EOF // set "connection" header // keep-alive is the default - static std::string const connection = "connection"; - - response->setHeaderNC(connection, (_closeRequested ? "Close" : "Keep-Alive")); + response->setHeaderNC( + StaticStrings::Connection, + (_closeRequested ? StaticStrings::Close : StaticStrings::KeepAlive)); size_t const responseBodyLength = response->bodySize(); @@ -780,40 +775,37 @@ void HttpCommTask::fillWriteBuffer() { //////////////////////////////////////////////////////////////////////////////// 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); - static std::string const allow = "allow"; - response.setHeaderNC(allow, allowedMethods); + response.setHeaderNC(StaticStrings::Allow, allowedMethods); if (!_origin.empty()) { LOG(TRACE) << "got CORS preflight request"; - std::string const allowHeaders = - StringUtils::trim(_request->header("access-control-request-headers")); + std::string const allowHeaders = StringUtils::trim( + _request->header(StaticStrings::AccessControlRequestHeaders)); // send back which HTTP methods are allowed for the resource // we'll allow all - static std::string const accessControl = "access-control-allow-methods"; - response.setHeaderNC(accessControl, allowedMethods); + response.setHeaderNC(StaticStrings::AccessControlAllowMethods, + allowedMethods); if (!allowHeaders.empty()) { // allow all extra headers the client requested // 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 // server. that's a client problem. - static std::string const accessControl = "access-control-allow-headers"; - response.setHeaderNC(accessControl, allowHeaders); + response.setHeaderNC(StaticStrings::AccessControlAllowHeaders, + allowHeaders); LOG(TRACE) << "client requested validation of the following headers: " << allowHeaders; } // set caching time (hard-coded value) - static std::string const accessAge = "access-control-max-age"; - static std::string const maxAge = "1800"; - - response.setHeaderNC(accessAge, maxAge); + response.setHeaderNC(StaticStrings::AccessControlMaxAge, StaticStrings::N1800); } clearRequest(); diff --git a/arangod/RestHandler/RestBaseHandler.cpp b/arangod/RestHandler/RestBaseHandler.cpp index 6454f105c6..936d1a65a0 100644 --- a/arangod/RestHandler/RestBaseHandler.cpp +++ b/arangod/RestHandler/RestBaseHandler.cpp @@ -22,6 +22,7 @@ //////////////////////////////////////////////////////////////////////////////// #include "RestBaseHandler.h" + #include "Basics/StaticStrings.h" #include "Basics/StringUtils.h" #include "Basics/VPackStringBufferAdapter.h" @@ -149,7 +150,7 @@ void RestBaseHandler::dumpResponse(VPackSlice const& slice, ////////////////////////////////////////////////////////////////////////////// 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)); } diff --git a/arangod/RestHandler/RestVersionHandler.cpp b/arangod/RestHandler/RestVersionHandler.cpp index 7170b15c46..b3d8b77581 100644 --- a/arangod/RestHandler/RestVersionHandler.cpp +++ b/arangod/RestHandler/RestVersionHandler.cpp @@ -59,10 +59,11 @@ HttpHandler::status_t RestVersionHandler::execute() { Version::getVPack(result); if (application_features::ApplicationServer::server != nullptr) { - auto server = application_features::ApplicationServer::server->getFeature("Server"); + auto server = application_features::ApplicationServer::server + ->getFeature("Server"); result.add("mode", VPackValue(server->operationModeString())); } - + result.close(); } result.close(); diff --git a/arangod/RestServer/WindowsService.cpp b/arangod/RestServer/WindowsService.cpp new file mode 100644 index 0000000000..b89ecbc128 --- /dev/null +++ b/arangod/RestServer/WindowsService.cpp @@ -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 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); + } +} diff --git a/arangod/RestServer/WindowsServiceUtils.cpp b/arangod/RestServer/WindowsServiceUtils.cpp index b29fd4193a..63c6ac6322 100644 --- a/arangod/RestServer/WindowsServiceUtils.cpp +++ b/arangod/RestServer/WindowsServiceUtils.cpp @@ -71,7 +71,6 @@ static std::string FriendlyServiceName = "ArangoDB - the multi-model database"; static SERVICE_STATUS_HANDLE ServiceStatus; // So we have a valid minidump area during startup: -static std::string miniDumpFilename = "c:\\arangodpanic.dmp"; //////////////////////////////////////////////////////////////////////////////// /// @brief installs arangod as service with command-line @@ -123,259 +122,6 @@ static void InstallServiceCommand(std::string command) { 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 //////////////////////////////////////////////////////////////////////////////// @@ -452,57 +198,6 @@ static void WINAPI ServiceCtrl(DWORD dwCtrlCode) { } } -#include -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 //////////////////////////////////////////////////////////////////////////////// @@ -511,73 +206,9 @@ class WindowsArangoServer : public ArangoServer { private: 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 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 //////////////////////////////////////////////////////////////////////////////// @@ -627,26 +258,6 @@ bool TRI_ParseMoreArgs(int argc, char* argv[]) { 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 diff --git a/arangod/RestServer/arangod.cpp b/arangod/RestServer/arangod.cpp index 9fcd3bc34e..20ad8315db 100644 --- a/arangod/RestServer/arangod.cpp +++ b/arangod/RestServer/arangod.cpp @@ -68,26 +68,13 @@ using namespace arangodb; using namespace arangodb::wal; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Hooks for OS-Specific functions -//////////////////////////////////////////////////////////////////////////////// - -// YYY #warning TODO #if 0 #ifdef _WIN32 -extern bool TRI_ParseMoreArgs(int argc, char* argv[]); -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[]) {} +WindowsService WINDOWS_SERVICE; #endif #endif -//////////////////////////////////////////////////////////////////////////////// -/// @brief creates an application server -//////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char* argv[]) { +static int runServer(int argc, char** argv) { ArangoGlobalContext context(argc, argv); context.installSegv(); context.maskAllSignals(); @@ -100,6 +87,45 @@ int main(int argc, char* argv[]) { 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 nonServerFeatures = { "Action", "Affinity", "Agency", "Cluster", "Daemon", "Dispatcher", @@ -175,35 +201,12 @@ int main(int argc, char* argv[]) { return context.exit(ret); } -// YYY #warning TODO +int main(int argc, char* argv[]) { #if 0 - - // windows only - 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; +#ifdef _WIN32 + WINDOWS_SERVICE.serviceStart(argc, argv, runServer); #endif - } - - ArangoInstance = nullptr; - } - - // shutdown sub-systems - return context.exit(ret); #endif + + return runServer(argc, argv); +} diff --git a/lib/Basics/StaticStrings.cpp b/lib/Basics/StaticStrings.cpp index 053a0dcad8..78ffcc69b7 100644 --- a/lib/Basics/StaticStrings.cpp +++ b/lib/Basics/StaticStrings.cpp @@ -24,6 +24,9 @@ using namespace arangodb; +// constants +std::string const StaticStrings::N1800("1800"); + // system attribute names std::string const StaticStrings::IdString("_id"); std::string const StaticStrings::KeyString("_key"); @@ -32,8 +35,21 @@ std::string const StaticStrings::FromString("_from"); std::string const StaticStrings::ToString("_to"); // 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::KeepAlive("Close"); +std::string const StaticStrings::Location("location"); +std::string const StaticStrings::WwwAuthenticate("www-authenticate"); // mime types std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8"); diff --git a/lib/Basics/StaticStrings.h b/lib/Basics/StaticStrings.h index 1bb776ff00..66a21718e6 100644 --- a/lib/Basics/StaticStrings.h +++ b/lib/Basics/StaticStrings.h @@ -28,7 +28,11 @@ namespace arangodb { class StaticStrings { StaticStrings() = delete; + public: + // constants + static std::string const N1800; + // system attribute names static std::string const IdString; static std::string const KeyString; @@ -37,8 +41,21 @@ class StaticStrings { static std::string const ToString; // 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 KeepAlive; + static std::string const Location; + static std::string const WwwAuthenticate; // mime types static std::string const MimeTypeVPack; diff --git a/utils/generateExamples.js b/utils/generateExamples.js index 51355e4ddf..92111f738b 100644 --- a/utils/generateExamples.js +++ b/utils/generateExamples.js @@ -127,7 +127,7 @@ function main(argv) { serverArgs["javascript.app-path"] = fs.join(tmpDataDir, "apps"); serverArgs["javascript.startup-directory"] = "js"; serverArgs["log.file"] = fs.join(tmpDataDir, "log"); - serverArgs["server.disable-authentication"] = "true"; + serverArgs["server.authentication"] = "false"; serverArgs["server.endpoint"] = serverEndpoint; serverArgs["server.threads"] = "3";