Home

Awesome

discover-tcp-transport

Stability: 1 - Experimental

NPM version

TCP transport for Discover, a distributed master-less node discovery mechanism that enables locating any entity (server, worker, drone, actor) based on node id.

Contributors

@tristanls, @mikedeboer, @skeggse

Installation

npm install discover-tcp-transport

Tests

npm test

Overview

Discover TCP transport implements the Discover transport protocol consisting of a stripped down version of the Kademlia DHT protocol, PING and FIND-NODE. The TCP transport reports a node as unreachable if a connection cannot be established with it.

NOTE: Unreachability of nodes depends on the transport. For example, other transports (like TLS transport) could use other criteria (like invalid certificate) for reporting unreachable nodes.

WARNING: Using TCP transport is meant primarily for development in a development environment. TCP transport exists because it is a low hanging fruit. It is most likely that it should be replaced with DTLS transport in production (maybe TLS if DTLS is not viable). There may also be a use-case for using UDP transport if communicating nodes are on a VPN/VPC. Only if UDP on a VPN/VPC seems not viable, should TCP transport be considered.

Documentation

TcpTransport

Public API

TcpTransport.listen(options, callback)

Creates new TCP transport and starts the server.

new TcpTransport(options)

Creates a new TCP transport.

tcpTransport.close(callback)

Stops the server from listening to requests from other nodes.

tcpTransport.findNode(contact, nodeId, sender)

Issues a FIND-NODE request to the contact. In other words, sends FIND-NODE request to the contact at contact.host and contact.port using TCP. The transport will emit node event when a response is processed (or times out).

tcpTransport.listen(callback)

Starts the server to listen to requests from other nodes.

tcpTransport.ping(contact, sender)

Issues a PING request to the contact. In other words, pings the contact at the contact.transport.host and contact.transport.port using TCP. The transport will emit unreachable event if the contact is deemed to be unreachable, or reached event otherwise.

tcpTransport.rpc(contact, payload, callback)

CAUTION: reserved for internal use

An internal common implementation for tcpTransport.findNode(...) and tcpTransport.ping(...).

tcpTransport.setTransportInfo(contact)

Sets contact.transport to TCP transport configured values. For example:

var contact = {id: 'id', data: 'data'};
var tcpTransport = new TcpTransport({host: 'foo.com', port: 8888});
contact = tcpTransport.setTransportInfo(contact);
assert.ok(contact.transport.host === 'foo.com'); // true
assert.ok(contact.transport.port === 8888); // true

Event: findNode

Emitted when another node issues a FIND-NODE request to this node.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('findNode', function (nodeId, sender, callback) {
    // ... find closestNodes to the desired nodeId
    return callback(null, closestNodes);
});

In the above example closestNodes is an Array of contacts that are closest known to the desired nodeId.

If the node handling the request itself contains the nodeId, then it sends only itself back.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('findNode', function (nodeId, sender, callback) {
    // ... this node knows the node with nodeId or is itself node with nodeId
    return callback(null, nodeWithNodeId);
});

In the above example, nodeWithNodeId is not an array, but an individual contact representing the answer to findNode query.

Event: node

If error occurs, the transport encountered an error when issuing the findNode request to the contact. contact and nodeId will also be provided in case of an error. response is undefined if an error occurs.

response will be an Array if the contact does not contain the nodeId requested. In this case response will be a contact list of nodes closer to the nodeId that the queried node is aware of. The usual step is to next query the returned contacts with the FIND-NODE request.

response will be an Object if the contact contains the nodeId. In other words, the node has been found.

Event: ping

Emitted when another node issues a PING request to this node.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('ping', function (nodeId, sender, callback) {
    // ... verify that we have the exact node specified by nodeId
    return callback(null, contact);
});

In the above example contact is an Object representing the answer to ping query.

If the exact node specified by nodeId does not exist, an error shall be returned as shown below:

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('ping', function (nodeId, sender, callback) {
    // ...we don't have the nodeId specified
    return callback(true);
});

Event: reached

Emitted when a previously pinged contact is deemed reachable by the transport.

Event: unreachable

Emitted when a previously pinged contact is deemed unreachable by the transport.

Wire Protocol

Wire protocol for TCP transport is simple one-line \r\n terminated ASCII.

FIND-NODE

{"request":{"findNode":"Zm9v"},"sender":{"id":"YmF6","data":"some data","transport":{"host":"127.0.0.1","port":6742}}}\r\n

FIND-NODE request consists of a JSON object with base64 encoded node id and a sender followed by \r\n as shown above.

Object Response

{"id":"Zm9v","data":"some data","transport":{"host":"127.0.0.1","port":6742}}\r\n

An Object response is JSON representation of the contact followed by \r\n.

Array Response

[{"id":"YmFy","data":"some data","transport":{"host":"192.168.0.1","port":6742}},{"id":"YmF6","data":"some data","transport":{"host":"192.168.0.2","port":6742}}]\r\n

An Array response is JSON representation of an array of closest contacts followed by \r\n.

PING

{"request":{"ping":"Zm9v"},"sender":{"id":"YmF6","data":"some data","transport":{"host":"127.0.0.1","port":6742}}}\r\n

PING request consists of a JSON object with base64 encoded node id and a sender followed by \r\n as shown above.

Object Response

{"id":"Zm9v","data":"some data","transport":{"host":"127.0.0.1","port":6742}}\r\n

An Object response is JSON representation of the pinged contact followed by \r\n.

Failure Responses

Closing the connection without an object response or inability to connect in the first place indicates a PING failure.