summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrant Limberg <glimberg@gmail.com>2015-07-21 17:53:39 -0700
committerGrant Limberg <glimberg@gmail.com>2015-07-21 17:53:39 -0700
commitbc0954381ccdca065987512a45d5dd6ace6cca9d (patch)
tree4ff1c5fd46a89ae78dcb29f310cee14fb04b4a97
parentd05e8a9772341f36fd767e862193ee95d14ea790 (diff)
parent7c761dea722621a929d42bdc79e2312d1b30a1e1 (diff)
downloadinfinitytier-bc0954381ccdca065987512a45d5dd6ace6cca9d.tar.gz
infinitytier-bc0954381ccdca065987512a45d5dd6ace6cca9d.zip
Merge branch 'adamierymenko-dev' into android-jni
-rw-r--r--controller/SqliteNetworkController.cpp272
-rw-r--r--controller/SqliteNetworkController.hpp1
-rw-r--r--service/README.md1
3 files changed, 145 insertions, 129 deletions
diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp
index 19e3d920..700b3561 100644
--- a/controller/SqliteNetworkController.cpp
+++ b/controller/SqliteNetworkController.cpp
@@ -175,7 +175,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignmentPool WHERE networkId = ?",-1,&_sDeleteIpAssignmentPoolsForNetwork,(const char **)0) != SQLITE_OK)
/* IpAssignment */
- ||(sqlite3_prepare_v2(_db,"SELECT \"type\",ip,ipNetmaskBits FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND ipVersion = ?",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT \"type\",ip,ipNetmaskBits FROM IpAssignment WHERE networkId = ? AND (nodeId = ? OR nodeId IS NULL) AND ipVersion = ?",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND \"type\" = ? ORDER BY ip ASC",-1,&_sGetIpAssignmentsForNode2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId IS NULL AND \"type\" = ?",-1,&_sGetLocalRoutes,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT 1 FROM IpAssignment WHERE networkId = ? AND ip = ? AND ipVersion = ? AND \"type\" = ?",-1,&_sCheckIfIpIsAllocated,(const char **)0) != SQLITE_OK)
@@ -193,7 +193,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"SELECT m.authorized,m.activeBridge,m.memberRevision,n.identity FROM Member AS m JOIN Node AS n ON n.id = m.nodeId WHERE m.networkId = ? AND m.nodeId = ?",-1,&_sGetMember2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO Member (networkId,nodeId,authorized,activeBridge,memberRevision) VALUES (?,?,?,0,(SELECT memberRevisionCounter FROM Network WHERE id = ?))",-1,&_sCreateMember,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT nodeId FROM Member WHERE networkId = ? AND activeBridge > 0 AND authorized > 0",-1,&_sGetActiveBridges,(const char **)0) != SQLITE_OK)
- ||(sqlite3_prepare_v2(_db,"SELECT m.nodeId FROM Member AS m WHERE m.networkId = ? ORDER BY m.nodeId ASC",-1,&_sListNetworkMembers,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT m.nodeId,m.memberRevision FROM Member AS m WHERE m.networkId = ? ORDER BY m.nodeId ASC",-1,&_sListNetworkMembers,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Member SET authorized = ?,memberRevision = (SELECT memberRevisionCounter FROM Network WHERE id = ?) WHERE rowid = ?",-1,&_sUpdateMemberAuthorized,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Member SET activeBridge = ?,memberRevision = (SELECT memberRevisionCounter FROM Network WHERE id = ?) WHERE rowid = ?",-1,&_sUpdateMemberActiveBridge,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK)
@@ -205,7 +205,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
/* Config */
||(sqlite3_prepare_v2(_db,"SELECT \"v\" FROM \"Config\" WHERE \"k\" = ?",-1,&_sGetConfig,(const char **)0) != SQLITE_OK)
- ||(sqlite3_prepare_v2(_db,"INSERT INTO \"Config\" (\"k\",\"v\") VALUES (?,?)",-1,&_sSetConfig,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO \"Config\" (\"k\",\"v\") VALUES (?,?)",-1,&_sSetConfig,(const char **)0) != SQLITE_OK)
) {
//printf("!!! %s\n",sqlite3_errmsg(_db));
@@ -221,16 +221,19 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
if (sqlite3_step(_sGetConfig) != SQLITE_ROW) {
unsigned char sr[32];
Utils::getSecureRandom(sr,32);
- char instanceId[32];
for(unsigned int i=0;i<32;++i)
- instanceId[i] = "0123456789abcdef"[(unsigned int)sr[i] & 0xf];
+ _instanceId.push_back("0123456789abcdef"[(unsigned int)sr[i] & 0xf]);
+
sqlite3_reset(_sSetConfig);
sqlite3_bind_text(_sSetConfig,1,"instanceId",10,SQLITE_STATIC);
- sqlite3_bind_text(_sSetConfig,2,instanceId,32,SQLITE_STATIC);
- if (sqlite3_step(_sSetConfig) != SQLITE_DONE) {
- sqlite3_close(_db);
+ sqlite3_bind_text(_sSetConfig,2,_instanceId.c_str(),-1,SQLITE_STATIC);
+ if (sqlite3_step(_sSetConfig) != SQLITE_DONE)
throw std::runtime_error("SqliteNetworkController unable to read or initialize instanceId");
- }
+ } else {
+ const char *iid = reinterpret_cast<const char *>(sqlite3_column_text(_sGetConfig,0));
+ if (!iid)
+ throw std::runtime_error("SqliteNetworkController unable to read instanceId (it's NULL)");
+ _instanceId = iid;
}
}
@@ -326,7 +329,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
sqlite3_bind_text(_sCreateNode,1,member.nodeId,10,SQLITE_STATIC);
sqlite3_bind_text(_sCreateNode,2,idstr.c_str(),-1,SQLITE_STATIC);
if (sqlite3_step(_sCreateNode) != SQLITE_DONE) {
- netconf["error"] = "unable to create new node record";
+ netconf["error"] = "unable to create new Node record";
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
}
}
@@ -346,7 +349,9 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
network.creationTime = (uint64_t)sqlite3_column_int64(_sGetNetworkById,7);
network.revision = (uint64_t)sqlite3_column_int64(_sGetNetworkById,8);
network.memberRevisionCounter = (uint64_t)sqlite3_column_int64(_sGetNetworkById,9);
- } else return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
+ } else {
+ return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
+ }
// Fetch Member record
@@ -1273,109 +1278,136 @@ unsigned int SqliteNetworkController::_doCPGet(
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
if (path.size() >= 3) {
- if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
- uint64_t address = Utils::hexStrToU64(path[3].c_str());
- char addrs[24];
- Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
-
- sqlite3_reset(_sGetMember2);
- sqlite3_bind_text(_sGetMember2,1,nwids,16,SQLITE_STATIC);
- sqlite3_bind_text(_sGetMember2,2,addrs,10,SQLITE_STATIC);
- if (sqlite3_step(_sGetMember2) == SQLITE_ROW) {
- Utils::snprintf(json,sizeof(json),
- "{\n"
- "\t\"nwid\": \"%s\",\n"
- "\t\"address\": \"%s\",\n"
- "\t\"authorized\": %s,\n"
- "\t\"activeBridge\": %s,\n"
- "\t\"memberRevision\": %llu,\n"
- "\t\"identity\": \"%s\",\n"
- "\t\"ipAssignments\": [",
- nwids,
- addrs,
- (sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false",
- (sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false",
- (unsigned long long)sqlite3_column_int64(_sGetMember2,2),
- _jsonEscape((const char *)sqlite3_column_text(_sGetMember2,3)).c_str());
- responseBody = json;
-
- sqlite3_reset(_sGetIpAssignmentsForNode2);
- sqlite3_bind_text(_sGetIpAssignmentsForNode2,1,nwids,16,SQLITE_STATIC);
- sqlite3_bind_text(_sGetIpAssignmentsForNode2,2,addrs,10,SQLITE_STATIC);
- sqlite3_bind_int(_sGetIpAssignmentsForNode2,3,(int)ZT_IP_ASSIGNMENT_TYPE_ADDRESS);
- bool firstIp = true;
- while (sqlite3_step(_sGetIpAssignmentsForNode2) == SQLITE_ROW) {
- int ipversion = sqlite3_column_int(_sGetIpAssignmentsForNode2,2);
- char ipBlob[16];
- memcpy(ipBlob,(const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),16);
- InetAddress ip(
- (const void *)(ipversion == 6 ? ipBlob : &ipBlob[12]),
- (ipversion == 6 ? 16 : 4),
- (unsigned int)sqlite3_column_int(_sGetIpAssignmentsForNode2,1)
- );
- responseBody.append(firstIp ? "\"" : ",\"");
- firstIp = false;
- responseBody.append(_jsonEscape(ip.toString()));
- responseBody.push_back('"');
- }
+ // /network/<nwid>/...
+
+ if (path[2] == "member") {
+
+ if (path.size() >= 4) {
+ // Get specific member info
+
+ uint64_t address = Utils::hexStrToU64(path[3].c_str());
+ char addrs[24];
+ Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
+
+ sqlite3_reset(_sGetMember2);
+ sqlite3_bind_text(_sGetMember2,1,nwids,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetMember2,2,addrs,10,SQLITE_STATIC);
+ if (sqlite3_step(_sGetMember2) == SQLITE_ROW) {
+ Utils::snprintf(json,sizeof(json),
+ "{\n"
+ "\t\"nwid\": \"%s\",\n"
+ "\t\"address\": \"%s\",\n"
+ "\t\"controllerInstanceId\": \"%s\",\n"
+ "\t\"authorized\": %s,\n"
+ "\t\"activeBridge\": %s,\n"
+ "\t\"memberRevision\": %llu,\n"
+ "\t\"identity\": \"%s\",\n"
+ "\t\"ipAssignments\": [",
+ nwids,
+ addrs,
+ _instanceId.c_str(),
+ (sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false",
+ (sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false",
+ (unsigned long long)sqlite3_column_int64(_sGetMember2,2),
+ _jsonEscape((const char *)sqlite3_column_text(_sGetMember2,3)).c_str());
+ responseBody = json;
+
+ sqlite3_reset(_sGetIpAssignmentsForNode2);
+ sqlite3_bind_text(_sGetIpAssignmentsForNode2,1,nwids,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetIpAssignmentsForNode2,2,addrs,10,SQLITE_STATIC);
+ sqlite3_bind_int(_sGetIpAssignmentsForNode2,3,(int)ZT_IP_ASSIGNMENT_TYPE_ADDRESS);
+ bool firstIp = true;
+ while (sqlite3_step(_sGetIpAssignmentsForNode2) == SQLITE_ROW) {
+ int ipversion = sqlite3_column_int(_sGetIpAssignmentsForNode2,2);
+ char ipBlob[16];
+ memcpy(ipBlob,(const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),16);
+ InetAddress ip(
+ (const void *)(ipversion == 6 ? ipBlob : &ipBlob[12]),
+ (ipversion == 6 ? 16 : 4),
+ (unsigned int)sqlite3_column_int(_sGetIpAssignmentsForNode2,1)
+ );
+ responseBody.append(firstIp ? "\"" : ",\"");
+ firstIp = false;
+ responseBody.append(_jsonEscape(ip.toString()));
+ responseBody.push_back('"');
+ }
- responseBody.append("]");
-
- /* It's possible to get the actual netconf dictionary by including these
- * three URL arguments. The member identity must be the string
- * serialized identity of this member, and the signing identity must be
- * the full secret identity of this network controller. The have revision
- * is optional but would designate the revision our hypothetical client
- * already has.
- *
- * This is primarily for testing and is not used in production. It makes
- * it easy to test the entire network controller via its JSON API.
- *
- * If these arguments are included, three more object fields are returned:
- * 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all
- * string fields and contain the actual netconf dictionary, the query
- * result code, and any verbose message e.g. an error description. */
- std::map<std::string,std::string>::const_iterator memids(urlArgs.find("memberIdentity"));
- std::map<std::string,std::string>::const_iterator sigids(urlArgs.find("signingIdentity"));
- std::map<std::string,std::string>::const_iterator hrs(urlArgs.find("haveRevision"));
- if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) {
- Dictionary netconf;
- Identity memid,sigid;
- try {
- if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) {
- uint64_t hr = 0;
- if (hrs != urlArgs.end())
- hr = Utils::strToU64(hrs->second.c_str());
- const char *result = "";
- switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) {
- case NetworkController::NETCONF_QUERY_OK: result = "OK"; break;
- case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break;
- case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break;
- case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break;
- case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break;
- default: result = "(unrecognized result code)"; break;
+ responseBody.append("]");
+
+ /* It's possible to get the actual netconf dictionary by including these
+ * three URL arguments. The member identity must be the string
+ * serialized identity of this member, and the signing identity must be
+ * the full secret identity of this network controller. The have revision
+ * is optional but would designate the revision our hypothetical client
+ * already has.
+ *
+ * This is primarily for testing and is not used in production. It makes
+ * it easy to test the entire network controller via its JSON API.
+ *
+ * If these arguments are included, three more object fields are returned:
+ * 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all
+ * string fields and contain the actual netconf dictionary, the query
+ * result code, and any verbose message e.g. an error description. */
+ std::map<std::string,std::string>::const_iterator memids(urlArgs.find("memberIdentity"));
+ std::map<std::string,std::string>::const_iterator sigids(urlArgs.find("signingIdentity"));
+ std::map<std::string,std::string>::const_iterator hrs(urlArgs.find("haveRevision"));
+ if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) {
+ Dictionary netconf;
+ Identity memid,sigid;
+ try {
+ if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) {
+ uint64_t hr = 0;
+ if (hrs != urlArgs.end())
+ hr = Utils::strToU64(hrs->second.c_str());
+ const char *result = "";
+ switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) {
+ case NetworkController::NETCONF_QUERY_OK: result = "OK"; break;
+ case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break;
+ case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break;
+ case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break;
+ case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break;
+ default: result = "(unrecognized result code)"; break;
+ }
+ responseBody.append(",\n\t\"netconf\": \"");
+ responseBody.append(_jsonEscape(netconf.toString().c_str()));
+ responseBody.append("\",\n\t\"netconfResult\": \"");
+ responseBody.append(result);
+ responseBody.append("\",\n\t\"netconfResultMessage\": \"");
+ responseBody.append(_jsonEscape(netconf["error"].c_str()));
+ responseBody.append("\"");
+ } else {
+ responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"invalid member or signing identity\"");
}
- responseBody.append(",\n\t\"netconf\": \"");
- responseBody.append(_jsonEscape(netconf.toString().c_str()));
- responseBody.append("\",\n\t\"netconfResult\": \"");
- responseBody.append(result);
- responseBody.append("\",\n\t\"netconfResultMessage\": \"");
- responseBody.append(_jsonEscape(netconf["error"].c_str()));
- responseBody.append("\"");
- } else {
- responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"invalid member or signing identity\"");
+ } catch ( ... ) {
+ responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"unexpected exception\"");
}
- } catch ( ... ) {
- responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"unexpected exception\"");
}
- }
- responseBody.append("\n}\n");
+ responseBody.append("\n}\n");
+
+ responseContentType = "application/json";
+ return 200;
+ } // else 404
+
+ } else {
+ // List members
+ sqlite3_reset(_sListNetworkMembers);
+ sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
+ while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
+ responseBody.append((responseBody.length() > 0) ? ",\"" : "{\"");
+ responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
+ responseBody.append("\":");
+ responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,1));
+ }
+ responseBody.push_back('}');
responseContentType = "application/json";
return 200;
- } // else 404
+
+ }
+
} // else 404
+
} else {
// get network info
sqlite3_reset(_sGetNetworkById);
@@ -1384,6 +1416,7 @@ unsigned int SqliteNetworkController::_doCPGet(
Utils::snprintf(json,sizeof(json),
"{\n"
"\t\"nwid\": \"%s\",\n"
+ "\t\"controllerInstanceId\": \"%s\",\n"
"\t\"name\": \"%s\",\n"
"\t\"private\": %s,\n"
"\t\"enableBroadcast\": %s,\n"
@@ -1394,8 +1427,9 @@ unsigned int SqliteNetworkController::_doCPGet(
"\t\"creationTime\": %llu,\n"
"\t\"revision\": %llu,\n"
"\t\"memberRevisionCounter\": %llu,\n"
- "\t\"members\": [",
+ "\t\"relays\": [",
nwids,
+ _instanceId.c_str(),
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(),
(sqlite3_column_int(_sGetNetworkById,1) > 0) ? "true" : "false",
(sqlite3_column_int(_sGetNetworkById,2) > 0) ? "true" : "false",
@@ -1408,20 +1442,6 @@ unsigned int SqliteNetworkController::_doCPGet(
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,9));
responseBody = json;
- sqlite3_reset(_sListNetworkMembers);
- sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
- bool firstMember = true;
- while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
- if (!firstMember)
- responseBody.push_back(',');
- responseBody.push_back('"');
- responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
- responseBody.push_back('"');
- firstMember = false;
- }
-
- responseBody.append("],\n\t\"relays\": [");
-
sqlite3_reset(_sGetRelays);
sqlite3_bind_text(_sGetRelays,1,nwids,16,SQLITE_STATIC);
bool firstRelay = true;
@@ -1657,14 +1677,10 @@ unsigned int SqliteNetworkController::_doCPGet(
} else {
// GET /controller returns status and API version if controller is supported
- sqlite3_reset(_sGetConfig);
- sqlite3_bind_text(_sGetConfig,1,"instanceId",10,SQLITE_STATIC);
- if (sqlite3_step(_sGetConfig) == SQLITE_ROW) {
- Utils::snprintf(json,sizeof(json),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"instanceId\": \"%s\"\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),(const char *)sqlite3_column_text(_sGetConfig,0));
- responseBody = json;
- responseContentType = "applicaiton/json";
- return 200;
- } else return 500;
+ Utils::snprintf(json,sizeof(json),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"instanceId\": \"%s\"\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),_instanceId.c_str());
+ responseBody = json;
+ responseContentType = "applicaiton/json";
+ return 200;
}
return 404;
diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp
index 95905bd1..8b39f7d9 100644
--- a/controller/SqliteNetworkController.hpp
+++ b/controller/SqliteNetworkController.hpp
@@ -96,6 +96,7 @@ private:
std::string &responseContentType);
std::string _dbPath;
+ std::string _instanceId;
sqlite3 *_db;
sqlite3_stmt *_sGetNetworkById;
diff --git a/service/README.md b/service/README.md
index d2dc6e91..668aab05 100644
--- a/service/README.md
+++ b/service/README.md
@@ -173,7 +173,6 @@ To create a new network with a random last six digits safely and atomically, you
<tr><td>creationTime</td><td>integer</td><td>Time network was created in ms since epoch</td><td>no</td></tr>
<tr><td>revision</td><td>integer</td><td>Network config revision number</td><td>no</td></tr>
<tr><td>memberRevisionCounter</td><td>integer</td><td>Current value of network revision counter (incremented after every member add or revision)</td><td>no</td></tr>
-<tr><td>members</td><td>[string]</td><td>Array of ZeroTier addresses of network members</td><td>no</td></tr>
<tr><td>relays</td><td>[object]</td><td>Array of network-specific relay nodes (see below)</td><td>yes</td></tr>
<tr><td>ipLocalRoutes</td><td>[string]</td><td>Array of IP network/netmask entries corresponding to networks routed directly via this interface (e.g. 10.0.0.0/8 to route 10.0.0.0 via this interface)</td></tr>
<tr><td>ipAssignmentPools</td><td>[object]</td><td>Array of IP auto-assignment pools for 'zt' assignment mode</td><td>yes</td></tr>