diff options
Diffstat (limited to 'testnet.cpp')
| -rw-r--r-- | testnet.cpp | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/testnet.cpp b/testnet.cpp new file mode 100644 index 00000000..df70e40e --- /dev/null +++ b/testnet.cpp @@ -0,0 +1,362 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2011-2014 ZeroTier Networks LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <string> +#include <map> +#include <vector> + +#include "node/Constants.hpp" +#include "node/Node.hpp" +#include "node/Utils.hpp" +#include "node/Address.hpp" +#include "node/Identity.hpp" +#include "node/Thread.hpp" +#include "node/CMWC4096.hpp" + +#include "testnet/SimNet.hpp" +#include "testnet/SimNetSocketManager.hpp" +#include "testnet/TestEthernetTap.hpp" +#include "testnet/TestEthernetTapFactory.hpp" +#include "testnet/TestRoutingTable.hpp" + +#ifdef __WINDOWS__ +#include <windows.h> +#else +#include <unistd.h> +#include <sys/stat.h> +#endif + +using namespace ZeroTier; + +class SimNode +{ +public: + SimNode(SimNet &net,const std::string &hp,const char *rootTopology,bool issn,const InetAddress &addr) : + home(hp), + tapFactory(), + routingTable(), + socketManager(net.newEndpoint(addr)), + node(home.c_str(),&tapFactory,&routingTable,socketManager,false,rootTopology), + reasonForTermination(Node::NODE_RUNNING), + supernode(issn) + { + thread = Thread::start(this); + } + + ~SimNode() + { + node.terminate(Node::NODE_NORMAL_TERMINATION,"SimNode shutdown"); + Thread::join(thread); + } + + void threadMain() + throw() + { + reasonForTermination = node.run(); + } + + std::string home; + TestEthernetTapFactory tapFactory; + TestRoutingTable routingTable; + SimNetSocketManager *socketManager; + Node node; + Node::ReasonForTermination reasonForTermination; + bool supernode; + Thread thread; +}; + +static std::string basePath; +static SimNet net; +static std::map< Address,SimNode * > nodes; +static std::map< InetAddress,Address > usedIps; +static CMWC4096 prng; +static std::string rootTopology; + +// Converts an address into a fake IP not already claimed. +// Be sure to call only once, as this claims the IP before returning it. +static InetAddress inetAddressFromZeroTierAddress(const Address &addr) +{ + uint32_t ip = (uint32_t)(addr.toInt() & 0xffffffff); + for(;;) { + if (((ip >> 24) & 0xff) >= 240) { + ip &= 0x00ffffff; + ip |= (((ip >> 24) & 0xff) % 240) << 24; + } + if (((ip >> 24) & 0xff) == 0) + ip |= 0x01000000; + if (((ip & 0xff) == 0)||((ip & 0xff) == 255)) + ip ^= 0x00000001; + InetAddress inaddr(Utils::hton(ip),9993); + if (usedIps.find(inaddr) == usedIps.end()) { + usedIps[inaddr] = addr; + return inaddr; + } + ++ip; // keep looking sequentially for an unclaimed IP + } +} + +static Identity makeNodeHome(bool super) +{ + Identity id; + id.generate(); + + std::string path(basePath + ZT_PATH_SEPARATOR_S + (super ? "S" : "N") + id.address().toString()); + +#ifdef __WINDOWS__ + CreateDirectoryA(path.c_str(),NULL); +#else + mkdir(path.c_str(),0700); +#endif + + if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.secret"),id.toString(true))) + return Identity(); + if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.public"),id.toString(false))) + return Identity(); + + return id; +} + +// Instantiates supernodes by scanning for S########## subdirectories +static std::vector<Address> initSupernodes() +{ + Dictionary supernodes; + std::vector< std::pair<Identity,InetAddress> > snids; + std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str())); + + for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) { + if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'S')) { + std::string idbuf; + if (Utils::readFile((basePath + ZT_PATH_SEPARATOR_S + d->first + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),idbuf)) { + Identity id(idbuf); + if (id) { + InetAddress inaddr(inetAddressFromZeroTierAddress(id.address())); + snids.push_back(std::pair<Identity,InetAddress>(id,inaddr)); + + Dictionary snd; + snd["id"] = id.toString(false); + snd["udp"] = inaddr.toString(); + snd["desc"] = id.address().toString(); + snd["dns"] = inaddr.toIpString(); + supernodes[id.address().toString()] = snd.toString(); + } + } + } + } + + Dictionary rtd; + rtd["supernodes"] = supernodes.toString(); + rtd["noupdate"] = "1"; + rootTopology = rtd.toString(); + + std::vector<Address> newNodes; + + for(std::vector< std::pair<Identity,InetAddress> >::iterator i(snids.begin());i!=snids.end();++i) { + SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + "S" + i->first.address().toString()),rootTopology.c_str(),true,i->second); + nodes[id.address()] = n; + newNodes.push_back(id.address()); + } + + return newNodes; +} + +// Instantiates any not-already-instantiated regular nodes +static std::vector<Address> scanForNewNodes() +{ + std::vector<Address> newNodes; + std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str())); + + for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) { + if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'N')) { + Address na(d->first.c_str() + 1); + if (nodes.find(na) == nodes.end()) { + InetAddress inaddr(inetAddressFromZeroTierAddress(na)); + + SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + d->first),rootTopology.c_str(),false,inaddr); + nodes[na] = n; + + newNodes.push_back(na); + } + } + } + + return newNodes; +} + +static void doHelp(const std::vector<std::string> &cmd) +{ + printf("---------- help"ZT_EOL_S); + printf("---------- mksn <number of supernodes>"ZT_EOL_S); + printf("---------- mkn <number of normal nodes>"ZT_EOL_S); + printf("---------- list"ZT_EOL_S); + printf("---------- join <address/*> <network ID>"ZT_EOL_S); + printf("---------- leave <address/*> <network ID>"ZT_EOL_S); + printf("---------- listnetworks <address/*>"ZT_EOL_S); + printf("---------- listpeers <address/*>"ZT_EOL_S); + printf("---------- alltoall"ZT_EOL_S); + printf("---------- quit"ZT_EOL_S) +} + +static void doMKSN(const std::vector<std::string> &cmd) +{ + if (cmd.size() < 2) { + doHelp(cmd); + return; + } + if (nodes.size() > 0) { + printf("---------- mksn error: mksn can only be called once (network already exists)"ZT_EOL_S,(unsigned int)nodes.size()); + return; + } + + int count = Utils::strToInt(cmd[1].c_str()); + for(int i=0;i<count;++i) { + Identity id(makeNodeHome(true)); + printf("%s identity created"ZT_EOL_S,id.address().toString().c_str()); + } + + std::vector<Address> nodes(initSupernodes()); + for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a) + printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str()); + + printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str()); +} + +static void doMKN(const std::vector<std::string> &cmd) +{ + if (cmd.size() < 2) { + doHelp(cmd); + return; + } + if (nodes.size() == 0) { + printf("---------- mkn error: use mksn to create supernodes first."ZT_EOL_S); + return; + } +} + +static void doList(const std::vector<std::string> &cmd) +{ +} + +static void doJoin(const std::vector<std::string> &cmd) +{ +} + +static void doLeave(const std::vector<std::string> &cmd) +{ +} + +static void doListNetworks(const std::vector<std::string> &cmd) +{ +} + +static void doListPeers(const std::vector<std::string> &cmd) +{ +} + +static void doAllToAll(const std::vector<std::string> &cmd) +{ +} + +int main(int argc,char **argv) +{ + char linebuf[1024]; + + if (argc <= 1) { + fprintf(stderr,"Usage: %s <base path for temporary node home directories>"ZT_EOL_S,argv[0]); + return 1; + } + + basePath = argv[1]; +#ifdef __WINDOWS__ + CreateDirectoryA(basePath.c_str(),NULL); +#else + mkdir(basePath.c_str(),0700); +#endif + + printf("*** ZeroTier One Version %s -- Headless Network Simulator ***"ZT_EOL_S,Node::versionString()); + printf(ZT_EOL_S); + + { + printf("---------- scanning '%s' for existing network..."ZT_EOL_S); + std::vector<Address> snodes(initSupernodes()); + if (snodes.empty()) { + printf("---------- no existing network found; use 'mksn' to create one."ZT_EOL_S); + } else { + for(std::vector<Address>::iterator a(snodes.begin());a!=snodes.end();++a) + printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str()); + printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str()); + std::vector<Address> nodes(scanForNewNodes()); + for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a) + printf("%s started (normal peer)"ZT_EOL_S,a->toString().c_str()); + printf("---------- %u peers and %u supernodes loaded!"ZT_EOL_S,(unsigned int)nodes.size(),(unsigned int)snodes.size()); + } + } + printf(ZT_EOL_S); + + printf("Type 'help' for help."ZT_EOL_S); + printf(ZT_EOL_S); + + for(;;) { + printf(">> "); + fflush(stdout); + if (!fgets(linebuf,sizeof(linebuf),stdin)) + break; + std::vector<std::string> cmd(Utils::split(linebuf," \r\n\t","\\","\"")); + if (cmd.size() == 0) + continue; + + if (cmd[0] == "quit") + break; + else if (cmd[0] == "help") + doHelp(cmd); + else if (cmd[0] == "mksn") + doMKSN(cmd); + else if (cmd[0] == "mkn") + doMKN(cmd); + else if (cmd[0] == "join") + doJoin(cmd); + else if (cmd[0] == "leave") + doLeave(cmd); + else if (cmd[0] == "listnetworks") + doListNetworks(cmd); + else if (cmd[0] == "listpeers") + doListPeers(cmd); + else if (cmd[0] == "alltoall") + doAllToAll(cmd); + else doHelp(cmd); + } + + for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { + printf("%s shutting down..."ZT_EOL_S,n->first.toString().c_str()); + delete n->second; + } + + return 0; +} |
