/** * Fill supplied value vector with all the DHT values we have under the key. * * This is an internal call, not the result of an external query, so no * statistics are updated. * * @param id the primary key of the value * @param valvec value vector where results are stored * @param valcnt size of value vector * * @return amount of values filled into valvec. The values are dynamically * created and must be freed by caller through dht_value_free(). */ int keys_get_all(const kuid_t *id, dht_value_t **valvec, int valcnt) { struct keyinfo *ki; struct keydata *kd; int i; int vcnt = valcnt; dht_value_t **vvec = valvec; g_assert(valvec); g_assert(valcnt > 0); ki = hikset_lookup(keys, id); if (ki == NULL) return 0; kd = get_keydata(id); if (kd == NULL) /* DB failure */ return 0; for (i = 0; i < kd->values && vcnt > 0; i++) { uint64 dbkey = kd->dbkeys[i]; dht_value_t *v; g_assert(0 != dbkey); v = values_get(dbkey, DHT_VT_ANY); if (v == NULL) continue; g_assert(kuid_eq(dht_value_key(v), id)); *vvec++ = v; vcnt--; } return vvec - valvec; /* Amount of entries filled */ }
int cmd_exec( REPLY *r, int argc, char **argv ) { char addrbuf[FULL_ADDSTRLEN+1]; time_t lifetime; int minutes; IP addrs[16]; int port; int count; static struct value_t *value; char *p; int rc = 0; if( argc == 0 ) { /* Print usage */ r_printf( r, cmd_usage ); if( r->allow_debug ) { r_printf( r, cmd_usage_debug ); } rc = 1; } else if( match( argv[0], "import" ) && argc == 2 ) { rc = cmd_import( r, argv[1] ); #if 0 } else if( match( argv[0], "lookup_node" ) && argc == 2 ) { /* Check searches for node */ rc = kad_lookup_node( argv[1], &addrs[0] ); if( rc == 0 ) { r_printf( r, "%s\n", str_addr( &addrs[0], addrbuf ) ); } else if( rc == 1 ) { r_printf( r ,"No search found.\n" ); rc = 1; } else if( rc == 2 ) { r_printf( r ,"Invalid id format. 20 digit hex string expected.\n" ); rc = 1; } else { rc = 1; } #endif } else if( match( argv[0], "lookup" ) && argc == 2 ) { size_t num = N_ELEMS(addrs); size_t i; /* Check searches for node */ rc = kad_lookup_value( argv[1], addrs, &num ); if( rc >= 0 && num > 0 ) { for( i = 0; i < num; ++i ) { r_printf( r, "%s\n", str_addr( &addrs[i], addrbuf ) ); } } else if( rc < 0 ) { r_printf( r ,"Some error occured.\n" ); rc = 1; } else if( rc == 0 ) { r_printf( r ,"Search in progress.\n" ); rc = 1; } else { r_printf( r ,"Search started.\n" ); rc = 1; } } else if( match( argv[0], "status" ) && argc == 1 ) { /* Print node id and statistics */ cmd_print_status( r ); } else if( match( argv[0], "announce" ) && (argc == 1 || argc == 2 || argc == 3) ) { if( argc == 1 ) { /* Announce all values; does not update value.refreshed */ count = 0; value = values_get(); while( value ) { kad_announce_once( value->id, value->port ); count++; value = value->next; } r_printf( r ,"%d announcements started.\n", count ); rc = 0; goto end; } else if( argc == 2 ) { minutes = 0; lifetime = 0; } else if( argc == 3 ) { minutes = atoi( argv[2] ); if( minutes < 0 ) { minutes = 0; lifetime = LONG_MAX; } else { /* Round up to multiple of 30 minutes */ minutes = (30 * (minutes/30 + 1)); lifetime = (time_now_sec() + (minutes * 60)); } } else { /* Make compilers happy */ exit( 1 ); } int is_random_port = 0; /* Find <id>:<port> delimiter */ p = strchr( argv[1], ':' ); if( p ) { *p = '\0'; port = port_parse( p + 1, -1 ); } else { /* A valid port will be choosen inside kad_announce() */ port = 0; is_random_port = 1; } if( kad_announce( argv[1], port, lifetime ) >= 0 ) { #ifdef FWD if( !is_random_port ) { forwardings_add( port, lifetime); } #endif if( lifetime == 0 ) { r_printf( r ,"Start single announcement now.\n" ); } else if( lifetime == LONG_MAX ) { r_printf( r ,"Start regular announcements for the entire run time (%sport %d).\n", (is_random_port ? "random " : ""), port ); } else { r_printf( r ,"Start regular announcements for %d minutes (%sport %d).\n", minutes, (is_random_port ? "random " : ""), port ); } } else { r_printf( r ,"Invalid port or query too long.\n" ); rc = 1; } } else if( match( argv[0], "blacklist" ) && argc == 2 ) { rc = cmd_blacklist( r, argv[1] ); } else if( match( argv[0], "export" ) && argc == 1 ) { rc = cmd_export( r ); } else if( match( argv[0], "list" ) && argc == 2 && r->allow_debug ) { if( gconf->is_daemon == 1 ) { r_printf( r ,"The 'list' command is not available while KadNode runs as daemon.\n" ); rc = 1; goto end; } else if( match( argv[1], "blacklist" ) ) { kad_debug_blacklist( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "buckets" ) ) { kad_debug_buckets( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "constants" ) ) { kad_debug_constants( STDOUT_FILENO ); rc = 0; #ifdef FWD } else if( match( argv[1], "forwardings" ) ) { forwardings_debug( STDOUT_FILENO ); rc = 0; #endif #ifdef AUTH } else if( match( argv[1], "pkeys" ) ) { auth_debug_pkeys( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "skeys" ) ) { auth_debug_skeys( STDOUT_FILENO ); rc = 0; #endif } else if( match( argv[1], "results" ) ) { results_debug( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "searches" ) ) { kad_debug_searches( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "storage" ) ) { kad_debug_storage( STDOUT_FILENO ); rc = 0; } else if( match( argv[1], "values" ) ) { values_debug( STDOUT_FILENO ); rc = 0; } else { dprintf( STDERR_FILENO, "Unknown argument.\n" ); rc = 1; } r_printf( r ,"\nOutput send to console.\n" ); } else { /* print usage */ r_printf( r, cmd_usage ); if( r->allow_debug ) { r_printf( r, cmd_usage_debug ); } rc = 1; } end: ; return rc; }
/** * Fill supplied value vector with the DHT values we have under the key that * match the specifications: among those bearing the specified secondary keys * (or all of them if no secondary keys are supplied), return only those with * the proper DHT value type. * * @param id the primary key of the value * @param type type of DHT value they want * @param secondary optional secondary keys * @param secondary_count amount of secondary keys supplied * @param valvec value vector where results are stored * @param valcnt size of value vector * @param loadptr where to write the average request load for key * @param cached if non-NULL, filled with whether key was cached * * @return amount of values filled into valvec. The values are dynamically * created and must be freed by caller through dht_value_free(). */ int keys_get(const kuid_t *id, dht_value_type_t type, kuid_t **secondary, int secondary_count, dht_value_t **valvec, int valcnt, float *loadptr, bool *cached) { struct keyinfo *ki; struct keydata *kd; int i; int vcnt = valcnt; dht_value_t **vvec = valvec; g_assert(secondary_count == 0 || secondary != NULL); g_assert(valvec); g_assert(valcnt > 0); g_assert(loadptr); ki = hikset_lookup(keys, id); g_assert(ki); /* If called, we know the key exists */ if (GNET_PROPERTY(dht_storage_debug) > 5) g_debug("DHT FETCH key %s (load = %g, current reqs = %u) type %s" " with %d secondary key%s", kuid_to_hex_string(id), ki->get_req_load, ki->get_requests, dht_value_type_to_string(type), secondary_count, plural(secondary_count)); *loadptr = ki->get_req_load; ki->get_requests++; kd = get_keydata(id); if (kd == NULL) /* DB failure */ return 0; /* * If secondary keys were requested, lookup them up and make sure * they have the right DHT type (or skip them). */ for (i = 0; i < secondary_count && vcnt > 0; i++) { uint64 dbkey = lookup_secondary(kd, secondary[i]); dht_value_t *v; if (0 == dbkey) continue; v = values_get(dbkey, type); if (v == NULL) continue; g_assert(kuid_eq(dht_value_key(v), id)); if (GNET_PROPERTY(dht_storage_debug) > 5) g_debug("DHT FETCH key %s via secondary key %s has matching %s", kuid_to_hex_string(id), kuid_to_hex_string2(secondary[i]), dht_value_to_string(v)); *vvec++ = v; vcnt--; } /* * Don't count secondary-key fetches in the local hit stats: in order to * be able to get these fetches, we must have initially provided the * list of these keys, and thus we have already traversed the code below * for that fetch, which accounted the hit already. */ if (secondary_count) { int n = vvec - valvec; /* Amount of entries filled */ gnet_stats_count_general(GNR_DHT_CLAIMED_SECONDARY_KEYS, n); if (ki->flags & DHT_KEY_F_CACHED) gnet_stats_count_general(GNR_DHT_CLAIMED_CACHED_SECONDARY_KEYS, n); goto done; } /* * No secondary keys specified. Look them all up. */ for (i = 0; i < kd->values && vcnt > 0; i++) { uint64 dbkey = kd->dbkeys[i]; dht_value_t *v; g_assert(0 != dbkey); v = values_get(dbkey, type); if (v == NULL) continue; g_assert(kuid_eq(dht_value_key(v), id)); if (GNET_PROPERTY(dht_storage_debug) > 5) g_debug("DHT FETCH key %s has matching %s", kuid_to_hex_string(id), dht_value_to_string(v)); *vvec++ = v; vcnt--; } /* * Stats update: we count all the hits, plus successful hits on keys * that do not fall within our k-ball, i.e. keys for which we act as * a "cache". Note that our k-ball frontier can evolve through time, * so we rely on the DHT_KEY_F_CACHED flag, positionned at creation time. */ if (vvec != valvec) { gnet_stats_inc_general(GNR_DHT_FETCH_LOCAL_HITS); if (ki->flags & DHT_KEY_F_CACHED) gnet_stats_inc_general(GNR_DHT_FETCH_LOCAL_CACHED_HITS); } done: if (cached) *cached = (ki->flags & DHT_KEY_F_CACHED) ? TRUE : FALSE; return vvec - valvec; /* Amount of entries filled */ }