00001 #ifndef CONNECTION_TABLE_IMPLEMENTATION_FILE
00002 #define CONNECTION_TABLE_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "connection.h"
00019 #include "connection_table.h"
00020
00021 #include <basis/istring.h>
00022 #include <basis/log_base.h>
00023 #include <basis/mutex.h>
00024 #include <data_struct/byte_hasher.h>
00025 #include <data_struct/int_hash.cpp>
00026 #include <textual/string_manipulation.h>
00027
00028 using namespace nodes;
00029
00030
00031
00032
00033 const int CTB_MAX_BITS = 10;
00034
00035
00036
00037 #undef AUTO_LOCK
00038 #define AUTO_LOCK auto_synchronizer l(*_connlock)
00039
00040 #undef LOG
00041 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00042
00044
00045 class conntab_hash : public int_hash<connection>
00046 {
00047 public:
00048 conntab_hash() : int_hash<connection>(CTB_MAX_BITS) {}
00049 };
00050
00052
00053 connection_table::connection_table(int heartbeats_until_expiration,
00054 int freshness_period, int ghost_period)
00055 : _connection_list(new conntab_hash),
00056 _connlock(new mutex),
00057 _heartbeats_until_expiration(heartbeats_until_expiration),
00058 _freshness_period(freshness_period),
00059 _ghost_period(ghost_period)
00060 {}
00061
00062 connection_table::~connection_table()
00063 {
00064 WHACK(_connlock);
00065 WHACK(_connection_list);
00066 }
00067
00068 int connection_table::connections_on_primary(const transport_id &real_id,
00069 const transport_id &ignored_link_id, int primary_id)
00070 { return count_users(real_id, ignored_link_id, primary_id, PRIMARY_ID); }
00071
00072 void connection_table::complain_missing_connection
00073 (const connection_id &conn_id, const istring &where) const
00074 {
00075 istring to_print = timestamp(true, true) + where
00076 + istring(istring::SPRINTF, "connection %d cannot be found.",
00077 conn_id.raw_id());
00078 EMERGENCY_LOG(program_wide_logger(), to_print);
00079 }
00080
00081 connection_id connection_table::find_state(const transport_id &real_id,
00082 connection::states to_find, int low_level)
00083 {
00084 FUNCDEF("find_state");
00085 if (!real_id) return 0;
00086 AUTO_LOCK;
00087 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00088 int curr_id = _connection_list->ids()[i];
00089 connection *conn = _connection_list->find(curr_id);
00090 if (conn && conn->alive && (conn->real_transport_id == real_id)
00091 && (conn->state() == to_find) ) {
00092
00093 if (negative(low_level)) return conn->conn_id();
00094
00095 if (conn->low_level[PRIMARY_ID] == low_level) return conn->conn_id();
00096 }
00097 }
00098 return 0;
00099 }
00100
00101 bool connection_table::connected(const connection_id &conn_id)
00102 {
00103 FUNCDEF("connected");
00104 if (!conn_id) return false;
00105 AUTO_LOCK;
00106 connection *conn = _connection_list->find(conn_id.raw_id());
00107 if (!conn) return false;
00108 return conn->connected();
00109 }
00110
00111 bool connection_table::transport_connected(const transport_id &tran_id)
00112 {
00113 FUNCDEF("transport_connected");
00114 if (!tran_id) return false;
00115 bool connected = false;
00116 AUTO_LOCK;
00117 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00118 int curr_id = _connection_list->ids()[i];
00119 connection *conn = _connection_list->find(curr_id);
00120 if (!conn) continue;
00121
00122 if (conn->alive && (conn->real_transport_id == tran_id)
00123 && conn->connected()) {
00124 connected = true;
00125 break;
00126 } else if (conn->alive && (conn->local_transport_id == tran_id)
00127 && conn->connected()) {
00128 connected = true;
00129 break;
00130 }
00131 }
00132 return connected;
00133 }
00134
00135 bool connection_table::live(const connection_id &conn_id)
00136 {
00137 FUNCDEF("live");
00138 if (!conn_id) return false;
00139 AUTO_LOCK;
00140 connection *conn = _connection_list->find(conn_id.raw_id());
00141 if (!conn) return false;
00142 return conn->alive;
00143 }
00144
00145 bool connection_table::reset_time(const connection_id &conn_id)
00146 {
00147 FUNCDEF("reset_time");
00148 if (!conn_id) return false;
00149 AUTO_LOCK;
00150 connection *conn = _connection_list->find(conn_id.raw_id());
00151 if (!conn) return false;
00152 conn->liveness.kabump();
00153 return true;
00154 }
00155
00156 heartbeat connection_table::liveness(const connection_id &conn_id)
00157 {
00158 if (!conn_id) return heartbeat(0, 0);
00159 AUTO_LOCK;
00160 connection *conn = _connection_list->find(conn_id.raw_id());
00161 if (!conn) return heartbeat(0, 0);
00162 return conn->liveness;
00163 }
00164
00165 bool connection_table::set_liveness(const connection_id &conn_id,
00166 const heartbeat &new_liveness)
00167 {
00168 if (!conn_id) return false;
00169 AUTO_LOCK;
00170 connection *conn = _connection_list->find(conn_id.raw_id());
00171 if (!conn) return false;
00172 conn->liveness = new_liveness;
00173 return true;
00174 }
00175
00176 bool connection_table::record_request(const connection_id &conn_id)
00177 {
00178 FUNCDEF("record_request");
00179 if (!conn_id) return false;
00180 AUTO_LOCK;
00181 connection *conn = _connection_list->find(conn_id.raw_id());
00182 if (!conn) return false;
00183 conn->liveness.made_request();
00184 return true;
00185 }
00186
00187 connection_id connection_table::find_linked(sides side,
00188 const transport_id &tran_id)
00189 {
00190 if (!tran_id) return 0;
00191 AUTO_LOCK;
00192 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00193 int curr_id = _connection_list->ids()[i];
00194 connection *conn = _connection_list->find(curr_id);
00195 if (conn && conn->alive
00196 && ( ((side == REMOTE_LINK) && (conn->remote_transport_id == tran_id))
00197 || ((side == LOCAL_LINK) && (conn->local_transport_id == tran_id))
00198 || ((side == LOCAL_REAL) && (conn->real_transport_id == tran_id)))) {
00199 connection_id found = conn->conn_id();
00200 return found;
00201 }
00202 }
00203
00204 return 0;
00205 }
00206
00207 connection_id connection_table::find_low_level
00208 (network_address::address_type type, int low_level_id, int index)
00209 {
00210 FUNCDEF("find_low_level");
00211 AUTO_LOCK;
00212 if (!low_level_id) return 0;
00213
00214 if (index < 0) index = 0;
00215 if (index > 1) index = 1;
00216 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00217 int curr_id = _connection_list->ids()[i];
00218 connection *conn = _connection_list->find(curr_id);
00219 if (conn && conn->alive && (conn->remote_host.type() == type)
00220 && (conn->low_level[index] == low_level_id) )
00221 return conn->conn_id();
00222 }
00223 return 0;
00224 }
00225
00226 connection_id connection_table::find_destination(const transport_id &real_id,
00227 const network_address &destination)
00228 {
00229 FUNCDEF("find [id/destination]");
00230 if (!real_id) return 0;
00231 AUTO_LOCK;
00232 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00233 int curr_id = _connection_list->ids()[i];
00234 connection *conn = _connection_list->find(curr_id);
00235 if (conn && (conn->remote_host == destination)
00236 && (conn->real_transport_id == real_id)
00237 && conn->alive) {
00238 connection_id found = conn->conn_id();
00239 return found;
00240 }
00241 }
00242 return 0;
00243 }
00244
00245 int connection_table::get_low_level_id(const transport_id &real_id, int index)
00246 {
00247 FUNCDEF("get_low_level_id");
00248 AUTO_LOCK;
00249 if (!real_id) return 0;
00250
00251 if (index < 0) index = 0;
00252 if (index > 1) index = 1;
00253 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00254 int curr_id = _connection_list->ids()[i];
00255 connection *conn = _connection_list->find(curr_id);
00256 if (conn && conn->connected()
00257 && (conn->real_transport_id == real_id)
00258 && conn->alive) {
00259 int found = conn->low_level[index];
00260 return found;
00261 }
00262 }
00263 return 0;
00264 }
00265
00266 bool connection_table::owns_connection(const connection_id &conn_id,
00267 const transport_id &link_id)
00268 {
00269 FUNCDEF("owns_connection");
00270 AUTO_LOCK;
00271 connection to_fill;
00272 if (!find(conn_id.raw_id(), to_fill)) return false;
00273 return to_fill.local_transport_id == link_id;
00274 }
00275
00276 int connection_table::count_users(const transport_id &real_id,
00277 const transport_id &ignored_link_id, int low_level_id, int index)
00278 {
00279 FUNCDEF("count_users");
00280 AUTO_LOCK;
00281
00282 if (!low_level_id) return 0;
00283 if (!real_id) return 0;
00284 if (index < 0) index = 0;
00285 if (index > 1) index = 1;
00286 int users_counted = 0;
00287 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00288 int curr_id = _connection_list->ids()[i];
00289 connection *conn = _connection_list->find(curr_id);
00290 if (conn && conn->alive && (conn->real_transport_id == real_id)
00291 && (conn->low_level[index] == low_level_id)
00292 && (conn->state() != connection::DISCONNECTED)
00293 && (conn->local_transport_id != ignored_link_id) )
00294 users_counted++;
00295 }
00296 return users_counted;
00297 }
00298
00299 connection_id connection_table::update(const connection &to_update)
00300 {
00301 FUNCDEF("update");
00302 if (!to_update.conn_id()) return 0;
00303 AUTO_LOCK;
00304 connection *conn = _connection_list->find(to_update.conn_id().raw_id());
00305 if (!conn) {
00306 FUNCTION(func);
00307 complain_missing_connection(to_update.conn_id(), function_name);
00308 return 0;
00309 }
00310 *conn = to_update;
00311 return to_update.conn_id();
00312 }
00313
00314
00315
00316
00317
00318 bool connection_table::find(const connection_id &conn_id, connection &to_fill)
00319 {
00320 FUNCDEF("find [id/conn]");
00321 to_fill = connection();
00322 if (!conn_id) return false;
00323 AUTO_LOCK;
00324 connection *conn = _connection_list->find(conn_id.raw_id());
00325 if (!conn) return false;
00326 if (conn->alive) {
00327 to_fill = *conn;
00328 return true;
00329 }
00330 return false;
00331 }
00332
00333 connection_id connection_table::add(const connection &to_add_in)
00334 {
00335 FUNCDEF("add");
00336 AUTO_LOCK;
00337 connection to_add = to_add_in;
00338 if (!to_add.conn_id()) {
00339 LOG("no id was assigned for connection; failing it.");
00340 return 0;
00341 }
00342 to_add.alive = true;
00343 to_add.liveness = heartbeat(_heartbeats_until_expiration, _freshness_period);
00344 connection_id found = find_linked(LOCAL_LINK, to_add.local_transport_id);
00345 if (!found) {
00346
00347 to_add.state(connection::DISCONNECTED);
00348
00349 connection *the_conn = new connection(to_add);
00350 _connection_list->add(the_conn->conn_id().raw_id(), the_conn);
00351
00352 } else {
00353 #ifdef DEBUG_CONNECTION_TABLE
00354 LOG(istring(istring::SPRINTF, "found existing connection %d!", found));
00355 #endif
00356 return 0;
00357 }
00358 return to_add.conn_id();
00359 }
00360
00361 bool connection_table::zap(const connection_id &conn_id)
00362 {
00363 FUNCDEF("zap");
00364 if (!conn_id) return false;
00365 AUTO_LOCK;
00366 connection *conn = _connection_list->find(conn_id.raw_id());
00367 if (!conn) return false;
00368 conn->alive = false;
00369 conn->liveness = heartbeat(_heartbeats_until_expiration,
00370 _ghost_period / _heartbeats_until_expiration);
00371 return true;
00372 }
00373
00374 void connection_table::clear_dead()
00375 {
00376 FUNCDEF("clear_dead");
00377 AUTO_LOCK;
00378 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00379 int curr_id = _connection_list->ids()[i];
00380 connection *conn = _connection_list->find(curr_id);
00381
00382 if (!conn) continue;
00383
00384
00385
00386
00387 if (!conn->alive) {
00388 if (conn->liveness.dead()) {
00389
00390 #ifdef DEBUG_CONNECTION_TABLE
00391 LOG(istring(istring::SPRINTF, "clearing out stale, dead "
00392 "connection %d.", conn->conn_id()));
00393 #endif
00394 _connection_list->zap(curr_id);
00395 i--;
00396 } else if (conn->liveness.due()) {
00397 #ifdef DEBUG_CONNECTION_TABLE
00398 LOG(istring(istring::SPRINTF, "making new heartbeat request on "
00399 "connection %d.", curr_id));
00400 #endif
00401 conn->liveness.made_request();
00402 }
00403 }
00404 }
00405 }
00406
00407 void connection_table::show_connections(istring &output, int indentation,
00408 bool alive_only)
00409 {
00410 AUTO_LOCK;
00411 istring indent = string_manipulation::indentation(indentation);
00412 bool any_printed = false;
00413 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00414 int curr_id = _connection_list->ids()[i];
00415 connection *conn = _connection_list->find(curr_id);
00416 if (conn && (!alive_only || conn->alive) ) {
00417 output += indent + conn->text_form() + log_base::platform_ending();
00418 any_printed = true;
00419 }
00420 }
00421 if (!any_printed)
00422 output += indent + istring("No connections exist.")
00423 + log_base::platform_ending();
00424 }
00425
00426 bool connection_table::set_conn_state(const transport_id &tran_id,
00427 connection::states state)
00428 {
00429 FUNCDEF("set_conn_state");
00430 if (!tran_id) return false;
00431 AUTO_LOCK;
00432 connection_id found = find_linked(LOCAL_LINK, tran_id);
00433 if (!found) return false;
00434 connection *conn = _connection_list->find(found.raw_id());
00435 if (!conn) return false;
00436 bool to_return = false;
00437 if (conn->alive) {
00438 conn->state(state);
00439 to_return = true;
00440 if (state == connection::DISCONNECTED)
00441 conn->low_level[PRIMARY_ID] = 0;
00442 }
00443 return to_return;
00444 }
00445
00446 int connection_table::set_conn_states(const transport_id &real_id,
00447 connection::states state)
00448 {
00449 FUNCDEF("set_conn_states");
00450 AUTO_LOCK;
00451 int conns_processed = 0;
00452 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00453 int curr_id = _connection_list->ids()[i];
00454 connection *conn = _connection_list->find(curr_id);
00455 if (conn && (conn->real_transport_id == real_id)) {
00456 conn->state(state);
00457 conns_processed++;
00458 }
00459 }
00460 return conns_processed;
00461 }
00462
00463 connection::states connection_table::get_conn_state(const transport_id &tran_id)
00464 {
00465 FUNCDEF("get_conn_state");
00466 connection::states to_return = connection::DISCONNECTED;
00467 if (!tran_id) return to_return;
00468 AUTO_LOCK;
00469 connection_id found = find_linked(LOCAL_LINK, tran_id);
00470 if (!found) return to_return;
00471 connection *conn = _connection_list->find(found.raw_id());
00472 if (!conn) return to_return;
00473 if (conn->alive)
00474 to_return = conn->state();
00475 return to_return;
00476 }
00477
00478 transport_id connection_table::socket_to_real_transport
00479 (network_address::address_type type, int socket, transport_id &linked_id)
00480 {
00481 FUNCDEF("socket_to_real_transport");
00482 AUTO_LOCK;
00483 linked_id = 0;
00484 bool is_linked;
00485 connection_id conn_id_found = find_low_level(type, socket, PRIMARY_ID);
00486 if (conn_id_found.raw_id()) is_linked = true;
00487 else {
00488
00489 is_linked = false;
00490 conn_id_found = find_low_level(type, socket, SECONDARY_ID);
00491 if (!conn_id_found) {
00492 #ifdef DEBUG_CONNECTION_TABLE
00493 LOG(istring(istring::SPRINTF, "can't find connection for "
00494 "socket %d in primary or secondary low-level ids; "
00495 "failing out.", socket));
00496 #endif
00497 return 0;
00498 }
00499 }
00500
00501 GET_CONN_ENTRY((*this), conn_id_found);
00502 if (!conn_found) return 0;
00503
00504
00505 if (is_linked) linked_id = conn_entry.local_transport_id;
00506
00507 return conn_entry.real_transport_id;
00508 }
00509
00510 int_set connection_table::find_related_conns(int low_level_primary,
00511 int real_transport)
00512 {
00513 FUNCDEF("find_related_conns");
00514 AUTO_LOCK;
00515 if (!low_level_primary) return int_set();
00516 if (!real_transport) return int_set();
00517 int_set to_return;
00518 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00519 int curr_id = _connection_list->ids()[i];
00520 connection *conn = _connection_list->find(curr_id);
00521 if (conn && conn->alive && (conn->real_transport_id == real_transport)
00522 && (conn->low_level[PRIMARY_ID] == low_level_primary) )
00523 to_return += curr_id;
00524 }
00525 return to_return;
00526 }
00527
00528 int_set connection_table::find_live_reals()
00529 {
00530 FUNCDEF("find_live_reals");
00531 AUTO_LOCK;
00532 int_set to_return;
00533 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00534 int curr_id = _connection_list->ids()[i];
00535 connection *conn = _connection_list->find(curr_id);
00536 if (conn && conn->alive) to_return += conn->real_transport_id.raw_id();
00537 }
00538 return to_return;
00539 }
00540
00541 connection_id connection_table::find_dupe(int real_transport,
00542 int low_level_primary, const network_address &sender,
00543 int other_side_transport)
00544 {
00545 FUNCDEF("find_dupe");
00546 AUTO_LOCK;
00547 for (int i = 0; i < _connection_list->ids().elements(); i++) {
00548 int curr_id = _connection_list->ids()[i];
00549 connection *conn = _connection_list->find(curr_id);
00550 if (conn && conn->alive) {
00551 if ( (conn->low_level[PRIMARY_ID] == low_level_primary)
00552 && (conn->real_transport_id == real_transport)
00553 && (conn->remote_host == sender)
00554 && (conn->remote_transport_id == other_side_transport) )
00555 return conn->conn_id();
00556 }
00557 }
00558 return 0;
00559 }
00560
00561
00562 #endif //CONNECTION_TABLE_IMPLEMENTATION_FILE
00563