void a_mapcache_add ( GdkPixbuf *pixbuf, mapcache_extra_t extra, gint x, gint y, gint z, guint16 type, gint zoom, guint8 alpha, gdouble xshrinkfactor, gdouble yshrinkfactor, const gchar* name ) { guint nn = name ? g_str_hash ( name ) : 0; gchar *key = g_strdup_printf ( HASHKEY_FORMAT_STRING, type, x, y, z, zoom, nn, alpha, xshrinkfactor, yshrinkfactor ); g_mutex_lock(mc_mutex); cache_add(key, pixbuf, extra); // TODO: that should be done on preference change only... max_cache_size = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "mapcache_size")->u * 1024 * 1024; if ( cache_size > max_cache_size ) { if ( queue_tail ) { gchar *oldkey = list_shift_add_entry ( key ); cache_remove(oldkey); while ( cache_size > max_cache_size && (queue_tail->next != queue_tail) ) { /* make sure there's more than one thing to delete */ oldkey = list_shift (); cache_remove(oldkey); } } /* chop off 'start' etc */ } else { list_add_entry ( key ); /* business as usual */ } g_mutex_unlock(mc_mutex); static int tmp = 0; if ( (++tmp == 100 )) { g_debug("DEBUG: cache count=%d size=%u list count=%d\n", g_hash_table_size(cache), cache_size, queue_count ); tmp=0; } }
void a_mapcache_add ( GdkPixbuf *pixbuf, gint x, gint y, gint z, guint8 type, guint zoom, guint8 alpha, gdouble xshrinkfactor, gdouble yshrinkfactor ) { gchar *key = g_strdup_printf ( HASHKEY_FORMAT_STRING, x, y, z, type, zoom, alpha, xshrinkfactor, yshrinkfactor ); static int tmp = 0; g_mutex_lock(mc_mutex); cache_add(key, pixbuf); // TODO: that should be done on preference change only... max_queue_size = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "mapcache_size")->u * 1024 * 1024; if ( queue_size > max_queue_size ) { gchar *oldkey = list_shift_add_entry ( key ); cache_remove(oldkey); while ( queue_size > max_queue_size && (queue_tail->next != queue_tail) ) { /* make sure there's more than one thing to delete */ oldkey = list_shift (); cache_remove(oldkey); } /* chop off 'start' etc */ } else { list_add_entry ( key ); /* business as usual */ } g_mutex_unlock(mc_mutex); if ( (++tmp == 100 )) { g_print("DEBUG: queue count=%d size=%u\n", queue_count, queue_size ); tmp=0; } }
bool mule_file_add_source( MULE_FILE* mf, uint8_t type, UINT128* id, uint32_t ip4_no, uint16_t tcp_port_no, uint16_t udp_port_no, uint8_t cipher_opts ) { bool result = false; MULE_SOURCE* msc = NULL; do { // [TODO] one file source can be attached to multiple kad files. if (!mf) break; if (!mule_source_create(type, id, ip4_no, tcp_port_no, udp_port_no, cipher_opts, &msc)){ LOG_ERROR("Failed to create mule source."); break; } mule_source_add_type(msc, MULE_SOURCE_FLAG_FILE_BOUND); if(!list_add_entry(&mf->sources, (void*)msc)){ LOG_ERROR("Failed to add source to sources list."); break; } result = true; } while (false); if (!result && msc) mule_source_destroy(msc); return result; }
bool mule_file_part_get_block_to_download( MULE_FILE_PART* mfp, uint32_t pref_blk_len, uint64_t* block_start_out, uint64_t* block_len_out ) { bool result = false; MULE_FILE_PART_BLOCK* mfpb = NULL; uint64_t offset_from_start = 0; uint64_t part_start = 0; uint64_t block_start = 0; uint64_t block_len = 0; bool found = false; do { if (!mfp || !block_start_out || !block_len_out) break; part_start = mfp->start; LOG_DEBUG("part_start = %.8x", (uint32_t)part_start); LIST_EACH_ENTRY_WITH_DATA_BEGIN(mfp->blocks, e, mfpb); LOG_DEBUG("block_start = %.8x, block_len = %.8x, block_recvd = %.8x, block_state = %.8x", (uint32_t)(part_start + offset_from_start), (uint32_t)mfpb->len, (uint32_t)mfpb->recvd, (uint32_t)mfpb->state ); if (mfpb->state == MULE_FILE_BLOCK_STATE_ALLOCATED){ // Block state remain allocated in case of this part being not available on remote source. // Can also be allocated when download was canceled and block was not fully downloaded. block_start = part_start + offset_from_start; block_len = mfpb->len; mfpb->state = MULE_FILE_BLOCK_STATE_DOWNLOADING; LOG_DEBUG("Already allocated block %.8x:%.8x", (uint32_t)block_start, (uint32_t)block_len); found = true; break; } offset_from_start += mfpb->len; LIST_EACH_ENTRY_WITH_DATA_END(e); if (!found){ LOG_DEBUG("offset_from_start = %.8x", offset_from_start); block_start = part_start + offset_from_start; block_len = ((mfp->length - offset_from_start) < pref_blk_len)?(mfp->length - offset_from_start):pref_blk_len; LOG_DEBUG("Next allocated block: %.8x:%.8x", (uint32_t)block_start, (uint32_t)block_len); if (!block_len) break; // In original source DebugBreak() used instead of break, probably for catching errors. mfpb = (MULE_FILE_PART_BLOCK*)mem_alloc(sizeof(MULE_FILE_PART_BLOCK) - 1 + (uint32_t)block_len); if (!mfpb){ LOG_ERROR("Failed to allocate memory for kad file part block."); break; } mfpb->state = MULE_FILE_BLOCK_STATE_DOWNLOADING; mfpb->len = (uint32_t) block_len; list_add_entry(&mfp->blocks, (void*)mfpb); } *block_start_out = block_start; *block_len_out = block_len; result = true; } while (false); return result; }
bool mule_file_init_parts( MULE_FILE* kf, uint64_t size, bool full ) { bool result = false; MULE_FILE_PART* part = NULL; uint32_t rem_file_size = 0; do { kf->part_size = MULE_FILE_PART_SIZE; // Real parts count kf->part_count = (uint32_t) ((size + MULE_FILE_PART_SIZE - 1) / MULE_FILE_PART_SIZE); kf->part_hashes_needed = kf->part_count > 1; // Parts for OP_FILESTATUS kf->e2k_part_count = (uint32_t)(size / MULE_FILE_PART_SIZE + 1); // Parts for OP_HASHSETANSWER; kf->e2k_part_hash_count = (uint32_t)(size / MULE_FILE_PART_SIZE); if (kf->e2k_part_hash_count) kf->e2k_part_hash_count++; LOG_DEBUG("size = %.8x%.8x, parts_size = %.8x, part_count = %.8x, e2k_part_count = %.8x, e2k_part_hash_count = %.8x", (uint32_t)(size >> 32), (uint32_t)size, kf->part_size, kf->part_count, kf->e2k_part_count, kf->e2k_part_hash_count ); rem_file_size = (uint32_t)size; for (uint32_t i = 0; i < kf->part_count; i++){ part = (MULE_FILE_PART*)mem_alloc(sizeof(MULE_FILE_PART) - 1 + kf->part_size); if (!part) { LOG_ERROR("Failed to allocate memory or part structure."); break; } // Initialize part entry part->status = full?MULE_FILE_PART_STATUS_ON_DISK:MULE_FILE_PART_STATUS_DOWNLOADING; // [LOCK] part lock initialization part->start = i * kf->part_size; part->idx = (uint16_t)i; part->length = (rem_file_size > kf->part_size)?kf->part_size:rem_file_size; list_add_entry(&kf->parts, (void*)part); rem_file_size -= (rem_file_size > kf->part_size)?kf->part_size:rem_file_size; } result = true; } while (false); if (!result) list_destroy(kf->parts, true); return result; }
bool kad_session_init( uint16_t tcp_port, uint16_t udp_port, char* nodes_file_path, KAD_SESSION** ks_out ) { bool result = false; KAD_SESSION* ks = NULL; char host_name[HOST_NAME_MAX + 1]; struct hostent* he = NULL; UINT128 zone_idx; uint32_t now = 0; do { LOG_PREFIX("[libkad] "); LOG_LEVEL_DEBUG; LOG_FILE_NAME("libkad.log"); LOG_OUTPUT_CONSOLE_AND_FILE; if (!ks_out) break; ks = (KAD_SESSION*)mem_alloc(sizeof(KAD_SESSION)); if (!ks){ LOG_ERROR("Failed to allocate memory for kad session."); break; } ks->version = KADEMLIA_VERSION; random_init(ticks_now_ms()); gethostname(host_name, HOST_NAME_MAX); LOG_DEBUG("Host name: %s", host_name); he = gethostbyname(host_name); ks->loc_ip4_no = *(uint32_t*)he->h_addr; kad_fw_set_status(&ks->fw, true); kad_fw_set_status_udp(&ks->fw, true); uint128_generate(&ks->kad_id); LOG_DEBUG_UINT128("kad_id: ", ((UINT128*)&ks->kad_id)); for (uint32_t i = 0; i < sizeof(ks->user_hash); i++){ ks->user_hash[i] = random_uint8(); } ks->user_hash[5] = 14; ks->user_hash[14] = 111; kadhlp_gen_udp_key(&ks->udp_key); LOG_DEBUG("udp_key: %.8x", ks->udp_key); ks->udp_port = udp_port; ks->tcp_port = tcp_port; LOG_DEBUG("udp_port = %d", udp_port); LOG_DEBUG("tcp_port = %d", tcp_port); uint128_init(&zone_idx, 0); routing_create_zone(NULL, 0, &zone_idx, &ks->root_zone); list_add_entry(&ks->active_zones, ks->root_zone); now = ticks_now_ms(); ks->timers.self_lookup = now + MIN2MS(3); ks->timers.udp_port_lookup = now; ks->timers.nodes_count_check = now + SEC2MS(10); ks->opts.use_extrn_udp_port = true; queue_create(CONTROL_PACKET_QUEUE_LENGTH, &ks->queue_in_udp); queue_create(CONTROL_PACKET_QUEUE_LENGTH, &ks->queue_out_udp); if (nodes_file_path) kadhlp_add_nodes_from_file(ks, nodes_file_path); kadusr_init(ks); *ks_out = ks; result = true; } while (false); return result; }
bool kadhlp_parse_nodes_dat( KAD_SESSION* ks, char* file_path, LIST** kn_lst_out ) { bool result = false; KAD_FILE* kf = NULL; uint32_t file_len = 0; uint32_t ver = 0; uint32_t kn_cnt = 0; UINT128 id; UINT128 dist; uint32_t ip4; uint16_t udp_port; uint16_t tcp_port; uint8_t type; uint8_t contact_ver; uint32_t udp_key_ip4; uint32_t udp_key; uint8_t verified; KAD_NODE* kn; LIST* kn_lst = NULL; do { if (!kadfile_open_read(file_path, &file_len, &kf)){ LOG_ERROR("Failed to open file %s", file_path); break; } LOG_DEBUG("Nodes file length %.8x(%d)", file_len, file_len); if (!file_len) break; // Skip zero counter for older versions. kadfile_read_uint32(kf, NULL); file_len -= 4; if (file_len < 8) break; // nodes file version. kadfile_read_uint32(kf, &ver); file_len -= 4; if (ver != 2) { LOG_ERROR("Wrong nodes file version."); break; } // nodes count in file. kadfile_read_uint32(kf, &kn_cnt); LOG_DEBUG("%d nodes in file.", kn_cnt); file_len -= 4; if (kn_cnt && file_len < kn_cnt * 25) break; while (kn_cnt--){ // node id kadfile_read_uint128(kf, &id); file_len -= sizeof(UINT128); // node ip address kadfile_read_uint32(kf, &ip4); file_len -= sizeof(uint32_t); // node udp port kadfile_read_uint16(kf, &udp_port); file_len -= sizeof(uint16_t); // node tcp port kadfile_read_uint16(kf, &tcp_port); file_len -= sizeof(uint16_t); // contact version kadfile_read_uint8(kf, &contact_ver); file_len -= sizeof(uint8_t); // udp key data kadfile_read_uint32(kf, &udp_key); file_len -= sizeof(uint32_t); kadfile_read_uint32(kf, &udp_key_ip4); file_len -= sizeof(uint32_t); // node verification status kadfile_read_uint8(kf, &verified); file_len -= sizeof(uint8_t); uint128_xor(&ks->kad_id, &id, &dist); if (!node_create( &id, htonl(udp_key_ip4), htonl(ip4), htons(tcp_port), htons(udp_port), contact_ver, udp_key, verified > 0, &dist, &kn ) ) continue; list_add_entry(kn_lst_out, kn); } LOG_DEBUG("Remained file length %.8x", file_len); result = true; } while (false); if (kf) kadfile_close(kf); return result; }
bool routing_get_bootstrap_contacts( ROUTING_ZONE* rz, // [LOCK] uint32_t max_required, LIST** kn_lst_out, bool top_level_call ) { bool result = false; LIST* kn_lst = NULL; LIST* entry = NULL; uint32_t ent_cnt = 0; void* data = NULL; uint32_t copy_cnt = 0; do { // [LOCK] lock active zones. if (!rz || !kn_lst_out) break; if (!routing_get_top_depth_entries(rz, LOG_BASE_EXPONENT, &kn_lst, false)){ LOG_ERROR("Failed to get top entries."); break; } list_entries_count(kn_lst, &ent_cnt); entry = kn_lst; if (ent_cnt){ copy_cnt = ent_cnt > max_required? max_required : ent_cnt; while (copy_cnt--) { if (!entry) break; list_get_entry_data(entry, &data); list_add_entry(kn_lst_out, data); list_next_entry(entry, &entry); } } result = true; } while (false); if (kn_lst) list_destroy(kn_lst, true); // [LOCK] unlock active zones. return result; }
bool routing_add_node( LIST** active_zones_ptr, // [LOCK] Here should be zone lock. ROUTING_ZONE* rz, KAD_NODE* kn, uint32_t self_pub_ip4_no, bool update_existing, bool* existing_updated_out, bool top_level_call ) { bool result = false; uint32_t idx = 0; KAD_NODE* found_kn = NULL; uint32_t check_udp_key = 0; do { if (!active_zones_ptr || !rz || !kn) break; // [LOCK] here should be active zones lock if call is top level. if (existing_updated_out) *existing_updated_out = false; // If zone bucket is empty then zone have sub zones. // Add node to one of zone sub zones. if (!rz->kb){ idx = uint128_get_bit_value_reverse(&kn->dist, rz->level); result = routing_add_node( active_zones_ptr, //[LOCK] here should be zone lock rz->sub_zones[idx], kn, self_pub_ip4_no, update_existing, existing_updated_out, false ); break; } if (kbucket_node_by_id(rz->kb, &kn->id, &found_kn)){ // Node already added to zone bucket. if (update_existing){ check_udp_key = node_get_udp_key_by_ip(found_kn, self_pub_ip4_no); if (check_udp_key && check_udp_key != node_get_udp_key_by_ip(kn, self_pub_ip4_no)) { // Nodes keys do not match. LOG_ERROR("Udp keys do not match, old = %.8x, new = %.8x", check_udp_key, node_get_udp_key_by_ip(kn, self_pub_ip4_no)); break; } if (kn->version < found_kn->version){ // New node version in lesser than old. break; } // Update node information. // [TODO] Legacy kad2 contacts. // [TODO] Checks when changing ip of exisitng node. found_kn->ip4_no = kn->ip4_no; found_kn->udp_port_no = kn->udp_port_no; found_kn->tcp_port_no = kn->tcp_port_no; found_kn->version = kn->version; if (kn->hello_received) found_kn->hello_received = true; found_kn->status = kn->status; found_kn->next_check_time = kn->next_check_time; node_set_udp_key_with_ip(found_kn, kn->udp_key, self_pub_ip4_no); if (!found_kn->ip_verified) found_kn->ip_verified = kn->ip_verified; if (existing_updated_out) *existing_updated_out = true; // All information copied to existing node // so we destroy the original. node_destroy(kn); result = true; } else { // Node found but we do not update it. result = false; } } else if (rz->kb->nodes_count < K) { // Have space in current zone bucket. result = kbucket_add_node(rz->kb, kn); } else if (routing_zone_can_be_split(rz)){ // Zone bucket is full, zone split required. if (!routing_split_zone(rz)){ LOG_ERROR("Failed to split zone."); break; } list_add_entry(active_zones_ptr, rz->sub_zones[0]); list_add_entry(active_zones_ptr, rz->sub_zones[1]); idx = uint128_get_bit_value_reverse(&kn->dist, rz->level); result = routing_add_node( active_zones_ptr, // [LOCK] lock rz->sub_zones[idx], kn, self_pub_ip4_no, update_existing, existing_updated_out, false ); } } while (false); // [LOCK] if (top_level_call) unlock active zones return result; }