testnet.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2011-2014 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <stdint.h>
  30. #include <string.h>
  31. #include <string>
  32. #include <map>
  33. #include <vector>
  34. #include <set>
  35. #include "node/Constants.hpp"
  36. #include "node/Node.hpp"
  37. #include "node/Utils.hpp"
  38. #include "node/Address.hpp"
  39. #include "node/Identity.hpp"
  40. #include "node/Thread.hpp"
  41. #include "node/CMWC4096.hpp"
  42. #include "node/Dictionary.hpp"
  43. #include "testnet/SimNet.hpp"
  44. #include "testnet/SimNetSocketManager.hpp"
  45. #include "testnet/TestEthernetTap.hpp"
  46. #include "testnet/TestEthernetTapFactory.hpp"
  47. #include "testnet/TestRoutingTable.hpp"
  48. #ifdef __WINDOWS__
  49. #include <windows.h>
  50. #else
  51. #include <unistd.h>
  52. #include <sys/stat.h>
  53. #endif
  54. using namespace ZeroTier;
  55. class SimNode
  56. {
  57. public:
  58. SimNode(SimNet &net,const std::string &hp,const char *rootTopology,bool issn,const InetAddress &addr) :
  59. home(hp),
  60. tapFactory(),
  61. routingTable(),
  62. socketManager(net.newEndpoint(addr)),
  63. node(home.c_str(),&tapFactory,&routingTable,socketManager,false,rootTopology),
  64. reasonForTermination(Node::NODE_RUNNING),
  65. supernode(issn)
  66. {
  67. thread = Thread::start(this);
  68. }
  69. ~SimNode()
  70. {
  71. node.terminate(Node::NODE_NORMAL_TERMINATION,"SimNode shutdown");
  72. Thread::join(thread);
  73. }
  74. void threadMain()
  75. throw()
  76. {
  77. reasonForTermination = node.run();
  78. }
  79. std::string home;
  80. TestEthernetTapFactory tapFactory;
  81. TestRoutingTable routingTable;
  82. SimNetSocketManager *socketManager;
  83. Node node;
  84. Node::ReasonForTermination reasonForTermination;
  85. bool supernode;
  86. Thread thread;
  87. };
  88. static std::string basePath;
  89. static SimNet net;
  90. static std::map< Address,SimNode * > nodes;
  91. static std::map< InetAddress,Address > usedIps;
  92. static CMWC4096 prng;
  93. static std::string rootTopology;
  94. // Converts an address into a fake IP not already claimed.
  95. // Be sure to call only once, as this claims the IP before returning it.
  96. static InetAddress inetAddressFromZeroTierAddress(const Address &addr)
  97. {
  98. uint32_t ip = (uint32_t)(addr.toInt() & 0xffffffff);
  99. for(;;) {
  100. if (((ip >> 24) & 0xff) >= 240) {
  101. ip &= 0x00ffffff;
  102. ip |= (((ip >> 24) & 0xff) % 240) << 24;
  103. }
  104. if (((ip >> 24) & 0xff) == 0)
  105. ip |= 0x01000000;
  106. if (((ip & 0xff) == 0)||((ip & 0xff) == 255))
  107. ip ^= 0x00000001;
  108. InetAddress inaddr(Utils::hton(ip),9993);
  109. if (usedIps.find(inaddr) == usedIps.end()) {
  110. usedIps[inaddr] = addr;
  111. return inaddr;
  112. }
  113. ++ip; // keep looking sequentially for an unclaimed IP
  114. }
  115. }
  116. static Identity makeNodeHome(bool super)
  117. {
  118. Identity id;
  119. id.generate();
  120. std::string path(basePath + ZT_PATH_SEPARATOR_S + (super ? "S" : "N") + id.address().toString());
  121. #ifdef __WINDOWS__
  122. CreateDirectoryA(path.c_str(),NULL);
  123. #else
  124. mkdir(path.c_str(),0700);
  125. #endif
  126. if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),id.toString(true)))
  127. return Identity();
  128. if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),id.toString(false)))
  129. return Identity();
  130. return id;
  131. }
  132. // Instantiates supernodes by scanning for S########## subdirectories
  133. static std::vector<Address> initSupernodes()
  134. {
  135. Dictionary supernodes;
  136. std::vector< std::pair<Identity,InetAddress> > snids;
  137. std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str()));
  138. for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) {
  139. if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'S')) {
  140. std::string idbuf;
  141. if (Utils::readFile((basePath + ZT_PATH_SEPARATOR_S + d->first + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),idbuf)) {
  142. Identity id(idbuf);
  143. if (id) {
  144. InetAddress inaddr(inetAddressFromZeroTierAddress(id.address()));
  145. snids.push_back(std::pair<Identity,InetAddress>(id,inaddr));
  146. Dictionary snd;
  147. snd["id"] = id.toString(false);
  148. snd["udp"] = inaddr.toString();
  149. snd["desc"] = id.address().toString();
  150. snd["dns"] = inaddr.toIpString();
  151. supernodes[id.address().toString()] = snd.toString();
  152. }
  153. }
  154. }
  155. }
  156. Dictionary rtd;
  157. rtd["supernodes"] = supernodes.toString();
  158. rtd["noupdate"] = "1";
  159. rootTopology = rtd.toString();
  160. std::vector<Address> newNodes;
  161. for(std::vector< std::pair<Identity,InetAddress> >::iterator i(snids.begin());i!=snids.end();++i) {
  162. SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + "S" + i->first.address().toString()),rootTopology.c_str(),true,i->second);
  163. nodes[i->first.address()] = n;
  164. newNodes.push_back(i->first.address());
  165. }
  166. return newNodes;
  167. }
  168. // Instantiates any not-already-instantiated regular nodes
  169. static std::vector<Address> scanForNewNodes()
  170. {
  171. std::vector<Address> newNodes;
  172. std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str()));
  173. for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) {
  174. if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'N')) {
  175. Address na(d->first.c_str() + 1);
  176. if (nodes.find(na) == nodes.end()) {
  177. InetAddress inaddr(inetAddressFromZeroTierAddress(na));
  178. SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + d->first),rootTopology.c_str(),false,inaddr);
  179. nodes[na] = n;
  180. newNodes.push_back(na);
  181. }
  182. }
  183. }
  184. return newNodes;
  185. }
  186. static void doHelp(const std::vector<std::string> &cmd)
  187. {
  188. printf("---------- help"ZT_EOL_S);
  189. printf("---------- mksn <number of supernodes>"ZT_EOL_S);
  190. printf("---------- mkn <number of normal nodes>"ZT_EOL_S);
  191. printf("---------- list"ZT_EOL_S);
  192. printf("---------- join <address/*/**> <network ID>"ZT_EOL_S);
  193. printf("---------- leave <address/*/**> <network ID>"ZT_EOL_S);
  194. printf("---------- listnetworks <address/*/**>"ZT_EOL_S);
  195. printf("---------- listpeers <address/*/**>"ZT_EOL_S);
  196. printf("---------- unicast <address/*/**> <address/*/**> <network ID> <frame length, min: 16> [<timeout, default: 2>]"ZT_EOL_S);
  197. printf("---------- quit"ZT_EOL_S);
  198. }
  199. static void doMKSN(const std::vector<std::string> &cmd)
  200. {
  201. if (cmd.size() < 2) {
  202. doHelp(cmd);
  203. return;
  204. }
  205. if (nodes.size() > 0) {
  206. printf("---------- mksn error: mksn can only be called once (network already exists)"ZT_EOL_S);
  207. return;
  208. }
  209. int count = Utils::strToInt(cmd[1].c_str());
  210. for(int i=0;i<count;++i) {
  211. Identity id(makeNodeHome(true));
  212. printf("%s identity created"ZT_EOL_S,id.address().toString().c_str());
  213. }
  214. std::vector<Address> nodes(initSupernodes());
  215. for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a)
  216. printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str());
  217. //printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str());
  218. }
  219. static void doMKN(const std::vector<std::string> &cmd)
  220. {
  221. if (cmd.size() < 2) {
  222. doHelp(cmd);
  223. return;
  224. }
  225. if (nodes.size() == 0) {
  226. printf("---------- mkn error: use mksn to create supernodes first."ZT_EOL_S);
  227. return;
  228. }
  229. int count = Utils::strToInt(cmd[1].c_str());
  230. for(int i=0;i<count;++i) {
  231. Identity id(makeNodeHome(false));
  232. printf("%s identity created"ZT_EOL_S,id.address().toString().c_str());
  233. }
  234. std::vector<Address> nodes(scanForNewNodes());
  235. for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a)
  236. printf("%s started (regular node)"ZT_EOL_S,a->toString().c_str());
  237. }
  238. static void doList(const std::vector<std::string> &cmd)
  239. {
  240. ZT1_Node_Status status;
  241. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  242. n->second->node.status(&status);
  243. printf("%s %c %s (%u peers, %u direct links)"ZT_EOL_S,
  244. n->first.toString().c_str(),
  245. n->second->supernode ? 'S' : 'N',
  246. (status.online ? "ONLINE" : "OFFLINE"),
  247. status.knownPeers,
  248. status.directlyConnectedPeers);
  249. }
  250. }
  251. static void doJoin(const std::vector<std::string> &cmd)
  252. {
  253. if (cmd.size() < 3) {
  254. doHelp(cmd);
  255. return;
  256. }
  257. std::vector<Address> addrs;
  258. if ((cmd[1] == "*")||(cmd[1] == "**")) {
  259. bool includeSuper = (cmd[1] == "**");
  260. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  261. if ((includeSuper)||(!n->second->supernode))
  262. addrs.push_back(n->first);
  263. }
  264. } else addrs.push_back(Address(cmd[1]));
  265. uint64_t nwid = Utils::hexStrToU64(cmd[2].c_str());
  266. for(std::vector<Address>::iterator a(addrs.begin());a!=addrs.end();++a) {
  267. std::map< Address,SimNode * >::iterator n(nodes.find(*a));
  268. if (n != nodes.end()) {
  269. n->second->node.join(nwid);
  270. printf("%s join %.16llx"ZT_EOL_S,n->first.toString().c_str(),nwid);
  271. }
  272. }
  273. }
  274. static void doLeave(const std::vector<std::string> &cmd)
  275. {
  276. if (cmd.size() < 3) {
  277. doHelp(cmd);
  278. return;
  279. }
  280. std::vector<Address> addrs;
  281. if ((cmd[1] == "*")||(cmd[1] == "**")) {
  282. bool includeSuper = (cmd[1] == "**");
  283. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  284. if ((includeSuper)||(!n->second->supernode))
  285. addrs.push_back(n->first);
  286. }
  287. } else addrs.push_back(Address(cmd[1]));
  288. uint64_t nwid = Utils::hexStrToU64(cmd[2].c_str());
  289. for(std::vector<Address>::iterator a(addrs.begin());a!=addrs.end();++a) {
  290. std::map< Address,SimNode * >::iterator n(nodes.find(*a));
  291. if (n != nodes.end()) {
  292. n->second->node.leave(nwid);
  293. printf("%s leave %.16llx"ZT_EOL_S,n->first.toString().c_str(),nwid);
  294. }
  295. }
  296. }
  297. static void doListNetworks(const std::vector<std::string> &cmd)
  298. {
  299. if (cmd.size() < 2) {
  300. doHelp(cmd);
  301. return;
  302. }
  303. std::vector<Address> addrs;
  304. if ((cmd[1] == "*")||(cmd[1] == "**")) {
  305. bool includeSuper = (cmd[1] == "**");
  306. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  307. if ((includeSuper)||(!n->second->supernode))
  308. addrs.push_back(n->first);
  309. }
  310. } else addrs.push_back(Address(cmd[1]));
  311. printf("---------- <nwid> <name> <mac> <status> <config age> <type> <dev> <ips>"ZT_EOL_S);
  312. for(std::vector<Address>::iterator a(addrs.begin());a!=addrs.end();++a) {
  313. std::string astr(a->toString());
  314. std::map< Address,SimNode * >::iterator n(nodes.find(*a));
  315. if (n != nodes.end()) {
  316. ZT1_Node_NetworkList *nl = n->second->node.listNetworks();
  317. if (nl) {
  318. for(unsigned int i=0;i<nl->numNetworks;++i) {
  319. printf("%s %s %s %s %s %ld %s %s ",
  320. astr.c_str(),
  321. nl->networks[i].nwidHex,
  322. nl->networks[i].name,
  323. nl->networks[i].macStr,
  324. nl->networks[i].statusStr,
  325. nl->networks[i].configAge,
  326. (nl->networks[i].isPrivate ? "private" : "public"),
  327. nl->networks[i].device);
  328. if (nl->networks[i].numIps > 0) {
  329. for(unsigned int j=0;j<nl->networks[i].numIps;++j) {
  330. if (j > 0)
  331. printf(",");
  332. printf("%s/%d",nl->networks[i].ips[j].ascii,(int)nl->networks[i].ips[j].port);
  333. }
  334. } else printf("-");
  335. printf(ZT_EOL_S);
  336. }
  337. n->second->node.freeQueryResult(nl);
  338. }
  339. }
  340. }
  341. }
  342. static void doListPeers(const std::vector<std::string> &cmd)
  343. {
  344. if (cmd.size() < 2) {
  345. doHelp(cmd);
  346. return;
  347. }
  348. std::vector<Address> addrs;
  349. if ((cmd[1] == "*")||(cmd[1] == "**")) {
  350. bool includeSuper = (cmd[1] == "**");
  351. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  352. if ((includeSuper)||(!n->second->supernode))
  353. addrs.push_back(n->first);
  354. }
  355. } else addrs.push_back(Address(cmd[1]));
  356. printf("---------- <ztaddr> <paths> <latency> <version> <role>"ZT_EOL_S);
  357. for(std::vector<Address>::iterator a(addrs.begin());a!=addrs.end();++a) {
  358. std::string astr(a->toString());
  359. std::map< Address,SimNode * >::iterator n(nodes.find(*a));
  360. if (n != nodes.end()) {
  361. ZT1_Node_PeerList *pl = n->second->node.listPeers();
  362. if (pl) {
  363. for(unsigned int i=0;i<pl->numPeers;++i) {
  364. printf("%s %.10llx ",astr.c_str(),(unsigned long long)pl->peers[i].rawAddress);
  365. if (pl->peers[i].numPaths == 0)
  366. printf("-");
  367. else {
  368. for(unsigned int j=0;j<pl->peers[i].numPaths;++j) {
  369. if (j > 0)
  370. printf(",");
  371. switch(pl->peers[i].paths[j].type) {
  372. default:
  373. printf("unknown;");
  374. break;
  375. case ZT1_Node_PhysicalPath_TYPE_UDP:
  376. printf("udp;");
  377. break;
  378. case ZT1_Node_PhysicalPath_TYPE_TCP_OUT:
  379. printf("tcp_out;");
  380. break;
  381. case ZT1_Node_PhysicalPath_TYPE_TCP_IN:
  382. printf("tcp_in;");
  383. break;
  384. case ZT1_Node_PhysicalPath_TYPE_ETHERNET:
  385. printf("eth;");
  386. break;
  387. }
  388. printf("%s/%d;%ld;%ld;%ld;%s",
  389. pl->peers[i].paths[j].address.ascii,
  390. (int)pl->peers[i].paths[j].address.port,
  391. pl->peers[i].paths[j].lastSend,
  392. pl->peers[i].paths[j].lastReceive,
  393. pl->peers[i].paths[j].lastPing,
  394. (pl->peers[i].paths[j].fixed ? "fixed" : (pl->peers[i].paths[j].active ? "active" : "inactive")));
  395. }
  396. }
  397. const char *rolestr;
  398. switch(pl->peers[i].role) {
  399. case ZT1_Node_Peer_SUPERNODE: rolestr = "SUPERNODE"; break;
  400. case ZT1_Node_Peer_HUB: rolestr = "HUB"; break;
  401. case ZT1_Node_Peer_NODE: rolestr = "NODE"; break;
  402. default: rolestr = "?"; break;
  403. }
  404. printf(" %u %s %s"ZT_EOL_S,
  405. pl->peers[i].latency,
  406. ((pl->peers[i].remoteVersion[0]) ? pl->peers[i].remoteVersion : "-"),
  407. rolestr);
  408. }
  409. n->second->node.freeQueryResult(pl);
  410. }
  411. }
  412. }
  413. }
  414. static void doUnicast(const std::vector<std::string> &cmd)
  415. {
  416. union {
  417. uint64_t i[2];
  418. unsigned char data[2800];
  419. } pkt;
  420. if (cmd.size() < 5) {
  421. doHelp(cmd);
  422. return;
  423. }
  424. uint64_t nwid = Utils::hexStrToU64(cmd[3].c_str());
  425. unsigned int frameLen = Utils::strToUInt(cmd[4].c_str());
  426. uint64_t tout = 2000;
  427. if (cmd.size() >= 6)
  428. tout = Utils::strToU64(cmd[5].c_str()) * 1000ULL;
  429. if (frameLen < 16)
  430. frameLen = 16;
  431. if (frameLen > 2800)
  432. frameLen = 2800;
  433. std::vector<Address> senders;
  434. if ((cmd[1] == "*")||(cmd[1] == "**")) {
  435. bool includeSuper = (cmd[1] == "**");
  436. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  437. if ((includeSuper)||(!n->second->supernode))
  438. senders.push_back(n->first);
  439. }
  440. } else senders.push_back(Address(cmd[1]));
  441. std::vector<Address> receivers;
  442. if ((cmd[2] == "*")||(cmd[2] == "**")) {
  443. bool includeSuper = (cmd[2] == "**");
  444. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  445. if ((includeSuper)||(!n->second->supernode))
  446. receivers.push_back(n->first);
  447. }
  448. } else receivers.push_back(Address(cmd[2]));
  449. for(unsigned int i=0;i<frameLen;++i)
  450. pkt.data[i] = (unsigned char)prng.next32();
  451. unsigned long sentCount = 0;
  452. for(std::vector<Address>::iterator s(senders.begin());s!=senders.end();++s) {
  453. for(std::vector<Address>::iterator r(receivers.begin());r!=receivers.end();++r) {
  454. if (*s == *r)
  455. continue;
  456. SimNode *sender = nodes[*s];
  457. SimNode *receiver = nodes[*r];
  458. SharedPtr<TestEthernetTap> stap(sender->tapFactory.getByNwid(nwid));
  459. SharedPtr<TestEthernetTap> rtap(receiver->tapFactory.getByNwid(nwid));
  460. if ((stap)&&(rtap)) {
  461. pkt.i[0] = s->toInt();
  462. pkt.i[1] = Utils::now();
  463. stap->injectPacketFromHost(stap->mac(),rtap->mac(),0xdead,pkt.data,frameLen);
  464. printf("%s -> %s etherType 0xdead network %.16llx length %u"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),nwid,frameLen);
  465. ++sentCount;
  466. } else if (stap) {
  467. printf("%s -> !%s (receiver not a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),nwid);
  468. } else if (rtap) {
  469. printf("%s -> !%s (sender not a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),nwid);
  470. } else {
  471. printf("%s -> !%s (neither party is a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),nwid);
  472. }
  473. }
  474. }
  475. printf("---------- waiting up to %llu seconds..."ZT_EOL_S,tout / 1000ULL);
  476. std::set< std::pair<Address,Address> > receivedPairs;
  477. std::vector<TestEthernetTap::TestFrame> frames;
  478. uint64_t toutend = Utils::now() + tout;
  479. do {
  480. for(std::vector<Address>::iterator r(receivers.begin());r!=receivers.end();++r) {
  481. SimNode *receiver = nodes[*r];
  482. SharedPtr<TestEthernetTap> rtap(receiver->tapFactory.getByNwid(nwid));
  483. if (rtap) {
  484. rtap->get(frames);
  485. for(std::vector<TestEthernetTap::TestFrame>::iterator f(frames.begin());f!=frames.end();++f) {
  486. if ((f->len == frameLen)&&(!memcmp(f->data + 16,pkt.data + 16,frameLen - 16))) {
  487. uint64_t ints[2];
  488. memcpy(ints,f->data,16);
  489. printf("%s <- %.10llx received test packet, latency == %llums"ZT_EOL_S,r->toString().c_str(),ints[0],f->timestamp - ints[1]);
  490. receivedPairs.insert(std::pair<Address,Address>(Address(ints[0]),*r));
  491. } else {
  492. printf("%s !! got spurious packet, length == %u, etherType == %.4x"ZT_EOL_S,r->toString().c_str(),f->len,f->etherType);
  493. }
  494. }
  495. }
  496. }
  497. Thread::sleep(250);
  498. } while ((receivedPairs.size() < sentCount)&&(Utils::now() < toutend));
  499. for(std::vector<Address>::iterator s(senders.begin());s!=senders.end();++s) {
  500. for(std::vector<Address>::iterator r(receivers.begin());r!=receivers.end();++r) {
  501. if (*s == *r)
  502. continue;
  503. if (!receivedPairs.count(std::pair<Address,Address>(*s,*r))) {
  504. printf("%s <- %s was never received (timed out)"ZT_EOL_S,r->toString().c_str(),s->toString().c_str());
  505. }
  506. }
  507. }
  508. }
  509. int main(int argc,char **argv)
  510. {
  511. char linebuf[1024];
  512. if (argc <= 1) {
  513. fprintf(stderr,"Usage: %s <base path for temporary node home directories>"ZT_EOL_S,argv[0]);
  514. return 1;
  515. }
  516. basePath = argv[1];
  517. #ifdef __WINDOWS__
  518. CreateDirectoryA(basePath.c_str(),NULL);
  519. #else
  520. mkdir(basePath.c_str(),0700);
  521. #endif
  522. printf("*** ZeroTier One Version %s -- Headless Network Simulator ***"ZT_EOL_S,Node::versionString());
  523. printf(ZT_EOL_S);
  524. {
  525. printf("---------- scanning '%s' for existing network..."ZT_EOL_S,basePath.c_str());
  526. std::vector<Address> snodes(initSupernodes());
  527. if (snodes.empty()) {
  528. printf("---------- no existing network found; use 'mksn' to create one."ZT_EOL_S);
  529. } else {
  530. for(std::vector<Address>::iterator a(snodes.begin());a!=snodes.end();++a)
  531. printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str());
  532. //printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str());
  533. std::vector<Address> nodes(scanForNewNodes());
  534. for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a)
  535. printf("%s started (normal peer)"ZT_EOL_S,a->toString().c_str());
  536. printf("---------- %u peers and %u supernodes loaded!"ZT_EOL_S,(unsigned int)nodes.size(),(unsigned int)snodes.size());
  537. }
  538. }
  539. printf(ZT_EOL_S);
  540. printf("Type 'help' for help."ZT_EOL_S);
  541. printf(ZT_EOL_S);
  542. for(;;) {
  543. printf(">> ");
  544. fflush(stdout);
  545. if (!fgets(linebuf,sizeof(linebuf),stdin))
  546. break;
  547. std::vector<std::string> cmd(Utils::split(linebuf," \r\n\t","\\","\""));
  548. if (cmd.size() == 0)
  549. continue;
  550. if (cmd[0] == "quit")
  551. break;
  552. else if (cmd[0] == "help")
  553. doHelp(cmd);
  554. else if (cmd[0] == "mksn")
  555. doMKSN(cmd);
  556. else if (cmd[0] == "mkn")
  557. doMKN(cmd);
  558. else if (cmd[0] == "list")
  559. doList(cmd);
  560. else if (cmd[0] == "join")
  561. doJoin(cmd);
  562. else if (cmd[0] == "leave")
  563. doLeave(cmd);
  564. else if (cmd[0] == "listnetworks")
  565. doListNetworks(cmd);
  566. else if (cmd[0] == "listpeers")
  567. doListPeers(cmd);
  568. else if (cmd[0] == "unicast")
  569. doUnicast(cmd);
  570. else doHelp(cmd);
  571. }
  572. for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
  573. printf("%s shutting down..."ZT_EOL_S,n->first.toString().c_str());
  574. delete n->second;
  575. }
  576. return 0;
  577. }