TcaRegistry.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * University of Waterloo Open Source License
00008  * 
00009  * Copyright (c) 2005 University of Waterloo. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  *  
00022  *   Neither the name of the University of Waterloo nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
00030  * OF WATERLOO OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00031  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00032  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00033  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00034  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00035  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00036  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include "libs/gateway_prot.h"
00040 #include "libs/gateway_rpc.h"
00041 #include "libs/sha1.h"
00042 #include "TcaRegistry.h"
00043 
00044 static const char* APP_STRING = "tca";
00045 static const char* CLIB_STRING = "rpcgen";
00046 
00047 static const int DHT_KEYLEN = 20;           // number of uints in a key
00048 
00049 
00050  // hash a key s, from original long-string form, down to 20-byte key
00051  // usable in the dht
00052  static void
00053  hash(const std::string& s, uint8 digest[DHT_KEYLEN])
00054  {
00055      // Use sha1 hash of endpointid to get a (probably) unique 20-byte key
00056      sha1_context ctx;
00057      sha1_starts(&ctx);
00058      sha1_update(&ctx, (unsigned char*)(s.c_str()), s.length());
00059      sha1_finish(&ctx, digest);
00060  }
00061 
00062 
00063 /*
00064 static void
00065 dump_digest(uint8 digest[DHT_KEYLEN])
00066 {
00067     printf("digest=");
00068     for (int i=0; i<DHT_KEYLEN; ++i) printf("%c", digest[i]);
00069     printf("\n");
00070 }
00071 */
00072  
00074 // class TcaRegistry
00075 
00076 
00077 bool
00078 TcaRegistry::init_nodes()
00079 {
00080     // Construct list of available DHT nodes, hard coded at the moment.
00081     // TODO: Do something smarter here, like go to OpenDHT site and read
00082     // the current list of DHT nodes. Or read them from a local file that
00083     // somebody actively maintains.
00084 
00085     // To make this fast as possible for testing, cut this list down to just
00086     // a few. For greater reliability and scalability, use more nodes.
00087     dht_nodes_.push_back(std::string("cloudburst.uwaterloo.ca"));
00088     dht_nodes_.push_back(std::string("blast.uwaterloo.ca"));
00089 
00090     // Other known nodes:
00091     /*
00092     dht_nodes_.push_back(std::string("lefthand.eecs.harvard.edu"));
00093     dht_nodes_.push_back(std::string("node2.lbnl.nodes.planet-lab.org"));
00094     dht_nodes_.push_back(std::string("pl1.cs.utk.edu"));
00095     dht_nodes_.push_back(std::string("pl1.ece.toronto.edu"));
00096     dht_nodes_.push_back(std::string("planetlab2.cnds.jhu.edu"));
00097     dht_nodes_.push_back(std::string("ricepl-3.cs.rice.edu"));
00098     dht_nodes_.push_back(std::string("pli2-pa-3.hpl.hp.com"));
00099     dht_nodes_.push_back(std::string("planetlab10.millennium.berkeley.edu"));
00100     */
00101 
00102     return true;
00103 }
00104 
00105 
00106 bool
00107 TcaRegistry::init_addrs()
00108 {
00109     // First pass at "something smarter"... 
00110     // Test each dht node and keep only the nodes that are awake.
00111 
00112     // Usage Note: It would be good to call this function periodically
00113     // to refresh the list of "good" nodes.
00114 
00115     printf("Initializing TcaRegistry...\n");
00116 
00117     last_node_ = 0;
00118 
00119     sockaddr_in addr;
00120     for (unsigned int i=0; i<dht_nodes_.size(); ++i)
00121     {
00122         if (test_node(dht_nodes_[i].c_str(), &addr))
00123         {
00124             // it's a keeper
00125             dht_addrs_.push_back(addr);
00126         }
00127     }
00128             
00129     if (dht_addrs_.size() == 0) return false;
00130 
00131     printf("...dht nodes available = %zu / %zu\n",
00132            dht_addrs_.size(), dht_nodes_.size());
00133     return true;
00134 }
00135 
00136 
00137 
00138 // write a registry record
00139 
00140 bool
00141 TcaRegistry::write(const RegRecord& rr, int ttl)
00142 {
00143     CLIENT* p_node = get_node();
00144     if (p_node == NULL) return false;
00145 
00146     // printf("TcaRegistry::write: using node %d\n", int(p_node));
00147 
00148     uint8 key[DHT_KEYLEN];
00149     hash(rr.host_, key);
00150     // dump_digest(key);
00151 
00152     bamboo_put_args args;
00153     memset(&args, 0, sizeof(args));
00154 
00155     args.application = const_cast<char*>(APP_STRING);
00156     args.client_library = const_cast<char*>(CLIB_STRING);
00157     memcpy(args.key, key, DHT_KEYLEN);
00158 
00159     args.value.bamboo_value_len = rr.link_addr_.length() + 1;
00160     args.value.bamboo_value_val = const_cast<char*>(rr.link_addr_.c_str());
00161 
00162     args.ttl_sec = ttl;
00163 
00164     // TODO: Append other fields? Like timestamp of entry/refresh?
00165     
00166     bamboo_stat* res = bamboo_dht_proc_put_2(&args, p_node);
00167     // printf("TcaRegistry::write: put return code = %d\n", int(*res));
00168         
00169     return (*res == BAMBOO_OK);
00170 }
00171 
00172 
00173 
00174 // read a registry record
00175 // rr.eid_ must be primed with the endpointid of the node to lookup
00176 
00177 bool
00178 TcaRegistry::read(RegRecord& rr)
00179 {
00180     CLIENT* p_node = get_node();
00181     if (p_node == NULL) return false;
00182 
00183     // printf("TcaRegistry::read: using node %d\n", int(p_node));
00184 
00185     uint8 key[DHT_KEYLEN];
00186     hash(rr.host_, key);
00187     // dump_digest(key);
00188 
00189     bamboo_get_args args;
00190     memset(&args, 0, sizeof(args));
00191 
00192     args.application = const_cast<char*>(APP_STRING);
00193     args.client_library = const_cast<char*>(CLIB_STRING);
00194     memcpy(args.key, key, DHT_KEYLEN);
00195 
00196     // Note: to here, this function is identical to write()
00197 
00198     args.maxvals = 1;
00199 
00200     bamboo_get_res* res = bamboo_dht_proc_get_2(&args, p_node);
00201     if (res == NULL)
00202     {
00203         printf("TcaRegistry::read: get returned NULL\n");
00204         return false;
00205     }
00206 
00207     int n_values = res->values.values_len;
00208     
00209     if (n_values != 1)
00210     {
00211         // printf("TcaRegistry::read: get returned %d values\n", n_values);
00212         return false;
00213     }
00214 
00215     bamboo_value* p_val = &res->values.values_val[0];
00216 
00217     rr.link_addr_ = p_val->bamboo_value_val;
00218     printf("TcaRegistry::read: succeeded! value=%s\n", rr.link_addr_.c_str());
00219 
00220     return true;
00221 }
00222 
00223 
00224 /*
00225 // This version gets nodes by dns name -- inneficient because of dns
00226 // lookup, and also bad because the node in question may not be alive.
00227 CLIENT*
00228 TcaRegistry::get_node()
00229 {
00230     // Get next available node. We deliberately spread the load around
00231     // among all availabe nodes, and also tolerate missing nodes.
00232 
00233     CLIENT* p_node = NULL;
00234 
00235     for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
00236     {
00237         if (i == dht_nodes_.size()) i = 0;
00238         p_node = get_connection(dht_nodes_[i].c_str());
00239         if (p_node)
00240         {
00241             printf("TcaRegistry::get_node: using node %s\n",
00242                     dht_nodes_[i].c_str());
00243             last_node_ = i;
00244             break;
00245         }
00246     }
00247 
00248     return p_node;
00249 }
00250 */
00251 
00252 
00253 CLIENT*
00254 TcaRegistry::get_node()
00255 {
00256     // Get next available node. We deliberately spread the load around
00257     // among all availabe nodes, and also tolerate missing nodes.
00258     //
00259     // This version uses the addrs list which saves a dns lookup.
00260     // Also, the addrs list is only populated with the nodes that are alive
00261     // at startup, so there's less chance of failed attempts.
00262 
00263     CLIENT* p_node = NULL;
00264 
00265     for (unsigned int i = last_node_ + 1; i != last_node_; ++i)
00266     {
00267         if (i == dht_addrs_.size()) i = 0;
00268         p_node = get_connection(&dht_addrs_[i]);
00269         if (p_node)
00270         {
00271             last_node_ = i;
00272             break;
00273         }
00274     }
00275 
00276     return p_node;
00277 }
00278 
00279 
00280 

Generated on Fri Dec 22 14:48:01 2006 for DTN Reference Implementation by  doxygen 1.5.1