getLinks.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env node
  2. /* vim: set expandtab ts=4 sw=4: */
  3. /*
  4. * You may redistribute this program and/or modify it under the terms of
  5. * the GNU General Public License as published by the Free Software Foundation,
  6. * either version 3 of the License, or (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. var Cjdns = require('../cjdnsadmin/cjdnsadmin');
  17. var nThen = require('../cjdnsadmin/nthen');
  18. var PublicToIp6 = require('./lib/publicToIp6');
  19. var NodeStore_nodeForAddr = function(cjdns, state, addr, callback) {
  20. if (typeof(state['NodeStore_nodeForAddr' + addr]) !== 'undefined') {
  21. callback(state['NodeStore_nodeForAddr' + addr]);
  22. } else {
  23. //console.log('NodeStore_nodeForAddr(' + addr + ');');
  24. cjdns.NodeStore_nodeForAddr(addr, function (err, ret) {
  25. if (err) { throw err; }
  26. state['NodeStore_nodeForAddr' + addr] = ret;
  27. callback(ret);
  28. });
  29. }
  30. };
  31. var getNode = function (cjdns, next, output, state, parentPath, ipsByReach, nodes, callback) {
  32. if (next.parent === next.child) { process.nextTick(callback); return; }
  33. var getNodeRet;
  34. var path;
  35. nThen(function (waitFor) {
  36. NodeStore_nodeForAddr(cjdns, state, next.child, waitFor(function (ret) {
  37. //console.log('cjdns.NodeStore_nodeForAddr(' + next.child + '); --> ' + JSON.stringify(ret, null, ' '));
  38. getNodeRet = ret;
  39. }));
  40. }).nThen(function (waitFor) {
  41. if (!parentPath) {
  42. return;
  43. }
  44. cjdns.NodeStore_getRouteLabel(parentPath, next.cannonicalLabel, waitFor(function (err, ret) {
  45. if (err) { throw err; }
  46. if (ret.error !== 'none') {
  47. throw new Error('cjdns.NodeStore_getRouteLabel(' + parentPath + ', ' + next.cannonicalLabel +
  48. '); --> ' + JSON.stringify(ret, null, ' '));
  49. }
  50. //console.log('cjdns.NodeStore_getRouteLabel(' + parentPath + ', ' + next.pathParentToChild + ') --> ' + ret.result);
  51. if (ret.result !== 'ffff.ffff.ffff.ffff') {
  52. path = ret.result;
  53. }
  54. }));
  55. }).nThen(function (waitFor) {
  56. //console.log(spaces + next.child + ' ' + next.cannonicalLabel + " -> " + path);
  57. // if next.parent skips the bootstrap route
  58. if (next.parent) {
  59. var out = {};
  60. output.push(out);
  61. output = out;
  62. }
  63. if (output.peers) { /* sanity check */ throw new Error(); }
  64. output.addr = next.child;
  65. output.cannonicalLabel = next.cannonicalLabel;
  66. output.isOneHop = next.isOneHop;
  67. output.fullPath = path;
  68. output.peers = [];
  69. if (!path) { return; }
  70. var links = [];
  71. nThen(function (waitFor) {
  72. for (var i = 0; i < getNodeRet.result.linkCount; i++) {
  73. cjdns.NodeStore_getLink(next.child, i, waitFor(function (err, ret) {
  74. if (err) { throw err; }
  75. links.push(ret);
  76. }));
  77. }
  78. }).nThen(function (waitFor) {
  79. if (nodes.indexOf(next.child) > -1) { process.nextTick(callback); return; }
  80. nodes.push(next.child);
  81. //console.log(JSON.stringify(links, null, ' '));
  82. links.sort(function (a,b) {
  83. if (a.isOneHop !== b.isOneHop) { return a.isOneHop ? -1 : 1; }
  84. return (ipsByReach.indexOf(a.result.child) < ipsByReach.indexOf(b.result.child)) ?
  85. -1 : 1;
  86. });
  87. //console.log(JSON.stringify(links, null, ' '));
  88. //console.log(JSON.stringify(ipsByReach, null, ' '));
  89. for (var i = 0; i < links.length; i++) {
  90. getNode(cjdns, links[i].result, output.peers, state, path, ipsByReach, nodes, waitFor());
  91. }
  92. }).nThen(waitFor());
  93. }).nThen(function (waitFor) {
  94. callback();
  95. });
  96. };
  97. var dumpOldTable = function (cjdns, callback) {
  98. var output = [];
  99. var again = function (i) {
  100. cjdns.NodeStore_dumpTable(i, function (err, table) {
  101. if (err) { throw err; }
  102. var j;
  103. for (j = 0; j < table.routingTable.length; j++) {
  104. var r = table.routingTable[j];
  105. output.push(r);
  106. }
  107. if (j) {
  108. again(i+1);
  109. } else {
  110. callback(output);
  111. }
  112. });
  113. };
  114. again(0);
  115. };
  116. var ipsByReachDesc = function (cjdns, callback) {
  117. dumpOldTable(cjdns, function (oldTable) {
  118. oldTable.sort(function (a, b) {
  119. if (a.ip !== b.ip) { return (a.ip > b.ip) ? 1 : -1; }
  120. if (a.link !== b.link) { return (Number(a.link) < Number(b.link)) ? 1 : -1; }
  121. if (a.path !== b.path) { return (a.path > b.path) ? 1 : -1; }
  122. throw new Error("dupe entry");
  123. });
  124. var bestReaches = [];
  125. var last;
  126. for (var i = 0; i < oldTable.length; i++) {
  127. var r = oldTable[i];
  128. if (last !== r.ip) {
  129. bestReaches.push({ip:r.ip, link:r.link});
  130. last = r.ip;
  131. }
  132. }
  133. bestReaches.sort(function (a, b) { return (a.link > b.link) ? 1 : -1; });
  134. var out = [];
  135. for (var i = 0; i < bestReaches.length; i++) {
  136. out.push(bestReaches[i].ip);
  137. }
  138. callback(out);
  139. //bestReaches.forEach(function (node) { console.log(node.ip + ' ' + node.link); });
  140. });
  141. };
  142. var getTree = function (cjdns, callback) {
  143. ipsByReachDesc(cjdns, function (ipsByReach) {
  144. cjdns.NodeStore_nodeForAddr(undefined, function (err, ret) {
  145. if (err) { throw err; }
  146. var myIp6 = PublicToIp6.convert(ret['result']['key']);
  147. var output = {};
  148. var selfRoute = '0000.0000.0000.0001';
  149. var initialNode = { child: myIp6, cannonicalLabel: selfRoute };
  150. getNode(cjdns, initialNode, output, {}, selfRoute, ipsByReach, [], function () {
  151. callback(output);
  152. });
  153. });
  154. });
  155. };
  156. var printTree = function (cjdns, tree, callback) {
  157. var pt = function (tree, spaces, callback) {
  158. var nt = nThen(function (waitFor) {
  159. process.stdout.write(spaces + tree.addr + ' ' + tree.cannonicalLabel + ' --> ' + tree.fullPath);
  160. if (tree.fullPath === '0000.0000.0000.0001') { return; }
  161. cjdns.RouterModule_pingNode(tree.fullPath, waitFor(function (err, ret) {
  162. if (err) { throw err; }
  163. var resp = (ret.result !== 'pong') ? "[" + ret.error + "]" : (ret.ms + 'ms.');
  164. if (resp == '[could not find node to ping]') { resp = '[notfound]'; }
  165. process.stdout.write(' rp:' + resp);
  166. }));
  167. }).nThen(function (waitFor) {
  168. cjdns.SwitchPinger_ping(tree.fullPath, waitFor(function (err, ret) {
  169. if (err) { throw err; }
  170. var resp = (ret.result !== 'pong') ? ("["+ret.result+"]") : (ret.ms + 'ms.');
  171. process.stdout.write(' sp:' + resp);
  172. }));
  173. }).nThen(function (waitFor) {
  174. process.stdout.write(((tree.isOneHop === '1') ? ' oh' : '') + '\n');
  175. }).nThen;
  176. tree.peers.forEach(function (peer) {
  177. nt = nt(function (waitFor) {
  178. pt(peer, ' ' + spaces, waitFor());
  179. }).nThen;
  180. });
  181. nt(callback);
  182. };
  183. pt(tree, '', callback);
  184. };
  185. Cjdns.connectWithAdminInfo(function (cjdns) {
  186. getTree(cjdns, function (output) {
  187. //console.log(JSON.stringify(output, null, ' '));
  188. printTree(cjdns, output, function() {
  189. cjdns.disconnect();
  190. });
  191. });
  192. });