--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/tca_admin/TcaRegistry.cc Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2005-2006 University of Waterloo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <dtn-config.h>
+#endif
+
+#include "libs/gateway_prot.h"
+#include "libs/gateway_rpc.h"
+#include "libs/sha1.h"
+#include "TcaRegistry.h"
+
+static const char* APP_STRING = "tca";
+static const char* CLIB_STRING = "rpcgen";
+
+static const int DHT_KEYLEN = 20; // number of uints in a key
+
+
+ // hash a key s, from original long-string form, down to 20-byte key
+ // usable in the dht
+ static void
+ hash(const std::string& s, uint8 digest[DHT_KEYLEN])
+ {
+ // Use sha1 hash of endpointid to get a (probably) unique 20-byte key
+ sha1_context ctx;
+ sha1_starts(&ctx);
+ sha1_update(&ctx, (unsigned char*)(s.c_str()), s.length());
+ sha1_finish(&ctx, digest);
+ }
+
+
+/*
+static void
+dump_digest(uint8 digest[DHT_KEYLEN])
+{
+ printf("digest=");
+ for (int i=0; i<DHT_KEYLEN; ++i) printf("%c", digest[i]);
+ printf("\n");
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// class TcaRegistry
+
+
+bool
+TcaRegistry::init_nodes()
+{
+ // Construct list of available DHT nodes, hard coded at the moment.
+ // TODO: Do something smarter here, like go to OpenDHT site and read
+ // the current list of DHT nodes. Or read them from a local file that
+ // somebody actively maintains.
+
+ // To make this fast as possible for testing, cut this list down to just
+ // a few. For greater reliability and scalability, use more nodes.
+ dht_nodes_.push_back(std::string("cloudburst.uwaterloo.ca"));
+ dht_nodes_.push_back(std::string("blast.uwaterloo.ca"));
+
+ // Other known nodes:
+ /*
+ dht_nodes_.push_back(std::string("lefthand.eecs.harvard.edu"));
+ dht_nodes_.push_back(std::string("node2.lbnl.nodes.planet-lab.org"));
+ dht_nodes_.push_back(std::string("pl1.cs.utk.edu"));
+ dht_nodes_.push_back(std::string("pl1.ece.toronto.edu"));
+ dht_nodes_.push_back(std::string("planetlab2.cnds.jhu.edu"));
+ dht_nodes_.push_back(std::string("ricepl-3.cs.rice.edu"));
+ dht_nodes_.push_back(std::string("pli2-pa-3.hpl.hp.com"));
+ dht_nodes_.push_back(std::string("planetlab10.millennium.berkeley.edu"));
+ */
+
+ return true;
+}
+
+
+bool
+TcaRegistry::init_addrs()
+{
+ // First pass at "something smarter"...
+ // Test each dht node and keep only the nodes that are awake.
+
+ // Usage Note: It would be good to call this function periodically
+ // to refresh the list of "good" nodes.
+
+ printf("Initializing TcaRegistry...\n");
+
+ last_node_ = 0;
+
+ sockaddr_in addr;
+ for (unsigned int i=0; i<dht_nodes_.size(); ++i)
+ {
+ if (test_node(dht_nodes_[i].c_str(), &addr))
+ {
+ // it's a keeper
+ dht_addrs_.push_back(addr);
+ }
+ }
+
+ if (dht_addrs_.size() == 0) return false;
+
+ printf("...dht nodes available = %zu / %zu\n",
+ dht_addrs_.size(), dht_nodes_.size());
+ return true;
+}
+
+
+
+// write a registry record
+
+bool
+TcaRegistry::write(const RegRecord& rr, int ttl)
+{
+ CLIENT* p_node = get_node();
+ if (p_node == NULL) return false;
+
+ // printf("TcaRegistry::write: using node %d\n", int(p_node));
+
+ uint8 key[DHT_KEYLEN];
+ hash(rr.host_, key);
+ // dump_digest(key);
+
+ bamboo_put_args args;
+ memset(&args, 0, sizeof(args));
+
+ args.application = const_cast<char*>(APP_STRING);
+ args.client_library = const_cast<char*>(CLIB_STRING);
+ memcpy(args.key, key, DHT_KEYLEN);
+
+ args.value.bamboo_value_len = rr.link_addr_.length() + 1;
+ args.value.bamboo_value_val = const_cast<char*>(rr.link_addr_.c_str());
+
+ args.ttl_sec = ttl;
+
+ // TODO: Append other fields? Like timestamp of entry/refresh?
+
+ bamboo_stat* res = bamboo_dht_proc_put_2(&args, p_node);
+ // printf("TcaRegistry::write: put return code = %d\n", int(*res));
+
+ return (*res == BAMBOO_OK);
+}
+
+
+
+// read a registry record
+// rr.eid_ must be primed with the endpointid of the node to lookup
+
+bool
+TcaRegistry::read(RegRecord& rr)
+{
+ CLIENT* p_node = get_node();
+ if (p_node == NULL) return false;
+
+ // printf("TcaRegistry::read: using node %d\n", int(p_node));
+
+ uint8 key[DHT_KEYLEN];
+ hash(rr.host_, key);
+ // dump_digest(key);
+
+ bamboo_get_args args;
+ memset(&args, 0, sizeof(args));
+
+ args.application = const_cast<char*>(APP_STRING);
+ args.client_library = const_cast<char*>(CLIB_STRING);
+ memcpy(args.key, key, DHT_KEYLEN);
+
+ // Note: to here, this function is identical to write()
+
+ args.maxvals = 1;
+
+ bamboo_get_res* res = bamboo_dht_proc_get_2(&args, p_node);
+ if (res == NULL)
+ {
+ printf("TcaRegistry::read: get returned NULL\n");
+ return false;
+ }
+
+ int n_values = res->values.values_len;
+
+ if (n_values != 1)
+ {
+ // printf("TcaRegistry::read: get returned %d values\n", n_values);
+ return false;
+ }
+
+ bamboo_value* p_val = &res->values.values_val[0];
+
+ rr.link_addr_ = p_val->bamboo_value_val;
+ printf("TcaRegistry::read: succeeded! value=%s\n", rr.link_addr_.c_str());
+
+ return true;
+}
+
+
+/*
+// This version gets nodes by dns name -- inneficient because of dns
+// lookup, and also bad because the node in question may not be alive.
+CLIENT*
+TcaRegistry::get_node()
+{
+ // Get next available node. We deliberately spread the load around
+ // among all availabe nodes, and also tolerate missing nodes.
+
+ CLIENT* p_node = NULL;
+
+ for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
+ {
+ if (i == dht_nodes_.size()) i = 0;
+ p_node = get_connection(dht_nodes_[i].c_str());
+ if (p_node)
+ {
+ printf("TcaRegistry::get_node: using node %s\n",
+ dht_nodes_[i].c_str());
+ last_node_ = i;
+ break;
+ }
+ }
+
+ return p_node;
+}
+*/
+
+
+CLIENT*
+TcaRegistry::get_node()
+{
+ // Get next available node. We deliberately spread the load around
+ // among all availabe nodes, and also tolerate missing nodes.
+ //
+ // This version uses the addrs list which saves a dns lookup.
+ // Also, the addrs list is only populated with the nodes that are alive
+ // at startup, so there's less chance of failed attempts.
+
+ CLIENT* p_node = NULL;
+
+ for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
+ {
+ if (i == dht_addrs_.size()) i = 0;
+ p_node = get_connection(&dht_addrs_[i]);
+ if (p_node)
+ {
+ last_node_ = i;
+ break;
+ }
+ }
+
+ return p_node;
+}
+
+
+