/* * Lookup known nodes that are nearest to the given id. */ int kad_lookup_value( const char query[], IP addr_array[], size_t *addr_num ) { char hexbuf[SHA1_HEX_LENGTH+1]; UCHAR id[SHA1_BIN_LENGTH]; int rc; /* Generate the id, e.g. id = sha1(query) */ id_compute( id, query ); log_debug( "KAD: Lookup '%s' as '%s'.", query, str_id( id, hexbuf ) ); dht_lock(); rc = results_collect( id, addr_array, *addr_num ); if( rc < 0 ) { /* No results item found - no search in progress - start search */ dht_lock(); results_add( id, query ); dht_search( id, 0, gconf->af, dht_callback_func, NULL ); dht_unlock(); *addr_num = 0; rc = -1; } else { *addr_num = rc; rc = 0; } dht_unlock(); return rc; }
/* Handle incoming packets and pass them to the DHT code */ void dht_handler( int rc, int sock ) { UCHAR buf[1500]; IP from; socklen_t fromlen; time_t time_wait = 0; if( rc > 0 ) { /* Check which socket received the data */ fromlen = sizeof(from); rc = recvfrom( sock, buf, sizeof(buf) - 1, 0, (struct sockaddr*) &from, &fromlen ); if( rc <= 0 || rc >= sizeof(buf) ) { return; } /* The DHT code expects the message to be null-terminated. */ buf[rc] = '\0'; /* Handle incoming data */ dht_lock(); rc = dht_periodic( buf, rc, (struct sockaddr*) &from, fromlen, &time_wait, dht_callback_func, NULL ); dht_unlock(); if( rc < 0 && errno != EINTR ) { if( rc == EINVAL || rc == EFAULT ) { log_err( "DHT: Error calling dht_periodic." ); } g_dht_maintenance = time_now_sec() + 1; } else { g_dht_maintenance = time_now_sec() + time_wait; } } else if( g_dht_maintenance <= time_now_sec() ) { /* Do a maintenance call */ dht_lock(); rc = dht_periodic( NULL, 0, NULL, 0, &time_wait, dht_callback_func, NULL ); dht_unlock(); /* Wait for the next maintenance call */ g_dht_maintenance = time_now_sec() + time_wait; log_debug( "DHT: Next maintenance call in %u seconds.", (unsigned int) time_wait ); } else { rc = 0; } if( rc < 0 ) { if( errno == EINTR ) { return; } else if( rc == EINVAL || rc == EFAULT ) { log_err( "DHT: Error using select: %s", strerror( errno ) ); return; } else { g_dht_maintenance = time_now_sec() + 1; } } }
/* Print announced ids we have received */ void kad_debug_storage( int fd ) { char addrbuf[FULL_ADDSTRLEN+1]; char hexbuf[SHA1_HEX_LENGTH+1]; struct storage *s = storage; IP addr; int i, j; dht_lock(); for( j = 0; s != NULL; ++j ) { dprintf( fd, "Id: %s\n", str_id(s->id, hexbuf )); for( i = 0; i < s->numpeers; ++i ) { struct peer* p = &s->peers[i]; if( p->len == 16 ) { IP6 *a = (IP6 *) &addr; a->sin6_family = AF_INET6; a->sin6_port = htons( p->port ); memcpy( &a->sin6_addr, p->ip, 16 ); } else { IP4 *a = (IP4 *) &addr; a->sin_family = AF_INET; a->sin_port = htons( p->port ); memcpy( &a->sin_addr, p->ip, 4 ); } dprintf( fd, " Peer: %s\n", str_addr( &addr, addrbuf) ); } dprintf( fd, " Found %d peers.\n", i ); s = s->next; } dprintf( fd, " Found %d stored hashes from received announcements.\n", j ); dht_unlock(); }
/* Print searches */ void kad_debug_searches( int fd ) { char addrbuf[FULL_ADDSTRLEN+1]; char hexbuf[SHA1_HEX_LENGTH+1]; struct search *s = searches; int i, j; dht_lock(); for( j = 0; s != NULL; ++j ) { dprintf( fd, " Search: %s\n", str_id( s->id, hexbuf ) ); dprintf( fd, " af: %s\n", (s->af == AF_INET) ? "AF_INET" : "AF_INET6" ); dprintf( fd, " port: %hu\n", s->port ); dprintf( fd, " done: %d\n", s->done ); for(i = 0; i < s->numnodes; ++i) { struct search_node *sn = &s->nodes[i]; dprintf( fd, " Node: %s\n", str_id(sn->id, hexbuf ) ); dprintf( fd, " addr: %s\n", str_addr( &sn->ss, addrbuf ) ); dprintf( fd, " pinged: %d\n", sn->pinged ); dprintf( fd, " replied: %d\n", sn->replied ); dprintf( fd, " acked: %d\n", sn->acked ); } dprintf( fd, " Found %d nodes.\n", i ); s = s->next; } dprintf( fd, " Found %d searches.\n", j ); dht_unlock(); }
/* Print buckets (leaf/finger table) */ void kad_debug_buckets( int fd ) { char addrbuf[FULL_ADDSTRLEN+1]; char hexbuf[SHA1_HEX_LENGTH+1]; struct bucket *b; struct node *n; int i, j; dht_lock(); b = (gconf->af == AF_INET) ? buckets : buckets6; for( j = 0; b != NULL; ++j ) { dprintf( fd, " Bucket: %s\n", str_id( b->first, hexbuf ) ); n = b->nodes; for( i = 0; n != NULL; ++i ) { dprintf( fd, " Node: %s\n", str_id( n->id, hexbuf ) ); dprintf( fd, " addr: %s\n", str_addr( &n->ss, addrbuf ) ); dprintf( fd, " pinged: %d\n", n->pinged ); n = n->next; } dprintf( fd, " Found %d nodes.\n", i ); b = b->next; } dprintf( fd, " Found %d buckets.\n", j ); dht_unlock(); }
int kad_export_nodes( IP addr_array[], size_t *num ) { IP4 addr4[64]; IP6 addr6[64]; int num4; int num6; int i, count; num6 = N_ELEMS( addr6 ); num4 = N_ELEMS( addr4 ); dht_lock(); dht_get_nodes( addr4, &num4, addr6, &num6 ); dht_unlock(); count = 0; for( i = 0; i < num6 && count < *num; ++i, ++count ) { memcpy( &addr_array[i], &addr6[i], sizeof(IP6) ); } for( i = 0; i < num4 && count < *num; ++i, ++count ) { memcpy( &addr_array[i], &addr4[i], sizeof(IP4) ); } /* Store number of nodes we have actually found */ *num = count; return 0; }
/* * Lookup the address of the node that has the given id. * The port refers to the kad instance. */ int kad_lookup_node( const char query[], IP *addr_return ) { UCHAR id[SHA1_BIN_LENGTH]; struct search *sr; int i, rc; /* That is the node id to lookup */ id_compute( id, query ); dht_lock(); rc = -1; sr = searches; while( sr ) { if( sr->af == gconf->af && id_equal( sr->id, id ) ) { for( i = 0; i < sr->numnodes; ++i ) { if( id_equal( sr->nodes[i].id, id ) ) { memcpy( addr_return, &sr->nodes[i].ss, sizeof(IP) ); rc = 0; goto done; } } break; } sr = sr->next; } done:; dht_unlock(); return rc; }
/* Print announced ids we have received */ void kad_debug_storage( int fd ) { char addrbuf[FULL_ADDSTRLEN+1]; char hexbuf[SHA1_HEX_LENGTH+1]; struct storage *s; struct peer* p; IP addr; int i, j; dht_lock(); s = storage; for( j = 0; s != NULL; ++j ) { dprintf( fd, " ID: %s\n", str_id(s->id, hexbuf )); for( i = 0; i < s->numpeers; ++i ) { p = &s->peers[i]; to_addr( &addr, &p->ip, p->len, htons( p->port ) ); dprintf( fd, " Peer: %s\n", str_addr( &addr, addrbuf) ); } dprintf( fd, " Found %d peers.\n", i ); s = s->next; } dprintf( fd, " Found %d stored hashes from received announcements.\n", j ); dht_unlock(); }
/* * Lookup the address of the node that has the given id. * The port refers to the kad instance. */ int kad_lookup_node( const char query[], IP *addr_return ) { UCHAR id[SHA1_BIN_LENGTH]; struct search *sr; int i, rc; if( strlen( query ) != SHA1_HEX_LENGTH || !str_isHex( query, SHA1_HEX_LENGTH ) ) { return -1; } bytes_from_hex( id, query, SHA1_HEX_LENGTH ); dht_lock(); rc = 1; sr = searches; while( sr ) { if( sr->af == gconf->af && id_equal( sr->id, id ) ) { for( i = 0; i < sr->numnodes; ++i ) { if( id_equal( sr->nodes[i].id, id ) ) { memcpy( addr_return, &sr->nodes[i].ss, sizeof(IP) ); rc = 0; goto done; } } break; } sr = sr->next; } done:; dht_unlock(); return rc; }
int kad_blacklist( const IP* addr ) { dht_lock(); blacklist_node( NULL, (struct sockaddr *) addr, sizeof(IP) ); dht_unlock(); return 0; }
int kad_ping( const IP* addr ) { int rc; dht_lock(); rc = dht_ping_node( (struct sockaddr *)addr, addr_len( addr ) ); dht_unlock(); return (rc < 0) ? -1 : 0; }
/* * Lookup known nodes that are nearest to the given id. */ int kad_lookup_value( const char _query[], IP addr_array[], size_t *addr_num ) { char query[QUERY_MAX_SIZE]; struct results_t *results; int is_new; int rc; if( query_sanitize( query, sizeof(query), _query ) != 0 ) { return -2; } log_debug( "KAD: Lookup string: %s", query ); dht_lock(); /* Find existing or create new item */ results = results_add( query, &is_new ); if( results && is_new ) { /* Search own announced values */ kad_lookup_local_values( results ); } if( results == NULL ) { /* Failed to create a new search */ rc = -1; } else if( results->done ) { /* * The search exists already but has finished. Restart the search when * no results have been found or more than half of the searches lifetime * has expired. */ if( results_entries_count( results ) == 0 || (time_now_sec() - results->start_time) > (MAX_SEARCH_LIFETIME / 2) ) { /* Mark search as in progress */ results_done( results, 0 ); /* Start another search for this id */ dht_search( results->id, 0, gconf->af, dht_callback_func, NULL ); } rc = 2; } else if( is_new ) { /* Start a new DHT search */ dht_search( results->id, 0, gconf->af, dht_callback_func, NULL ); rc = 1; } else { /* Search is still running */ rc = 0; } /* Collect addresses to be returned */ *addr_num = results_collect( results, addr_array, *addr_num ); dht_unlock(); return rc; }
/* * Find nodes that are near the given id and announce to them * that this node can satisfy the given id on the given port */ int kad_announce( const UCHAR *id, int port ) { if( port < 1 || port > 65535 ) { return -1; } dht_lock(); dht_search( id, port, gconf->af, dht_callback_func, NULL ); dht_unlock(); return 0; }
void kad_debug_blacklist( int fd ) { char addrbuf[FULL_ADDSTRLEN+1]; int i; dht_lock(); for( i = 0; i < (next_blacklisted % DHT_MAX_BLACKLISTED); i++ ) { dprintf( fd, " %s\n", str_addr( &blacklist[i], addrbuf ) ); } dprintf( fd, " Found %d blacklisted addresses.\n", i ); dht_unlock(); }
/* Export known nodes; the maximum is 200 nodes */ int kad_export_nodes( IP addr_array[], size_t *num ) { IP4 *addr4; IP6 *addr6; int num4; int num6; int i; if( gconf->af == AF_INET6 ) { num6 = MIN(*num, 200); addr6 = calloc( num6, sizeof(IP6) ); num4 = 0; addr4 = NULL; } else { num6 = 0; addr6 = NULL; num4 = MIN(*num, 200); addr4 = calloc( num4, sizeof(IP4) ); } dht_lock(); dht_get_nodes( addr4, &num4, addr6, &num6 ); dht_unlock(); if( gconf->af == AF_INET6 ) { for( i = 0; i < num6; ++i ) { memcpy( &addr_array[i], &addr6[i], sizeof(IP6) ); } free( addr6 ); } else { for( i = 0; i < num4; ++i ) { memcpy( &addr_array[i], &addr4[i], sizeof(IP4) ); } free( addr4 ); } /* Store number of nodes we have actually found */ *num = i; return 0; }