summaryrefslogtreecommitdiff
path: root/tests/http/agent.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/http/agent.js')
-rw-r--r--tests/http/agent.js196
1 files changed, 196 insertions, 0 deletions
diff --git a/tests/http/agent.js b/tests/http/agent.js
new file mode 100644
index 00000000..9ab2e019
--- /dev/null
+++ b/tests/http/agent.js
@@ -0,0 +1,196 @@
+// ZeroTier distributed HTTP test agent
+
+// ---------------------------------------------------------------------------
+// Customizable parameters:
+
+// Time between startup and first test attempt
+var TEST_STARTUP_LAG = 10000;
+
+// Maximum interval between test attempts (actual timing is random % this)
+var TEST_INTERVAL_MAX = (60000 * 10);
+
+// Test timeout in ms
+var TEST_TIMEOUT = 30000;
+
+// Where should I get other agents' IDs and POST results?
+var SERVER_HOST = '52.26.196.147';
+var SERVER_PORT = 18080;
+
+// Which port do agents use to serve up test data to each other?
+var AGENT_PORT = 18888;
+
+// Payload size in bytes
+var PAYLOAD_SIZE = 5000;
+
+// ---------------------------------------------------------------------------
+
+var ipaddr = require('ipaddr.js');
+var os = require('os');
+var http = require('http');
+var async = require('async');
+
+var express = require('express');
+var app = express();
+
+// Find our ZeroTier-assigned RFC4193 IPv6 address
+var thisAgentId = null;
+var interfaces = os.networkInterfaces();
+if (!interfaces) {
+ console.error('FATAL: os.networkInterfaces() failed.');
+ process.exit(1);
+}
+for(var ifname in interfaces) {
+ var ifaddrs = interfaces[ifname];
+ if (Array.isArray(ifaddrs)) {
+ for(var i=0;i<ifaddrs.length;++i) {
+ if (ifaddrs[i].family == 'IPv6') {
+ try {
+ var ipbytes = ipaddr.parse(ifaddrs[i].address).toByteArray();
+ if ((ipbytes.length === 16)&&(ipbytes[0] == 0xfd)&&(ipbytes[9] == 0x99)&&(ipbytes[10] == 0x93)) {
+ thisAgentId = '';
+ for(var j=0;j<16;++j) {
+ var tmp = ipbytes[j].toString(16);
+ if (tmp.length === 1)
+ thisAgentId += '0';
+ thisAgentId += tmp;
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+ }
+}
+if (thisAgentId === null) {
+ console.error('FATAL: no ZeroTier-assigned RFC4193 IPv6 addresses found on any local interface!');
+ process.exit(1);
+}
+
+//console.log(thisAgentId);
+
+// Create a random (and therefore not very compressable) payload
+var payload = new Buffer(PAYLOAD_SIZE);
+for(var xx=0;xx<PAYLOAD_SIZE;++xx) {
+ payload.writeUInt8(Math.round(Math.random() * 255.0),xx);
+}
+
+function agentIdToIp(agentId)
+{
+ var ip = '';
+ ip += agentId.substr(0,4);
+ ip += ':';
+ ip += agentId.substr(4,4);
+ ip += ':';
+ ip += agentId.substr(8,4);
+ ip += ':';
+ ip += agentId.substr(12,4);
+ ip += ':';
+ ip += agentId.substr(16,4);
+ ip += ':';
+ ip += agentId.substr(20,4);
+ ip += ':';
+ ip += agentId.substr(24,4);
+ ip += ':';
+ ip += agentId.substr(28,4);
+ return ip;
+};
+
+var lastTestResult = null;
+var allOtherAgents = {};
+
+function doTest()
+{
+ var submit = http.request({
+ host: SERVER_HOST,
+ port: SERVER_PORT,
+ path: '/'+thisAgentId,
+ method: 'POST'
+ },function(res) {
+ var body = '';
+ res.on('data',function(chunk) { body += chunk.toString(); });
+ res.on('end',function() {
+
+ if (body) {
+ try {
+ var peers = JSON.parse(body);
+ if (Array.isArray(peers)) {
+ for(var xx=0;xx<peers.length;++xx)
+ allOtherAgents[peers[xx]] = true;
+ }
+ } catch (e) {}
+ }
+
+ var agents = Object.keys(allOtherAgents);
+ if (agents.length > 1) {
+
+ var target = agents[Math.floor(Math.random() * agents.length)];
+ while (target === thisAgentId)
+ target = agents[Math.floor(Math.random() * agents.length)];
+
+ var testRequest = null;
+ var timeoutId = null;
+ timeoutId = setTimeout(function() {
+ if (testRequest !== null)
+ testRequest.abort();
+ timeoutId = null;
+ },TEST_TIMEOUT);
+ var startTime = Date.now();
+
+ testRequest = http.get({
+ host: agentIdToIp(target),
+ port: AGENT_PORT,
+ path: '/'
+ },function(res) {
+ var bytes = 0;
+ res.on('data',function(chunk) { bytes += chunk.length; });
+ res.on('end',function() {
+ lastTestResult = {
+ source: thisAgentId,
+ target: target,
+ time: (Date.now() - startTime),
+ bytes: bytes,
+ timedOut: (timeoutId === null),
+ error: null
+ };
+ if (timeoutId !== null)
+ clearTimeout(timeoutId);
+ return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1);
+ });
+ }).on('error',function(e) {
+ lastTestResult = {
+ source: thisAgentId,
+ target: target,
+ time: (Date.now() - startTime),
+ bytes: 0,
+ timedOut: (timeoutId === null),
+ error: e.toString()
+ };
+ if (timeoutId !== null)
+ clearTimeout(timeoutId);
+ return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1);
+ });
+
+ } else {
+ return setTimeout(doTest,1000);
+ }
+
+ });
+ }).on('error',function(e) {
+ console.log('POST failed: '+e.toString());
+ return setTimeout(doTest,1000);
+ });
+ if (lastTestResult !== null) {
+ submit.write(JSON.stringify(lastTestResult));
+ lastTestResult = null;
+ }
+ submit.end();
+};
+
+// Agents just serve up a test payload
+app.get('/',function(req,res) { return res.status(200).send(payload); });
+
+var expressServer = app.listen(AGENT_PORT,function () {
+ // Start timeout-based loop
+ setTimeout(doTest(),TEST_STARTUP_LAG);
+});