1
0
Fork 0

runtime addition and removal of endpoints

This commit is contained in:
Jan Steemann 2013-09-12 18:07:39 +02:00
parent 6bbfb65f7c
commit 6ff314de0e
28 changed files with 823 additions and 491 deletions

View File

@ -231,49 +231,6 @@ BOOST_AUTO_TEST_CASE (EndpointDomainTypes) {
CHECK_ENDPOINT_FEATURE(client, "http@unix:///tmp/socket", DomainType, Endpoint::DOMAIN_UNIX);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test protocols
////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE (EndpointProtocols) {
Endpoint* e;
CHECK_ENDPOINT_FEATURE(client, "tcp://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://localhost", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://www.arangodb.org", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://127.0.0.1:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://localhost:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://www.arangodb.org:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://[127.0.0.1]", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://[::]", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://[127.0.0.1]:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "tcp://[::]:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://localhost", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://www.arangodb.org", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://127.0.0.1:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://localhost:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://www.arangodb.org:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://[127.0.0.1]", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://[::]", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://[127.0.0.1]:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "ssl://[::]:8529", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "unix:///tmp/socket", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "unix:///tmp/socket/arango.sock", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "http@tcp://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "http@ssl://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "http@unix:///tmp/socket", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "Http@tcp://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "Http@ssl://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "Http@unix:///tmp/socket", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "HTTP@tcp://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "HTTP@ssl://127.0.0.1", Protocol, Endpoint::PROTOCOL_HTTP);
CHECK_ENDPOINT_FEATURE(client, "HTTP@unix:///tmp/socket", Protocol, Endpoint::PROTOCOL_HTTP);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test ports
////////////////////////////////////////////////////////////////////////////////
@ -579,7 +536,6 @@ BOOST_AUTO_TEST_CASE (EndpointServerTcpIpv4WithPort) {
BOOST_CHECK_EQUAL("tcp://127.0.0.1:667", e->getSpecification());
BOOST_CHECK_EQUAL(Endpoint::ENDPOINT_SERVER, e->getType());
BOOST_CHECK_EQUAL(Endpoint::DOMAIN_IPV4, e->getDomainType());
BOOST_CHECK_EQUAL(Endpoint::PROTOCOL_HTTP, e->getProtocol());
BOOST_CHECK_EQUAL(Endpoint::ENCRYPTION_NONE, e->getEncryption());
BOOST_CHECK_EQUAL(AF_INET, e->getDomain());
BOOST_CHECK_EQUAL("127.0.0.1", e->getHost());
@ -600,7 +556,6 @@ BOOST_AUTO_TEST_CASE (EndpointServerUnix) {
BOOST_CHECK_EQUAL("unix:///path/to/arango.sock", e->getSpecification());
BOOST_CHECK_EQUAL(Endpoint::ENDPOINT_SERVER, e->getType());
BOOST_CHECK_EQUAL(Endpoint::DOMAIN_UNIX, e->getDomainType());
BOOST_CHECK_EQUAL(Endpoint::PROTOCOL_HTTP, e->getProtocol());
BOOST_CHECK_EQUAL(Endpoint::ENCRYPTION_NONE, e->getEncryption());
BOOST_CHECK_EQUAL(AF_UNIX, e->getDomain());
BOOST_CHECK_EQUAL("localhost", e->getHost());
@ -621,7 +576,6 @@ BOOST_AUTO_TEST_CASE (EndpointClientSslIpV6WithPortHttp) {
BOOST_CHECK_EQUAL("http@SSL://[0001:0002:0003:0004:0005:0006:0007:0008]:43425", e->getSpecification());
BOOST_CHECK_EQUAL(Endpoint::ENDPOINT_CLIENT, e->getType());
BOOST_CHECK_EQUAL(Endpoint::DOMAIN_IPV6, e->getDomainType());
BOOST_CHECK_EQUAL(Endpoint::PROTOCOL_HTTP, e->getProtocol());
BOOST_CHECK_EQUAL(Endpoint::ENCRYPTION_SSL, e->getEncryption());
BOOST_CHECK_EQUAL(AF_INET6, e->getDomain());
BOOST_CHECK_EQUAL("0001:0002:0003:0004:0005:0006:0007:0008", e->getHost());
@ -642,7 +596,6 @@ BOOST_AUTO_TEST_CASE (EndpointClientTcpIpv6WithoutPort) {
BOOST_CHECK_EQUAL("tcp://[::]", e->getSpecification());
BOOST_CHECK_EQUAL(Endpoint::ENDPOINT_CLIENT, e->getType());
BOOST_CHECK_EQUAL(Endpoint::DOMAIN_IPV6, e->getDomainType());
BOOST_CHECK_EQUAL(Endpoint::PROTOCOL_HTTP, e->getProtocol());
BOOST_CHECK_EQUAL(Endpoint::ENCRYPTION_NONE, e->getEncryption());
BOOST_CHECK_EQUAL(AF_INET6, e->getDomain());
BOOST_CHECK_EQUAL("::", e->getHost());

View File

@ -560,6 +560,9 @@ void ArangoServer::buildApplicationServer () {
LOGGER_FATAL_AND_EXIT("no database path has been supplied, giving up");
}
// strip trailing separators
_databasePath = StringUtils::rTrim(_databasePath, TRI_DIR_SEPARATOR_STR);
// .............................................................................
// now run arangod
// .............................................................................
@ -1191,6 +1194,7 @@ void ArangoServer::openDatabases () {
assert(_server != 0);
int res = TRI_InitServer(_server,
_applicationEndpointServer,
_databasePath.c_str(),
&defaults,
_disableReplicationLogger,

View File

@ -539,8 +539,8 @@ void ApplicationV8::setupOptions (map<string, basics::ProgramOptionsDescription>
("javascript.gc-interval", &_gcInterval, "JavaScript request-based garbage collection interval (each x requests)")
("javascript.gc-frequency", &_gcFrequency, "JavaScript time-based garbage collection frequency (each x seconds)")
("javascript.action-directory", &_actionPath, "path to the JavaScript action directory")
("javascript.app-path", &_appPath, "one directory for applications")
("javascript.dev-app-path", &_devAppPath, "one directory for dev applications")
("javascript.app-path", &_appPath, "directory for Foxx applications (normal mode)")
("javascript.dev-app-path", &_devAppPath, "directory for Foxx applications (development mode)")
("javascript.modules-path", &_modulesPath, "one or more directories separated by semi-colons")
("javascript.package-path", &_packagePath, "one or more directories separated by semi-colons")
("javascript.startup-directory", &_startupPath, "path to the directory containing alternate JavaScript startup scripts")

View File

@ -45,6 +45,7 @@
#include "BasicsC/tri-strings.h"
#include "CapConstraint/cap-constraint.h"
#include "FulltextIndex/fulltext-index.h"
#include "HttpServer/ApplicationEndpointServer.h"
#include "Replication/InitialSyncer.h"
#include "Rest/SslInterface.h"
#include "ShapedJson/shape-accessor.h"
@ -7920,7 +7921,16 @@ static v8::Handle<v8::Value> JS_ConfigureEndpoint (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() < 1 || argv.Length() > 2) {
TRI_V8_EXCEPTION_USAGE(scope, "CONFIGURE_ENDPOINT(<endpoint>, <names>)");
TRI_V8_EXCEPTION_USAGE(scope, "configureEndpoint(<endpoint>, <databases>)");
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
TRI_server_t* server = (TRI_server_t*) v8g->_server;
ApplicationEndpointServer* s = static_cast<ApplicationEndpointServer*>(server->_applicationEndpointServer);
if (s == 0) {
// not implemented in console mode
TRI_V8_EXCEPTION(scope, TRI_ERROR_NOT_IMPLEMENTED);
}
TRI_vocbase_t* vocbase = GetContextVocBase();
@ -7933,16 +7943,14 @@ static v8::Handle<v8::Value> JS_ConfigureEndpoint (v8::Arguments const& argv) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE);
}
// TODO: check endpoint string
const string endpoint = TRI_ObjectToString(argv[0]);
// validate and register dbNames
TRI_vector_string_t dbNames;
TRI_InitVectorString(&dbNames, TRI_CORE_MEM_ZONE);
// register dbNames
vector<string> dbNames;
if (argv.Length() > 1) {
if (! argv[1]->IsArray()) {
TRI_V8_EXCEPTION_PARAMETER(scope, "<names> must be a list");
TRI_V8_EXCEPTION_PARAMETER(scope, "<databases> must be a list");
}
v8::Handle<v8::Array> list = v8::Handle<v8::Array>::Cast(argv[1]);
@ -7952,23 +7960,119 @@ static v8::Handle<v8::Value> JS_ConfigureEndpoint (v8::Arguments const& argv) {
v8::Handle<v8::Value> name = list->Get(i);
if (name->IsString()) {
const string dbName = TRI_ObjectToString(name);
TRI_PushBackVectorString(&dbNames, TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, dbName.c_str()));
dbNames.push_back(TRI_ObjectToString(name));
}
else {
TRI_V8_EXCEPTION_PARAMETER(scope, "<names> must be a list of strings");
TRI_V8_EXCEPTION_PARAMETER(scope, "<databases> must be a list of strings");
}
}
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
TRI_StoreEndpointServer((TRI_server_t*) v8g->_server, endpoint.c_str(), &dbNames);
TRI_DestroyVectorString(&dbNames);
bool result = s->addEndpoint(endpoint, dbNames);
if (! result) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_BAD_PARAMETER, "unable to bind to endpoint");
}
return scope.Close(v8::True());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes a new endpoint
///
/// @FUN{REMOVE_ENDPOINT}
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_RemoveEndpoint (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() < 1 || argv.Length() > 2) {
TRI_V8_EXCEPTION_USAGE(scope, "removeEndpoint(<endpoint>)");
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
TRI_server_t* server = (TRI_server_t*) v8g->_server;
ApplicationEndpointServer* s = static_cast<ApplicationEndpointServer*>(server->_applicationEndpointServer);
if (s == 0) {
// not implemented in console mode
TRI_V8_EXCEPTION(scope, TRI_ERROR_NOT_IMPLEMENTED);
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (! TRI_IsSystemVocBase(vocbase)) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE);
}
bool result = s->removeEndpoint(TRI_ObjectToString(argv[0]));
if (! result) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_BAD_PARAMETER, "endpoint is not registered");
}
return scope.Close(v8::True());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a list of all endpoints
///
/// @FUN{LIST_ENDPOINTS}
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_ListEndpoints (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
TRI_V8_EXCEPTION_USAGE(scope, "listEndpoints()");
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
TRI_server_t* server = (TRI_server_t*) v8g->_server;
ApplicationEndpointServer* s = static_cast<ApplicationEndpointServer*>(server->_applicationEndpointServer);
if (s == 0) {
// not implemented in console mode
TRI_V8_EXCEPTION(scope, TRI_ERROR_NOT_IMPLEMENTED);
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (! TRI_IsSystemVocBase(vocbase)) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE);
}
const map<string, vector<string> >& endpoints = s->getEndpoints();
v8::Handle<v8::Array> result = v8::Array::New();
uint32_t j = 0;
map<string, vector<string> >::const_iterator it;
for (it = endpoints.begin(); it != endpoints.end(); ++it) {
v8::Handle<v8::Array> dbNames = v8::Array::New();
for (uint32_t i = 0; i < (*it).second.size(); ++i) {
dbNames->Set(i, v8::String::New((*it).second.at(i).c_str()));
}
v8::Handle<v8::Object> item = v8::Object::New();
item->Set(v8::String::New("endpoint"), v8::String::New((*it).first.c_str()));
item->Set(v8::String::New("databases"), dbNames);
result->Set(j++, item);
}
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -8786,6 +8890,8 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
TRI_AddGlobalFunctionVocbase(context, "PARSE_DATETIME", JS_parseDatetime);
TRI_AddGlobalFunctionVocbase(context, "CONFIGURE_ENDPOINT", JS_ConfigureEndpoint, true);
TRI_AddGlobalFunctionVocbase(context, "REMOVE_ENDPOINT", JS_RemoveEndpoint, true);
TRI_AddGlobalFunctionVocbase(context, "LIST_ENDPOINTS", JS_ListEndpoints, true);
TRI_AddGlobalFunctionVocbase(context, "RELOAD_AUTH", JS_ReloadAuth, true);
TRI_AddGlobalFunctionVocbase(context, "TRANSACTION", JS_Transaction, true);

View File

@ -155,7 +155,7 @@ static bool EqualKeyDatabaseName (TRI_associative_pointer_t* array,
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- endpoint functions
// --SECTION-- server id functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
@ -163,99 +163,6 @@ static bool EqualKeyDatabaseName (TRI_associative_pointer_t* array,
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes the endpoint
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementEndpoint (TRI_associative_pointer_t* array,
void const* element) {
TRI_server_endpoint_t const* e = element;
return TRI_FnvHashString((char const*) e->_endpoint);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compares an endpoint name and an endpoint
////////////////////////////////////////////////////////////////////////////////
static bool EqualKeyEndpoint (TRI_associative_pointer_t* array,
void const* key,
void const* element) {
char const* k = (char const*) key;
TRI_server_endpoint_t const* e = element;
return TRI_EqualString(k, e->_endpoint);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- tick functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current tick value, without using a lock
////////////////////////////////////////////////////////////////////////////////
static inline TRI_voc_tick_t GetTick (void) {
return (ServerIdentifier | (CurrentTick << 16));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates the tick counter, without using a lock
////////////////////////////////////////////////////////////////////////////////
static inline void UpdateTick (TRI_voc_tick_t tick) {
TRI_voc_tick_t s = tick >> 16;
if (CurrentTick < s) {
CurrentTick = s;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extract the numeric part from a filename
////////////////////////////////////////////////////////////////////////////////
static uint64_t GetNumericFilenamePart (const char* filename) {
char* pos;
pos = strrchr(filename, '-');
if (pos == NULL) {
return 0;
}
return TRI_UInt64String(pos + 1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compare two filenames, based on the numeric part contained in
/// the filename. this is used to sort database filenames on startup
////////////////////////////////////////////////////////////////////////////////
static int NameComparator (const void* lhs, const void* rhs) {
const char* l = *((char**) lhs);
const char* r = *((char**) rhs);
const uint64_t numLeft = GetNumericFilenamePart(l);
const uint64_t numRight = GetNumericFilenamePart(r);
if (numLeft != numRight) {
return numLeft < numRight ? -1 : 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a new server id
///
@ -393,6 +300,43 @@ static int DetermineServerId (TRI_server_t* server) {
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- tick functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current tick value, without using a lock
////////////////////////////////////////////////////////////////////////////////
static inline TRI_voc_tick_t GetTick (void) {
return (ServerIdentifier | (CurrentTick << 16));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates the tick counter, without using a lock
////////////////////////////////////////////////////////////////////////////////
static inline void UpdateTick (TRI_voc_tick_t tick) {
TRI_voc_tick_t s = tick >> 16;
if (CurrentTick < s) {
CurrentTick = s;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief reads shutdown information file
/// this is called at server startup. if the file is present, the last tick
@ -513,6 +457,58 @@ static int WriteShutdownInfo (TRI_server_t* server) {
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- database functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current tick value, without using a lock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief extract the numeric part from a filename
////////////////////////////////////////////////////////////////////////////////
static uint64_t GetNumericFilenamePart (const char* filename) {
char* pos;
pos = strrchr(filename, '-');
if (pos == NULL) {
return 0;
}
return TRI_UInt64String(pos + 1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compare two filenames, based on the numeric part contained in
/// the filename. this is used to sort database filenames on startup
////////////////////////////////////////////////////////////////////////////////
static int NameComparator (const void* lhs, const void* rhs) {
const char* l = *((char**) lhs);
const char* r = *((char**) rhs);
const uint64_t numLeft = GetNumericFilenamePart(l);
const uint64_t numRight = GetNumericFilenamePart(r);
if (numLeft != numRight) {
return numLeft < numRight ? -1 : 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief iterate over all databases in the databases directory and open them
////////////////////////////////////////////////////////////////////////////////
@ -1298,7 +1294,6 @@ static void DatabaseManager (void* data) {
// remember the database path
char* path;
printf("PHYSICALLY REMOVING DATABASE %s\n", database->_name);
path = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, database->_path);
TRI_DestroyVocBase(database);
@ -1348,12 +1343,17 @@ TRI_server_t* TRI_CreateServer () {
////////////////////////////////////////////////////////////////////////////////
int TRI_InitServer (TRI_server_t* server,
void* applicationEndpointServer,
char const* basePath,
TRI_vocbase_defaults_t const* defaults,
bool disableLoggers,
bool disableAppliers) {
assert(server != NULL);
assert(basePath != NULL);
// c++ object, may be null in console mode
server->_applicationEndpointServer = applicationEndpointServer;
// .............................................................................
// set up paths and filenames
@ -1426,20 +1426,6 @@ int TRI_InitServer (TRI_server_t* server,
TRI_InitMutex(&server->_createLock);
// .............................................................................
// endpoints
// .............................................................................
TRI_InitAssociativePointer(&server->_endpoints,
TRI_UNKNOWN_MEM_ZONE,
&TRI_HashStringKeyAssociativePointer,
HashElementEndpoint,
EqualKeyEndpoint,
NULL);
TRI_InitReadWriteLock(&server->_endpointsLock);
server->_disableReplicationLoggers = disableLoggers;
server->_disableReplicationAppliers = disableAppliers;
@ -1457,9 +1443,6 @@ int TRI_InitServer (TRI_server_t* server,
void TRI_DestroyServer (TRI_server_t* server) {
CloseDatabases(server);
TRI_DestroyReadWriteLock(&server->_endpointsLock);
TRI_DestroyAssociativePointer(&server->_endpoints);
TRI_DestroyMutex(&server->_createLock);
TRI_DestroyVectorPointer(&server->_droppedDatabases);
TRI_DestroyReadWriteLock(&server->_databasesLock);
@ -2000,65 +1983,6 @@ TRI_voc_tick_t TRI_CurrentTickServer () {
/// @{
////////////////////////////////////////////////////////////////////////////////
static TRI_server_endpoint_t* CreateEndpoint (char const* endpoint,
TRI_vector_string_t const* databases) {
TRI_server_endpoint_t* ep;
ep = TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(TRI_server_endpoint_t), false);
if (ep == NULL) {
return NULL;
}
ep->_endpoint = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, endpoint);
if (ep->_endpoint == NULL) {
TRI_Free(TRI_CORE_MEM_ZONE, ep);
return NULL;
}
TRI_InitVectorString(&ep->_databases, TRI_CORE_MEM_ZONE);
TRI_CopyDataVectorString(TRI_CORE_MEM_ZONE, &ep->_databases, databases);
return ep;
}
static void FreeEndpoint (TRI_server_endpoint_t* ep) {
TRI_FreeString(TRI_CORE_MEM_ZONE, ep->_endpoint);
TRI_DestroyVectorString(&ep->_databases);
TRI_Free(TRI_CORE_MEM_ZONE, ep);
}
int TRI_StoreEndpointServer (TRI_server_t* server,
char const* endpoint,
TRI_vector_string_t const* databases) {
TRI_server_endpoint_t* ep;
TRI_WriteLockReadWriteLock(&server->_endpointsLock);
ep = TRI_RemoveKeyAssociativePointer(&server->_endpoints, endpoint);
if (ep != NULL) {
FreeEndpoint(ep);
}
ep = CreateEndpoint(endpoint, databases);
if (ep == NULL) {
TRI_WriteUnlockReadWriteLock(&server->_endpointsLock);
return TRI_ERROR_OUT_OF_MEMORY;
}
TRI_InsertKeyAssociativePointer(&server->_endpoints, ep->_endpoint, ep, false);
TRI_WriteUnlockReadWriteLock(&server->_endpointsLock);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief msyncs a memory block between begin (incl) and end (excl)
////////////////////////////////////////////////////////////////////////////////

View File

@ -62,10 +62,8 @@ typedef struct TRI_server_s {
TRI_vector_pointer_t _droppedDatabases;
bool _shutdown;
TRI_associative_pointer_t _endpoints;
TRI_read_write_lock_t _endpointsLock;
TRI_vocbase_defaults_t _defaults;
void* _applicationEndpointServer; // ptr to C++ object
char* _basePath;
char* _databasePath;
@ -80,17 +78,6 @@ typedef struct TRI_server_s {
}
TRI_server_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief endpoint declaration for a server
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_server_endpoint_s {
char* _endpoint;
TRI_vector_string_t _databases;
}
TRI_server_endpoint_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief page size
////////////////////////////////////////////////////////////////////////////////
@ -121,6 +108,7 @@ TRI_server_t* TRI_CreateServer (void);
////////////////////////////////////////////////////////////////////////////////
int TRI_InitServer (TRI_server_t* server,
void*,
char const*,
TRI_vocbase_defaults_t const*,
bool,
@ -277,14 +265,6 @@ TRI_voc_tick_t TRI_CurrentTickServer (void);
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief store a setting for an endpoint
////////////////////////////////////////////////////////////////////////////////
int TRI_StoreEndpointServer (TRI_server_t*,
char const*,
TRI_vector_string_t const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief msyncs a memory block between begin (incl) and end (excl)
////////////////////////////////////////////////////////////////////////////////

View File

@ -650,6 +650,58 @@ actions.defineHttp({
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_get_admin_configure_endpoint
/// @brief configures a server endpoint
///
/// @RESTHEADER{POST /_admin/endpoint,configures a server endpoint}
///
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/endpoint",
context : "admin",
prefix : true,
callback : function (req, res) {
try {
if (req.requestType === actions.GET) {
actions.resultOk(req, res, actions.HTTP_OK, internal.listEndpoints());
}
else if (req.requestType === actions.POST) {
var body = actions.getJsonBody(req, res);
if (typeof body === undefined || typeof body.endpoint !== 'string') {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"invalid endpoint value");
return;
}
var result = internal.configureEndpoint(body.endpoint, body.databases || [ ]);
actions.resultOk(req, res, actions.HTTP_OK, { result: result });
}
else if (req.requestType === actions.DELETE) {
if (req.suffix.length !== 1) {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expected DELETE /" + this.url + "/<endpoint>");
return;
}
var endpoint = decodeURIComponent(req.suffix[0]);
var result = internal.removeEndpoint(endpoint);
actions.resultOk(req, res, actions.HTTP_OK, { result: result });
}
else {
actions.resultUnsupported(req, res);
}
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -4,7 +4,7 @@
REPLICATION_LOGGER_START, REPLICATION_LOGGER_STOP, REPLICATION_LOGGER_STATE,
REPLICATION_LOGGER_CONFIGURE, REPLICATION_APPLIER_CONFIGURE, REPLICATION_APPLIER_START,
REPLICATION_APPLIER_STOP, REPLICATION_APPLIER_FORGET, REPLICATION_APPLIER_STATE,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID, CONFIGURE_ENDPOINT, REMOVE_ENDPOINT, LIST_ENDPOINTS,
SYS_DEBUG_CAN_USE_FAILAT, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT, SYS_DEBUG_CLEAR_FAILAT,
SYS_DOWNLOAD, SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
@ -329,6 +329,33 @@
delete REPLICATION_SERVER_ID;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief configureEndpoint
////////////////////////////////////////////////////////////////////////////////
if (typeof CONFIGURE_ENDPOINT !== "undefined") {
exports.configureEndpoint = CONFIGURE_ENDPOINT;
delete CONFIGURE_ENDPOINT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removeEndpoint
////////////////////////////////////////////////////////////////////////////////
if (typeof REMOVE_ENDPOINT !== "undefined") {
exports.removeEndpoint = REMOVE_ENDPOINT;
delete REMOVE_ENDPOINT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief listEndpoints
////////////////////////////////////////////////////////////////////////////////
if (typeof LIST_ENDPOINTS !== "undefined") {
exports.listEndpoints = LIST_ENDPOINTS;
delete LIST_ENDPOINTS;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
REPLICATION_LOGGER_START, REPLICATION_LOGGER_STOP, REPLICATION_LOGGER_STATE,
REPLICATION_LOGGER_CONFIGURE, REPLICATION_APPLIER_CONFIGURE, REPLICATION_APPLIER_START,
REPLICATION_APPLIER_STOP, REPLICATION_APPLIER_FORGET, REPLICATION_APPLIER_STATE,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID, CONFIGURE_ENDPOINT, REMOVE_ENDPOINT, LIST_ENDPOINTS,
SYS_DEBUG_CAN_USE_FAILAT, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT, SYS_DEBUG_CLEAR_FAILAT,
SYS_DOWNLOAD, SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
@ -329,6 +329,33 @@
delete REPLICATION_SERVER_ID;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief configureEndpoint
////////////////////////////////////////////////////////////////////////////////
if (typeof CONFIGURE_ENDPOINT !== "undefined") {
exports.configureEndpoint = CONFIGURE_ENDPOINT;
delete CONFIGURE_ENDPOINT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removeEndpoint
////////////////////////////////////////////////////////////////////////////////
if (typeof REMOVE_ENDPOINT !== "undefined") {
exports.removeEndpoint = REMOVE_ENDPOINT;
delete REMOVE_ENDPOINT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief listEndpoints
////////////////////////////////////////////////////////////////////////////////
if (typeof LIST_ENDPOINTS !== "undefined") {
exports.listEndpoints = LIST_ENDPOINTS;
delete LIST_ENDPOINTS;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////

View File

@ -160,7 +160,7 @@
fm.scanAppDirectory();
}
catch (err) {
console.error("cannot initialize FOXX application: %s", String(err));
console.error("cannot initialize Foxx application: %s", String(err));
}
var aal = internal.db._collection("_aal");

View File

@ -101,12 +101,6 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return the protocol to be used
////////////////////////////////////////////////////////////////////////////////
virtual Endpoint::ProtocolType getProtocol () const = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief return the encryption to be used
////////////////////////////////////////////////////////////////////////////////
@ -122,11 +116,23 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief starts listining
/// @brief add another endpoint at runtime
////////////////////////////////////////////////////////////////////////////////
virtual bool addEndpoint (Endpoint*) = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief remove an endpoint at runtime
////////////////////////////////////////////////////////////////////////////////
virtual bool removeEndpoint (Endpoint*) = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief starts listening
////////////////////////////////////////////////////////////////////////////////
virtual void startListening () = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief shuts down handlers
////////////////////////////////////////////////////////////////////////////////

View File

@ -180,31 +180,64 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief starts listining
/// @brief starts listening
////////////////////////////////////////////////////////////////////////////////
void startListening () {
EndpointList::ListType endpoints = _endpointList->getEndpoints(this->getProtocol(), this->getEncryption());
map<string, Endpoint*> endpoints = _endpointList->getByPrefix(this->getEncryption());
for (EndpointList::ListType::const_iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LOGGER_TRACE("trying to bind to endpoint '" << (*i).first->getSpecification() << "' for requests");
for (map<string, Endpoint*>::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LOGGER_TRACE("trying to bind to endpoint '" << (*i).first << "' for requests");
bool ok = openEndpoint((*i).first);
bool ok = openEndpoint((*i).second);
if (ok) {
LOGGER_DEBUG("bound to endpoint '" << (*i).first->getSpecification() << "'");
LOGGER_DEBUG("bound to endpoint '" << (*i).first << "'");
}
else {
if ((*i).second) {
LOGGER_FATAL_AND_EXIT("failed to bind to endpoint '" << (*i).first->getSpecification() << "'");
}
else {
LOGGER_WARNING("failed to bind to endpoint '" << (*i).first->getSpecification() << "'");
}
LOGGER_FATAL_AND_EXIT("failed to bind to endpoint '" << (*i).first << "'");
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add another endpoint at runtime
/// the caller must make sure this is not called in parallel
////////////////////////////////////////////////////////////////////////////////
bool addEndpoint (Endpoint* endpoint) {
bool ok = openEndpoint(endpoint);
if (ok) {
LOGGER_INFO("added endpoint '" << endpoint->getSpecification() << "'");
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an endpoint at runtime
/// the caller must make sure this is not called in parallel
////////////////////////////////////////////////////////////////////////////////
bool removeEndpoint (Endpoint* endpoint) {
for (vector<ListenTask*>::iterator i = _listenTasks.begin(); i != _listenTasks.end(); ++i) {
ListenTask* task = (*i);
if (task->endpoint() == endpoint) {
// TODO: remove commtasks for the listentask
_scheduler->destroyTask(task);
_listenTasks.erase(i);
LOGGER_INFO("removed endpoint '" << endpoint->getSpecification() << "'");
return true;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief shuts down handlers
////////////////////////////////////////////////////////////////////////////////
@ -220,7 +253,7 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief stops listining
/// @brief stops listening
////////////////////////////////////////////////////////////////////////////////
void stopListening () {
@ -255,7 +288,8 @@ namespace triagens {
/// @brief handles connection request
////////////////////////////////////////////////////////////////////////////////
virtual void handleConnected (TRI_socket_t s, ConnectionInfo& info) {
virtual void handleConnected (TRI_socket_t s,
ConnectionInfo& info) {
GeneralCommTask<S, HF>* task = new SpecificCommTask<S, HF, CT>(dynamic_cast<S*>(this), s, info, _keepAliveTimeout);
GENERAL_SERVER_LOCK(&_commTasksLock);

View File

@ -151,19 +151,16 @@ bool ApplicationEndpointServer::buildServers () {
EndpointServer* server;
// unencrypted endpoints
if (_endpointList.count(Endpoint::PROTOCOL_HTTP, Endpoint::ENCRYPTION_NONE) > 0) {
// http endpoints
server = new HttpServer(_applicationScheduler->scheduler(),
_applicationDispatcher->dispatcher(),
_keepAliveTimeout,
_handlerFactory);
server = new HttpServer(_applicationScheduler->scheduler(),
_applicationDispatcher->dispatcher(),
_keepAliveTimeout,
_handlerFactory);
server->setEndpointList(&_endpointList);
_servers.push_back(server);
}
server->setEndpointList(&_endpointList);
_servers.push_back(server);
// ssl endpoints
if (_endpointList.count(Endpoint::PROTOCOL_HTTP, Endpoint::ENCRYPTION_SSL) > 0) {
if (_endpointList.has(Endpoint::ENCRYPTION_SSL)) {
// check the ssl context
if (_sslContext == 0) {
LOGGER_INFO("please use the --server.keyfile option");
@ -254,17 +251,11 @@ bool ApplicationEndpointServer::parsePhase2 (ProgramOptions& options) {
LOGGER_FATAL_AND_EXIT("no endpoint has been specified, giving up");
}
const vector<string> dbNames;
// add & validate endpoints
for (vector<string>::const_iterator i = _endpoints.begin(); i != _endpoints.end(); ++i) {
Endpoint* endpoint = Endpoint::serverFactory(*i, _backlogSize);
if (endpoint == 0) {
LOGGER_FATAL_AND_EXIT("invalid endpoint '" << *i << "'");
}
assert(endpoint);
bool ok = _endpointList.addEndpoint(endpoint->getProtocol(), endpoint->getEncryption(), endpoint, true);
bool ok = _endpointList.add((*i), dbNames, _backlogSize);
if (! ok) {
LOGGER_FATAL_AND_EXIT("invalid endpoint '" << *i << "'");
@ -276,36 +267,123 @@ bool ApplicationEndpointServer::parsePhase2 (ProgramOptions& options) {
}
////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
/// @brief return a list of all endpoints
////////////////////////////////////////////////////////////////////////////////
bool ApplicationEndpointServer::addEndpoint (std::string const& newEndpoint) {
// create the ssl context (if possible)
bool ok = createSslContext();
std::map<std::string, std::vector<std::string> > ApplicationEndpointServer::getEndpoints () {
MUTEX_LOCKER(_endpointsLock);
if (! ok) {
return _endpointList.getAll();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a new endpoint at runtime, and connects to it
////////////////////////////////////////////////////////////////////////////////
bool ApplicationEndpointServer::addEndpoint (std::string const& newEndpoint,
vector<string> const& dbNames) {
// validate...
const string unified = Endpoint::getUnifiedForm(newEndpoint);
if (unified.empty()) {
// invalid endpoint
return false;
}
Endpoint* endpoint = Endpoint::serverFactory(newEndpoint, _backlogSize);
if (endpoint != 0) {
ok = _endpointList.addEndpoint(endpoint->getProtocol(), endpoint->getEncryption(), endpoint, false);
if (ok) {
_endpoints.push_back(newEndpoint);
}
Endpoint::EncryptionType encryption;
if (unified.substr(0, 6) == "ssl://") {
encryption = Endpoint::ENCRYPTION_SSL;
}
else {
ok = false;
encryption = Endpoint::ENCRYPTION_NONE;
}
if (! ok) {
LOGGER_WARNING("Could not add endpoint '" << newEndpoint << "'");
// find the correct server (HTTP or HTTPS)
for (size_t i = 0; i < _servers.size(); ++i) {
if (_servers[i]->getEncryption() == encryption) {
// found the correct server
MUTEX_LOCKER(_endpointsLock);
Endpoint* endpoint;
bool ok = _endpointList.add(newEndpoint, dbNames, _backlogSize, &endpoint);
if (! ok) {
return false;
}
if (endpoint == 0) {
// in this case, we updated an existing endpoint and are done
return true;
}
// this connects the new endpoint
ok = _servers[i]->addEndpoint(endpoint);
if (ok) {
LOGGER_DEBUG("bound to endpoint '" << newEndpoint << "'");
}
else {
LOGGER_WARNING("failed to bind to endpoint '" << newEndpoint << "'");
}
return ok;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an existing endpoint, and disconnects from it
////////////////////////////////////////////////////////////////////////////////
bool ApplicationEndpointServer::removeEndpoint (std::string const& oldEndpoint) {
// validate...
const string unified = Endpoint::getUnifiedForm(oldEndpoint);
if (unified.empty()) {
// invalid endpoint
return false;
}
return ok;
Endpoint::EncryptionType encryption;
if (unified.substr(0, 6) == "ssl://") {
encryption = Endpoint::ENCRYPTION_SSL;
}
else {
encryption = Endpoint::ENCRYPTION_NONE;
}
// find the correct server (HTTP or HTTPS)
for (size_t i = 0; i < _servers.size(); ++i) {
if (_servers[i]->getEncryption() == encryption) {
// found the correct server
MUTEX_LOCKER(_endpointsLock);
Endpoint* endpoint;
bool ok = _endpointList.remove(unified, &endpoint);
if (! ok) {
LOGGER_WARNING("could not remove endpoint '" << oldEndpoint << "'");
return false;
}
// this disconnects the new endpoint
ok = _servers[i]->removeEndpoint(endpoint);
delete endpoint;
if (ok) {
LOGGER_DEBUG("removed endpoint '" << oldEndpoint << "'");
}
else {
LOGGER_WARNING("failed to remove endpoint '" << oldEndpoint << "'");
}
return ok;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
@ -313,7 +391,7 @@ bool ApplicationEndpointServer::addEndpoint (std::string const& newEndpoint) {
////////////////////////////////////////////////////////////////////////////////
bool ApplicationEndpointServer::prepare () {
// dump used endpoints for user information
// dump all endpoints for user information
_endpointList.dump();
_handlerFactory = new HttpHandlerFactory(_authenticationRealm,

View File

@ -32,6 +32,7 @@
#include <openssl/ssl.h>
#include "Basics/MutexLocker.h"
#include "GeneralServer/EndpointServer.h"
#include "Rest/EndpointList.h"
#include "HttpServer/HttpHandlerFactory.h"
@ -150,10 +151,23 @@ namespace triagens {
bool parsePhase2 (basics::ProgramOptions&);
////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
/// @brief return a list of all endpoints
////////////////////////////////////////////////////////////////////////////////
std::map<std::string, std::vector<std::string> > getEndpoints ();
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a new endpoint at runtime, and connects to it
////////////////////////////////////////////////////////////////////////////////
bool addEndpoint (std::string const&);
bool addEndpoint (std::string const&,
std::vector<std::string> const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an existing endpoint and disconnects from it
////////////////////////////////////////////////////////////////////////////////
bool removeEndpoint (std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
@ -275,6 +289,12 @@ namespace triagens {
rest::EndpointList _endpointList;
////////////////////////////////////////////////////////////////////////////////
/// @brief mutex to protect _endpointList
////////////////////////////////////////////////////////////////////////////////
basics::Mutex _endpointsLock;
////////////////////////////////////////////////////////////////////////////////
/// @brief deprecated hidden option for downwards compatibility
////////////////////////////////////////////////////////////////////////////////

View File

@ -97,14 +97,6 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return the protocol to be used
////////////////////////////////////////////////////////////////////////////////
Endpoint::ProtocolType getProtocol () const {
return Endpoint::PROTOCOL_HTTP;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the handler factory
////////////////////////////////////////////////////////////////////////////////

View File

@ -60,14 +60,12 @@ using namespace triagens::rest;
Endpoint::Endpoint (const Endpoint::EndpointType type,
const Endpoint::DomainType domainType,
const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption,
const std::string& specification,
int listenBacklog) :
_connected(false),
_type(type),
_domainType(domainType),
_protocol(protocol),
_encryption(encryption),
_specification(specification),
_listenBacklog(listenBacklog) {
@ -95,6 +93,81 @@ Endpoint::~Endpoint () {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return the endpoint specification in a unified form
////////////////////////////////////////////////////////////////////////////////
std::string Endpoint::getUnifiedForm (const std::string& specification) {
if (specification.size() < 7) {
return "";
}
string copy = specification;
StringUtils::trimInPlace(copy);
copy = StringUtils::tolower(copy);
if (specification[specification.size() - 1] == '/') {
// address ends with a slash => remove
copy = copy.substr(0, copy.size() - 1);
}
// read protocol from string
if (StringUtils::isPrefix(copy, "http@")) {
copy = copy.substr(5);
}
#if TRI_HAVE_LINUX_SOCKETS
if (StringUtils::isPrefix(copy, "unix://")) {
// unix socket
return copy;
}
#else
// no unix socket for windows
if (StringUtils::isPrefix(copy, "unix://")) {
// unix socket
return "";
}
#endif
else if (! StringUtils::isPrefix(copy, "ssl://") &&
! StringUtils::isPrefix(copy, "tcp://")) {
// invalid type
return "";
}
// tcp/ip or ssl
size_t found;
string temp = copy.substr(6, copy.length()); // strip tcp:// or ssl://
if (temp[0] == '[') {
// ipv6
found = temp.find("]:", 1);
if (found != string::npos && found > 2 && found + 2 < temp.size()) {
// hostname and port (e.g. [address]:port)
return copy;
}
found = temp.find("]", 1);
if (found != string::npos && found > 2 && found + 1 == temp.size()) {
// hostname only (e.g. [address])
return copy + ":" + StringUtils::itoa(EndpointIp::_defaultPort);
}
// invalid address specification
return "";
}
// ipv4
found = temp.find(':');
if (found != string::npos && found + 1 < temp.size()) {
// hostname and port
return copy;
}
// hostname only
return copy + ":" + StringUtils::itoa(EndpointIp::_defaultPort);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a client endpoint object from a string value
////////////////////////////////////////////////////////////////////////////////
@ -133,9 +206,6 @@ Endpoint* Endpoint::factory (const Endpoint::EndpointType type,
copy = copy.substr(0, copy.size() - 1);
}
// default protocol is HTTP
Endpoint::ProtocolType protocol = PROTOCOL_HTTP;
// read protocol from string
size_t found = copy.find('@');
if (found != string::npos) {
@ -161,7 +231,7 @@ Endpoint* Endpoint::factory (const Endpoint::EndpointType type,
#if TRI_HAVE_LINUX_SOCKETS
else if (StringUtils::isPrefix(domainType, "unix://")) {
// unix socket
return new EndpointUnixDomain(type, protocol, specification, listenBacklog, copy.substr(strlen("unix://")));
return new EndpointUnixDomain(type, specification, listenBacklog, copy.substr(strlen("unix://")));
}
#else
// no unix socket for windows
@ -186,14 +256,14 @@ Endpoint* Endpoint::factory (const Endpoint::EndpointType type,
// hostname and port (e.g. [address]:port)
uint16_t port = (uint16_t) StringUtils::uint32(copy.substr(found + 2));
return new EndpointIpV6(type, protocol, encryption, specification, listenBacklog, copy.substr(1, found - 1), port);
return new EndpointIpV6(type, encryption, specification, listenBacklog, copy.substr(1, found - 1), port);
}
found = copy.find("]", 1);
if (found != string::npos && found > 2 && found + 1 == copy.size()) {
// hostname only (e.g. [address])
return new EndpointIpV6(type, protocol, encryption, specification, listenBacklog, copy.substr(1, found - 1), EndpointIp::_defaultPort);
return new EndpointIpV6(type, encryption, specification, listenBacklog, copy.substr(1, found - 1), EndpointIp::_defaultPort);
}
// invalid address specification
@ -207,11 +277,11 @@ Endpoint* Endpoint::factory (const Endpoint::EndpointType type,
// hostname and port
uint16_t port = (uint16_t) StringUtils::uint32(copy.substr(found + 1));
return new EndpointIpV4(type, protocol, encryption, specification, listenBacklog, copy.substr(0, found), port);
return new EndpointIpV4(type, encryption, specification, listenBacklog, copy.substr(0, found), port);
}
// hostname only
return new EndpointIpV4(type, protocol, encryption, specification, listenBacklog, copy, EndpointIp::_defaultPort);
return new EndpointIpV4(type, encryption, specification, listenBacklog, copy, EndpointIp::_defaultPort);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -96,15 +96,6 @@ namespace triagens {
DOMAIN_IPV6
};
////////////////////////////////////////////////////////////////////////////////
/// @brief protocols used for endpoints
////////////////////////////////////////////////////////////////////////////////
enum ProtocolType {
PROTOCOL_UNKNOWN,
PROTOCOL_HTTP
};
////////////////////////////////////////////////////////////////////////////////
/// @brief encryption used when talking to endpoint
////////////////////////////////////////////////////////////////////////////////
@ -135,7 +126,6 @@ namespace triagens {
Endpoint (const EndpointType,
const DomainType,
const ProtocolType,
const EncryptionType,
const std::string&,
int);
@ -163,6 +153,12 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return the endpoint specification in a unified form
////////////////////////////////////////////////////////////////////////////////
static std::string getUnifiedForm (const std::string&);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a server endpoint from a string value
////////////////////////////////////////////////////////////////////////////////
@ -249,14 +245,6 @@ namespace triagens {
return _domainType;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the protocol of an endpoint
////////////////////////////////////////////////////////////////////////////////
ProtocolType getProtocol () const {
return _protocol;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the encryption used
////////////////////////////////////////////////////////////////////////////////
@ -336,12 +324,6 @@ namespace triagens {
DomainType _domainType;
////////////////////////////////////////////////////////////////////////////////
/// @brief protocol used
////////////////////////////////////////////////////////////////////////////////
ProtocolType _protocol;
////////////////////////////////////////////////////////////////////////////////
/// @brief encryption used
////////////////////////////////////////////////////////////////////////////////

View File

@ -81,13 +81,12 @@ const std::string EndpointIp::_defaultHost = "127.0.0.1";
EndpointIp::EndpointIp (const Endpoint::EndpointType type,
const Endpoint::DomainType domainType,
const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption,
const std::string& specification,
int listenBacklog,
const std::string& host,
const uint16_t port) :
Endpoint(type, domainType, protocol, encryption, specification, listenBacklog), _host(host), _port(port) {
Endpoint(type, domainType, encryption, specification, listenBacklog), _host(host), _port(port) {
assert(domainType == DOMAIN_IPV4 || domainType == Endpoint::DOMAIN_IPV6);
}

View File

@ -58,7 +58,6 @@ namespace triagens {
EndpointIp (const EndpointType,
const DomainType,
const ProtocolType,
const EncryptionType,
const std::string&,
int,

View File

@ -50,13 +50,12 @@ using namespace triagens::rest;
////////////////////////////////////////////////////////////////////////////////
EndpointIpV4::EndpointIpV4 (const Endpoint::EndpointType type,
const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption,
const std::string& specification,
int listenBacklog,
const std::string& host,
const uint16_t port) :
EndpointIp(type, DOMAIN_IPV4, protocol, encryption, specification, listenBacklog, host, port) {
EndpointIp(type, DOMAIN_IPV4, encryption, specification, listenBacklog, host, port) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -56,7 +56,6 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
EndpointIpV4 (const EndpointType,
const ProtocolType,
const EncryptionType,
const std::string&,
int,

View File

@ -50,13 +50,12 @@ using namespace triagens::rest;
////////////////////////////////////////////////////////////////////////////////
EndpointIpV6::EndpointIpV6 (const Endpoint::EndpointType type,
const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption,
const std::string& specification,
int listenBacklog,
const std::string& host,
const uint16_t port) :
EndpointIp(type, DOMAIN_IPV6, protocol, encryption, specification, listenBacklog, host, port) {
EndpointIp(type, DOMAIN_IPV6, encryption, specification, listenBacklog, host, port) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -56,7 +56,6 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
EndpointIpV6 (const EndpointType,
const ProtocolType,
const EncryptionType,
const std::string&,
int,

View File

@ -27,8 +27,10 @@
#include "EndpointList.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
using namespace triagens::basics;
using namespace triagens::rest;
// -----------------------------------------------------------------------------
@ -49,7 +51,7 @@ using namespace triagens::rest;
////////////////////////////////////////////////////////////////////////////////
EndpointList::EndpointList () :
_lists() {
_endpoints() {
}
////////////////////////////////////////////////////////////////////////////////
@ -57,13 +59,15 @@ EndpointList::EndpointList () :
////////////////////////////////////////////////////////////////////////////////
EndpointList::~EndpointList () {
for (map<string, ListType>::iterator i = _lists.begin(); i != _lists.end(); ++i) {
for (ListType::iterator i2 = (*i).second.begin(); i2 != (*i).second.end(); ++i2) {
delete (*i2).first;
}
map<string, pair<Endpoint*, vector<string> > >::iterator it;
(*i).second.clear();
for (it = _endpoints.begin(); it != _endpoints.end(); ++it) {
Endpoint* ep = (*it).second.first;
delete ep;
}
_endpoints.clear();
}
////////////////////////////////////////////////////////////////////////////////
@ -80,19 +84,151 @@ EndpointList::~EndpointList () {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief count the number of elements in a sub-list
/// @brief add a new endpoint
////////////////////////////////////////////////////////////////////////////////
size_t EndpointList::count (const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption) const {
bool EndpointList::add (const string& specification,
const vector<string>& dbNames,
int backLogSize,
Endpoint** dst) {
const string key = Endpoint::getUnifiedForm(specification);
map<string, ListType>::const_iterator i = _lists.find(getKey(protocol, encryption));
if (key.empty()) {
return false;
}
if (i == _lists.end()) {
return 0;
}
map<string, pair<Endpoint*, vector<string> > >::iterator it = _endpoints.find(key);
return i->second.size();
if (it != _endpoints.end()) {
// already in list, just update
(*it).second.second = dbNames;
*dst = 0;
return true;
}
Endpoint* ep = Endpoint::serverFactory(key, backLogSize);
if (ep == 0) {
return false;
}
_endpoints[key] = pair<Endpoint*, vector<string> >(ep, dbNames);
if (dst != 0) {
*dst = ep;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a specific endpoint
////////////////////////////////////////////////////////////////////////////////
bool EndpointList::remove (const string& specification,
Endpoint** dst) {
const string key = Endpoint::getUnifiedForm(specification);
if (key.empty()) {
return false;
}
map<string, pair<Endpoint*, vector<string> > >::const_iterator it = _endpoints.find(key);
if (it == _endpoints.end()) {
// not in list
return false;
}
*dst = (*it).second.first;
_endpoints.erase(key);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return all endpoints
////////////////////////////////////////////////////////////////////////////////
std::map<std::string, std::vector<std::string> > EndpointList::getAll () const {
map<string, vector<string> > result;
map<string, pair<Endpoint*, vector<string> > >::const_iterator it;
for (it = _endpoints.begin(); it != _endpoints.end(); ++it) {
result[(*it).first] = (*it).second.second;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return all endpoints with a certain prefix
////////////////////////////////////////////////////////////////////////////////
std::map<std::string, Endpoint*> EndpointList::getByPrefix (const string& prefix) const {
map<string, Endpoint*> result;
map<string, pair<Endpoint*, vector<string> > >::const_iterator it;
for (it = _endpoints.begin(); it != _endpoints.end(); ++it) {
const string& key = (*it).first;
if (StringUtils::isPrefix(key, prefix)) {
result[key] = (*it).second.first;
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return all endpoints with a certain encryption type
////////////////////////////////////////////////////////////////////////////////
std::map<std::string, Endpoint*> EndpointList::getByPrefix (const Endpoint::EncryptionType encryption) const {
map<string, Endpoint*> result;
map<string, pair<Endpoint*, vector<string> > >::const_iterator it;
for (it = _endpoints.begin(); it != _endpoints.end(); ++it) {
const string& key = (*it).first;
if (encryption == Endpoint::ENCRYPTION_SSL) {
if (StringUtils::isPrefix(key, "ssl://")) {
result[key] = (*it).second.first;
}
}
else {
if (StringUtils::isPrefix(key, "tcp://") || StringUtils::isPrefix(key, "unix://")) {
result[key] = (*it).second.first;
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return if there is an endpoint with a certain encryption type
////////////////////////////////////////////////////////////////////////////////
bool EndpointList::has (const Endpoint::EncryptionType encryption) const {
map<string, pair<Endpoint*, vector<string> > >::const_iterator it;
for (it = _endpoints.begin(); it != _endpoints.end(); ++it) {
const string& key = (*it).first;
if (encryption == Endpoint::ENCRYPTION_SSL) {
if (StringUtils::isPrefix(key, "ssl://")) {
return true;
}
}
else {
if (StringUtils::isPrefix(key, "tcp://") || StringUtils::isPrefix(key, "unix://")) {
return true;
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
@ -100,43 +236,25 @@ size_t EndpointList::count (const Endpoint::ProtocolType protocol,
////////////////////////////////////////////////////////////////////////////////
void EndpointList::dump () const {
for (map<string, ListType>::const_iterator i = _lists.begin(); i != _lists.end(); ++i) {
for (ListType::const_iterator i2 = (*i).second.begin(); i2 != (*i).second.end(); ++i2) {
LOGGER_INFO("using endpoint '" << (*i2).first->getSpecification() << "' for " << (*i).first << " requests");
}
for (map<string, pair<Endpoint*, vector<string> > >::const_iterator it = _endpoints.begin(); it != _endpoints.end(); ++it) {
Endpoint const* ep = (*it).second.first;
LOGGER_INFO("using endpoint '" << (*it).first << "' for " << getEncryptionName(ep->getEncryption()) << " requests");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return all endpoints for a specific protocol
/// @brief return an encryption name
////////////////////////////////////////////////////////////////////////////////
EndpointList::ListType EndpointList::getEndpoints (const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption) const {
EndpointList::ListType result;
map<string, EndpointList::ListType>::const_iterator i = _lists.find(getKey(protocol, encryption));
if (i != _lists.end()) {
for (ListType::const_iterator i2 = (*i).second.begin(); i2 != (*i).second.end(); ++i2) {
result.insert(pair<Endpoint*, bool>((*i2).first, (*i2).second));
}
std::string EndpointList::getEncryptionName (const Endpoint::EncryptionType encryption) {
switch (encryption) {
case Endpoint::ENCRYPTION_SSL:
return "ssl-encrypted";
case Endpoint::ENCRYPTION_NONE:
default:
return "non-encrypted";
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an endpoint for a specific protocol
////////////////////////////////////////////////////////////////////////////////
bool EndpointList::addEndpoint (const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption,
Endpoint* endpoint,
bool isSystem) {
_lists[getKey(protocol, encryption)].insert(pair<Endpoint*, bool>(endpoint, isSystem));
return true;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -43,25 +43,6 @@ namespace triagens {
public:
// -----------------------------------------------------------------------------
// --SECTION-- typedefs
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Rest
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief typedef for list contents
////////////////////////////////////////////////////////////////////////////////
typedef std::map<Endpoint*, bool> ListType;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
@ -93,25 +74,6 @@ namespace triagens {
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Rest
/// @{
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
static const string getKey (const Endpoint::ProtocolType protocol,
const Endpoint::EncryptionType encryption) {
return string(getProtocolName(protocol) + " " + getEncryptionName(encryption));
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Rest
/// @{
@ -120,60 +82,56 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return a protocol name
/// @brief add a new endpoint
////////////////////////////////////////////////////////////////////////////////
static const string getProtocolName (const Endpoint::ProtocolType protocol) {
switch (protocol) {
case Endpoint::PROTOCOL_HTTP:
return "http";
default:
return "unknown";
}
}
bool add (const std::string&,
const std::vector<std::string>&,
int,
Endpoint** = 0);
////////////////////////////////////////////////////////////////////////////////
/// @brief return a encryption name
/// @brief remove a specific endpoint
////////////////////////////////////////////////////////////////////////////////
static const string getEncryptionName (const Endpoint::EncryptionType encryption) {
switch (encryption) {
case Endpoint::ENCRYPTION_SSL:
return "ssl-encrypted";
case Endpoint::ENCRYPTION_NONE:
default:
return "non-encrypted";
}
}
bool remove (const std::string&,
Endpoint**);
////////////////////////////////////////////////////////////////////////////////
/// @brief count the number of elements in a sub-list
/// @brief return all endpoints
////////////////////////////////////////////////////////////////////////////////
size_t count (const Endpoint::ProtocolType,
const Endpoint::EncryptionType) const;
std::map<std::string, std::vector<std::string> > getAll () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief dump all used endpoints
/// @brief return all endpoints with a certain prefix
////////////////////////////////////////////////////////////////////////////////
void dump() const ;
std::map<std::string, Endpoint*> getByPrefix (const std::string&) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return all endpoints for a specific protocol
/// @brief return all endpoints with a certain encryption type
////////////////////////////////////////////////////////////////////////////////
ListType getEndpoints (const Endpoint::ProtocolType,
const Endpoint::EncryptionType) const;
std::map<std::string, Endpoint*> getByPrefix (const Endpoint::EncryptionType) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an endpoint for a specific protocol
/// @brief return if there is an endpoint with a certain encryption type
////////////////////////////////////////////////////////////////////////////////
bool has (const Endpoint::EncryptionType) const;
//////////////////////////////////////////////////////////////////////////////
/// @brief dump all endpoints used
////////////////////////////////////////////////////////////////////////////////
bool addEndpoint (const Endpoint::ProtocolType,
const Endpoint::EncryptionType,
Endpoint*,
bool);
void dump () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return an encryption name
////////////////////////////////////////////////////////////////////////////////
static string getEncryptionName (const Endpoint::EncryptionType);
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -191,10 +149,10 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief lists of endpoints
/// @brief list of endpoints
////////////////////////////////////////////////////////////////////////////////
map<string, ListType> _lists;
std::map<std::string, std::pair<Endpoint*, std::vector<std::string> > > _endpoints;
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -57,11 +57,10 @@ using namespace triagens::rest;
////////////////////////////////////////////////////////////////////////////////
EndpointUnixDomain::EndpointUnixDomain (const Endpoint::EndpointType type,
const Endpoint::ProtocolType protocol,
const std::string& specification,
int listenBacklog,
const std::string& path) :
Endpoint(type, DOMAIN_UNIX, protocol, ENCRYPTION_NONE, specification, listenBacklog),
Endpoint(type, DOMAIN_UNIX, ENCRYPTION_NONE, specification, listenBacklog),
_path(path) {
}

View File

@ -66,7 +66,6 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
EndpointUnixDomain (const EndpointType,
const ProtocolType,
const std::string&,
int,
const std::string&);

View File

@ -78,6 +78,14 @@ namespace triagens {
bool isBound () const;
////////////////////////////////////////////////////////////////////////////////
/// @brief return the endpoint
////////////////////////////////////////////////////////////////////////////////
Endpoint* endpoint () const {
return _endpoint;
}
protected:
////////////////////////////////////////////////////////////////////////////////
@ -131,6 +139,7 @@ namespace triagens {
private:
Endpoint* _endpoint;
TRI_socket_t _listenSocket;
size_t acceptFailures;