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