TcaRegistry.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2005-2006 University of Waterloo
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "libs/gateway_prot.h"
00019 #include "libs/gateway_rpc.h"
00020 #include "libs/sha1.h"
00021 #include "TcaRegistry.h"
00022 
00023 static const char* APP_STRING = "tca";
00024 static const char* CLIB_STRING = "rpcgen";
00025 
00026 static const int DHT_KEYLEN = 20;           // number of uints in a key
00027 
00028 
00029  // hash a key s, from original long-string form, down to 20-byte key
00030  // usable in the dht
00031  static void
00032  hash(const std::string& s, uint8 digest[DHT_KEYLEN])
00033  {
00034      // Use sha1 hash of endpointid to get a (probably) unique 20-byte key
00035      sha1_context ctx;
00036      sha1_starts(&ctx);
00037      sha1_update(&ctx, (unsigned char*)(s.c_str()), s.length());
00038      sha1_finish(&ctx, digest);
00039  }
00040 
00041 
00042 /*
00043 static void
00044 dump_digest(uint8 digest[DHT_KEYLEN])
00045 {
00046     printf("digest=");
00047     for (int i=0; i<DHT_KEYLEN; ++i) printf("%c", digest[i]);
00048     printf("\n");
00049 }
00050 */
00051  
00053 // class TcaRegistry
00054 
00055 
00056 bool
00057 TcaRegistry::init_nodes()
00058 {
00059     // Construct list of available DHT nodes, hard coded at the moment.
00060     // TODO: Do something smarter here, like go to OpenDHT site and read
00061     // the current list of DHT nodes. Or read them from a local file that
00062     // somebody actively maintains.
00063 
00064     // To make this fast as possible for testing, cut this list down to just
00065     // a few. For greater reliability and scalability, use more nodes.
00066     dht_nodes_.push_back(std::string("cloudburst.uwaterloo.ca"));
00067     dht_nodes_.push_back(std::string("blast.uwaterloo.ca"));
00068 
00069     // Other known nodes:
00070     /*
00071     dht_nodes_.push_back(std::string("lefthand.eecs.harvard.edu"));
00072     dht_nodes_.push_back(std::string("node2.lbnl.nodes.planet-lab.org"));
00073     dht_nodes_.push_back(std::string("pl1.cs.utk.edu"));
00074     dht_nodes_.push_back(std::string("pl1.ece.toronto.edu"));
00075     dht_nodes_.push_back(std::string("planetlab2.cnds.jhu.edu"));
00076     dht_nodes_.push_back(std::string("ricepl-3.cs.rice.edu"));
00077     dht_nodes_.push_back(std::string("pli2-pa-3.hpl.hp.com"));
00078     dht_nodes_.push_back(std::string("planetlab10.millennium.berkeley.edu"));
00079     */
00080 
00081     return true;
00082 }
00083 
00084 
00085 bool
00086 TcaRegistry::init_addrs()
00087 {
00088     // First pass at "something smarter"... 
00089     // Test each dht node and keep only the nodes that are awake.
00090 
00091     // Usage Note: It would be good to call this function periodically
00092     // to refresh the list of "good" nodes.
00093 
00094     printf("Initializing TcaRegistry...\n");
00095 
00096     last_node_ = 0;
00097 
00098     sockaddr_in addr;
00099     for (unsigned int i=0; i<dht_nodes_.size(); ++i)
00100     {
00101         if (test_node(dht_nodes_[i].c_str(), &addr))
00102         {
00103             // it's a keeper
00104             dht_addrs_.push_back(addr);
00105         }
00106     }
00107             
00108     if (dht_addrs_.size() == 0) return false;
00109 
00110     printf("...dht nodes available = %zu / %zu\n",
00111            dht_addrs_.size(), dht_nodes_.size());
00112     return true;
00113 }
00114 
00115 
00116 
00117 // write a registry record
00118 
00119 bool
00120 TcaRegistry::write(const RegRecord& rr, int ttl)
00121 {
00122     CLIENT* p_node = get_node();
00123     if (p_node == NULL) return false;
00124 
00125     // printf("TcaRegistry::write: using node %d\n", int(p_node));
00126 
00127     uint8 key[DHT_KEYLEN];
00128     hash(rr.host_, key);
00129     // dump_digest(key);
00130 
00131     bamboo_put_args args;
00132     memset(&args, 0, sizeof(args));
00133 
00134     args.application = const_cast<char*>(APP_STRING);
00135     args.client_library = const_cast<char*>(CLIB_STRING);
00136     memcpy(args.key, key, DHT_KEYLEN);
00137 
00138     args.value.bamboo_value_len = rr.link_addr_.length() + 1;
00139     args.value.bamboo_value_val = const_cast<char*>(rr.link_addr_.c_str());
00140 
00141     args.ttl_sec = ttl;
00142 
00143     // TODO: Append other fields? Like timestamp of entry/refresh?
00144     
00145     bamboo_stat* res = bamboo_dht_proc_put_2(&args, p_node);
00146     // printf("TcaRegistry::write: put return code = %d\n", int(*res));
00147         
00148     return (*res == BAMBOO_OK);
00149 }
00150 
00151 
00152 
00153 // read a registry record
00154 // rr.eid_ must be primed with the endpointid of the node to lookup
00155 
00156 bool
00157 TcaRegistry::read(RegRecord& rr)
00158 {
00159     CLIENT* p_node = get_node();
00160     if (p_node == NULL) return false;
00161 
00162     // printf("TcaRegistry::read: using node %d\n", int(p_node));
00163 
00164     uint8 key[DHT_KEYLEN];
00165     hash(rr.host_, key);
00166     // dump_digest(key);
00167 
00168     bamboo_get_args args;
00169     memset(&args, 0, sizeof(args));
00170 
00171     args.application = const_cast<char*>(APP_STRING);
00172     args.client_library = const_cast<char*>(CLIB_STRING);
00173     memcpy(args.key, key, DHT_KEYLEN);
00174 
00175     // Note: to here, this function is identical to write()
00176 
00177     args.maxvals = 1;
00178 
00179     bamboo_get_res* res = bamboo_dht_proc_get_2(&args, p_node);
00180     if (res == NULL)
00181     {
00182         printf("TcaRegistry::read: get returned NULL\n");
00183         return false;
00184     }
00185 
00186     int n_values = res->values.values_len;
00187     
00188     if (n_values != 1)
00189     {
00190         // printf("TcaRegistry::read: get returned %d values\n", n_values);
00191         return false;
00192     }
00193 
00194     bamboo_value* p_val = &res->values.values_val[0];
00195 
00196     rr.link_addr_ = p_val->bamboo_value_val;
00197     printf("TcaRegistry::read: succeeded! value=%s\n", rr.link_addr_.c_str());
00198 
00199     return true;
00200 }
00201 
00202 
00203 /*
00204 // This version gets nodes by dns name -- inneficient because of dns
00205 // lookup, and also bad because the node in question may not be alive.
00206 CLIENT*
00207 TcaRegistry::get_node()
00208 {
00209     // Get next available node. We deliberately spread the load around
00210     // among all availabe nodes, and also tolerate missing nodes.
00211 
00212     CLIENT* p_node = NULL;
00213 
00214     for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
00215     {
00216         if (i == dht_nodes_.size()) i = 0;
00217         p_node = get_connection(dht_nodes_[i].c_str());
00218         if (p_node)
00219         {
00220             printf("TcaRegistry::get_node: using node %s\n",
00221                     dht_nodes_[i].c_str());
00222             last_node_ = i;
00223             break;
00224         }
00225     }
00226 
00227     return p_node;
00228 }
00229 */
00230 
00231 
00232 CLIENT*
00233 TcaRegistry::get_node()
00234 {
00235     // Get next available node. We deliberately spread the load around
00236     // among all availabe nodes, and also tolerate missing nodes.
00237     //
00238     // This version uses the addrs list which saves a dns lookup.
00239     // Also, the addrs list is only populated with the nodes that are alive
00240     // at startup, so there's less chance of failed attempts.
00241 
00242     CLIENT* p_node = NULL;
00243 
00244     for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
00245     {
00246         if (i == dht_addrs_.size()) i = 0;
00247         p_node = get_connection(&dht_addrs_[i]);
00248         if (p_node)
00249         {
00250             last_node_ = i;
00251             break;
00252         }
00253     }
00254 
00255     return p_node;
00256 }
00257 
00258 
00259 

Generated on Thu Jun 7 16:56:52 2007 for DTN Reference Implementation by  doxygen 1.5.1