/** * @brief Restore the peers on disk to #valid_peers. */ static void restore_valid_peers () { off_t file_size; uint32_t num_peers; struct GNUNET_DISK_FileHandle *fh; char *buf; ssize_t size_read; char *iter_buf; char *str_repr; const struct GNUNET_PeerIdentity *peer; if (0 == strncmp ("DISABLE", filename_valid_peers, 7)) { return; } if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers)) { return; } fh = GNUNET_DISK_file_open (filename_valid_peers, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); GNUNET_assert (NULL != fh); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size)); num_peers = file_size / 53; buf = GNUNET_malloc (file_size); size_read = GNUNET_DISK_file_read (fh, buf, file_size); GNUNET_assert (size_read == file_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restoring %" PRIu32 " peers from file `%s'\n", num_peers, filename_valid_peers); for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53) { str_repr = GNUNET_strndup (iter_buf, 53); peer = s2i_full (str_repr); GNUNET_free (str_repr); add_valid_peer (peer); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restored valid peer %s from disk\n", GNUNET_i2s_full (peer)); } iter_buf = NULL; GNUNET_free (buf); LOG (GNUNET_ERROR_TYPE_DEBUG, "num_peers: %" PRIu32 ", _size (valid_peers): %u\n", num_peers, GNUNET_CONTAINER_multipeermap_size (valid_peers)); if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Number of restored peers does not match file size. Have probably duplicates.\n"); } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restored %u valid peers from disk\n", GNUNET_CONTAINER_multipeermap_size (valid_peers)); }
/** * @brief Store the peers currently in #valid_peers to disk. */ static void store_valid_peers () { struct GNUNET_DISK_FileHandle *fh; uint32_t number_written_peers; int ret; if (0 == strncmp ("DISABLE", filename_valid_peers, 7)) { return; } ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers); if (GNUNET_SYSERR == ret) { LOG (GNUNET_ERROR_TYPE_WARNING, "Not able to create directory for file `%s'\n", filename_valid_peers); GNUNET_break (0); } else if (GNUNET_NO == ret) { LOG (GNUNET_ERROR_TYPE_WARNING, "Directory for file `%s' exists but is not writable for us\n", filename_valid_peers); GNUNET_break (0); } fh = GNUNET_DISK_file_open (filename_valid_peers, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fh) { LOG (GNUNET_ERROR_TYPE_WARNING, "Not able to write valid peers to file `%s'\n", filename_valid_peers); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u valid peers to disk\n", GNUNET_CONTAINER_multipeermap_size (valid_peers)); number_written_peers = GNUNET_CONTAINER_multipeermap_iterate (valid_peers, store_peer_presistently_iterator, fh); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); GNUNET_assert (number_written_peers == GNUNET_CONTAINER_multipeermap_size (valid_peers)); }
/** * Change length of view * * If size is decreased, peers with higher indices are removed. * * @param len the (maximum) length for the view */ void View_change_len (uint32_t len) { uint32_t i; uint32_t *index; if (GNUNET_CONTAINER_multipeermap_size (mpm) < len) { /* Simply shrink */ /* We might simply clear and free the left over space */ GNUNET_array_grow (array, length, len); } else /* We have to remove elements */ { /* TODO find a way to preserve indices */ for (i = 0; i < len; i++) { index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[i]); GNUNET_assert (NULL != index); GNUNET_free (index); } GNUNET_array_grow (array, length, len); GNUNET_CONTAINER_multipeermap_destroy (mpm); mpm = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO); for (i = 0; i < len; i++) { index = GNUNET_new (uint32_t); *index = i; GNUNET_CONTAINER_multipeermap_put (mpm, &array[i], index, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } } GNUNET_assert (length == len); }
/** * Create a session, a key exchange was just completed. * * @param peer peer that is now connected * @param kx key exchange that completed */ void GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx) { struct Session *session; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating session for peer `%4s'\n", GNUNET_i2s (peer)); session = GNUNET_new (struct Session); session->tmap = GSC_TYPEMAP_create (); session->peer = *peer; session->kxinfo = kx; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (sessions, &session->peer, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multipeermap_size (sessions), GNUNET_NO); GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, session->tmap); start_typemap_task (session); }
/** * This path is no longer needed, free resources. * * @param path path resources to free */ static void path_destroy (struct CadetPeerPath *path) { GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (path->connections)); GNUNET_CONTAINER_multipeermap_destroy (path->connections); GNUNET_free (path->entries); GNUNET_free (path); }
/** * Provide an update on the `p2a` map size to statistics. * This function should be called whenever the `p2a` map * is changed. */ static void publish_p2a_stat_update () { GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# Addresses given to ATS"), GNUNET_CONTAINER_multipeermap_size (p2a) - num_blocked, GNUNET_NO); GNUNET_STATISTICS_set (GST_stats, "# blocked addresses", num_blocked, GNUNET_NO); }
/** * Get a peer by index * * @param index the index of the peer to get * * @return peer to the corresponding index. * NULL if this index is not known */ const struct GNUNET_PeerIdentity * View_get_peer_by_index (uint32_t index) { if (index < GNUNET_CONTAINER_multipeermap_size (mpm)) { return &array[index]; } else { return NULL; } }
/** * End the session with the given peer (we are no longer * connected). * * @param pid identity of peer to kill session with */ void GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) { struct Session *session; struct GSC_ClientActiveRequest *car; struct SessionMessageEntry *sme; session = find_session (pid); if (NULL == session) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying session for peer `%4s'\n", GNUNET_i2s (&session->peer)); if (NULL != session->cork_task) { GNUNET_SCHEDULER_cancel (session->cork_task); session->cork_task = NULL; } while (NULL != (car = session->active_client_request_head)) { GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, session->active_client_request_tail, car); GSC_CLIENTS_reject_request (car, GNUNET_NO); } while (NULL != (sme = session->sme_head)) { GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); GNUNET_free (sme); } if (NULL != session->typemap_task) { GNUNET_SCHEDULER_cancel (session->typemap_task); session->typemap_task = NULL; } GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, session->tmap, NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (sessions, &session->peer, session)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multipeermap_size (sessions), GNUNET_NO); GSC_TYPEMAP_destroy (session->tmap); session->tmap = NULL; GNUNET_free (session); }
/** * Update statistics * * @param m peermap to update values from */ static void update_stats (struct GNUNET_CONTAINER_MultiPeerMap *m) { GNUNET_assert (NULL != m); GNUNET_assert (NULL != GED_stats); if (m == nodes_active) { GNUNET_STATISTICS_set (GED_stats, "# nodes active", GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO); } else if (m == nodes_inactive) { GNUNET_STATISTICS_set (GED_stats, "# nodes inactive", GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO); } else if (m == nodes_requested) { GNUNET_STATISTICS_set (GED_stats, "# nodes requested", GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO); } else GNUNET_break (0); }
/** * @brief Get a random peer from @a peer_map * * @param peer_map the peer_map to get the peer from * * @return a random peer */ static const struct GNUNET_PeerIdentity * get_random_peer_from_peermap (const struct GNUNET_CONTAINER_MultiPeerMap *peer_map) { struct GetRandPeerIteratorCls *iterator_cls; const struct GNUNET_PeerIdentity *ret; iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls); iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multipeermap_size (peer_map)); (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers, get_rand_peer_iterator, iterator_cls); ret = iterator_cls->peer; GNUNET_free (iterator_cls); return ret; }
/** * @brief Add a given @a peer to valid peers. * * If valid peers are already #num_valid_peers_max, delete a peer previously. * * @param peer the peer that is added to the valid peers. * * @return #GNUNET_YES if no other peer had to be removed * #GNUNET_NO otherwise */ static int add_valid_peer (const struct GNUNET_PeerIdentity *peer) { const struct GNUNET_PeerIdentity *rand_peer; int ret; ret = GNUNET_YES; while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max) { rand_peer = get_random_peer_from_peermap (valid_peers); GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer); ret = GNUNET_NO; } (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); return ret; }
/** * Free the given entry for the neighbour. * * @param n neighbour to free */ static void free_neighbour (struct Neighbour *n) { struct NeighbourMessageEntry *m; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying neighbour entry for peer `%s'\n", GNUNET_i2s (&n->peer)); while (NULL != (m = n->message_head)) { GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); n->queue_size--; GNUNET_free (m); } GNUNET_assert (0 == n->queue_size); if (NULL != n->th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); n->th = NULL; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# sessions terminated by transport disconnect"), 1, GNUNET_NO); if (NULL != n->kxinfo) { GSC_KX_stop (n->kxinfo); n->kxinfo = NULL; } if (NULL != n->retry_plaintext_task) { GNUNET_SCHEDULER_cancel (n->retry_plaintext_task); n->retry_plaintext_task = NULL; } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (neighbours, &n->peer, n)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# neighbour entries allocated"), GNUNET_CONTAINER_multipeermap_size (neighbours), GNUNET_NO); GNUNET_free (n); }
/** * Function called by transport to notify us that * a peer connected to us (on the network level). * * @param cls closure * @param peer the peer that connected */ static void handle_transport_notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct Neighbour *n; if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return; } n = find_neighbour (peer); if (NULL != n) { /* duplicate connect notification!? */ GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer %s exists already\n", GNUNET_i2s (peer)); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%s'.\n", GNUNET_i2s (peer)); n = GNUNET_new (struct Neighbour); n->peer = *peer; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (neighbours, &n->peer, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# neighbour entries allocated"), GNUNET_CONTAINER_multipeermap_size (neighbours), GNUNET_NO); n->kxinfo = GSC_KX_start (peer); }
/** * Get the size of the view * * @return current number of actually contained peers */ unsigned int View_size () { return GNUNET_CONTAINER_multipeermap_size (mpm); }
/** * Shutdown routing subsystem. */ void GDS_ROUTING_done () { GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (routing_table)); GNUNET_CONTAINER_multipeermap_destroy (routing_table); }
subscriber->channel = GNUNET_MESH_channel_create (mesh_handle, NULL, id, GNUNET_APPLICATION_TYPE_MQTT, GNUNET_MESH_OPTION_RELIABLE); subscriber->peer_added = GNUNET_NO; subscriber->peer_connecting = GNUNET_NO; subscriber->id = *id; GNUNET_CONTAINER_multipeermap_put (remote_subscribers, id, subscriber, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } LOG(GNUNET_ERROR_TYPE_DEBUG, "Maintaining %d remote subscribers\n", GNUNET_CONTAINER_multipeermap_size(remote_subscribers)); add_pending_subscriber_message (subscriber, pm); subscriber->peer_added = GNUNET_YES; subscriber->peer_connecting = GNUNET_NO; process_pending_subscriber_messages (subscriber); } /** * Call regex search to find subscribed peers. * * @param topic of the message identification of the client * @param publish_msg the publish message */ static void
/** * Initialize a message to clients with the current network * size estimate. * * @param em message to fill in */ static void setup_estimate_message (struct GNUNET_NSE_ClientMessage *em) { double mean; double sum; double std_dev; double variance; double val; double nsize; #define WEST 1 /* Weighted incremental algorithm for stddev according to West (1979) */ #if WEST double sumweight; double weight; double q; double r; double temp; mean = 0.0; sum = 0.0; sumweight = 0.0; variance = 0.0; for (unsigned int i = 0; i < estimate_count; i++) { unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; val = htonl (size_estimate_messages[j].matching_bits); weight = estimate_count + 1 - i; temp = weight + sumweight; q = val - mean; r = q * weight / temp; mean += r; sum += sumweight * q * r; sumweight = temp; } if (estimate_count > 0) variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0); #else /* trivial version for debugging */ double vsq; /* non-weighted trivial version */ sum = 0.0; vsq = 0.0; variance = 0.0; mean = 0.0; for (unsigned int i = 0; i < estimate_count; i++) { unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; val = htonl (size_estimate_messages[j].matching_bits); sum += val; vsq += val * val; } if (0 != estimate_count) { mean = sum / estimate_count; variance = (vsq - mean * sum) / (estimate_count - 1.0); // terrible for numerical stability... } #endif if (variance >= 0) std_dev = sqrt (variance); else std_dev = variance; /* must be infinity due to estimate_count == 0 */ current_std_dev = std_dev; current_size_estimate = mean; em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage)); em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); em->reserved = htonl (0); em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); { double se = mean - 0.332747; unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers); if (0 == j) j = 1; /* Avoid log2(0); can only happen if CORE didn't report connection to self yet */ nsize = log2 (j); em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize)); em->std_deviation = GNUNET_hton_double (std_dev); GNUNET_STATISTICS_set (stats, "# nodes in the network (estimate)", (uint64_t) pow (2, GNUNET_MAX (se, nsize)), GNUNET_NO); } }
static int testMap (int i) { struct GNUNET_CONTAINER_MultiPeerMap *m; struct GNUNET_PeerIdentity k1; struct GNUNET_PeerIdentity k2; struct GNUNET_CONTAINER_MultiPeerMapIterator *iter; struct GNUNET_PeerIdentity key_ret; const char *ret; int j; CHECK (NULL != (m = GNUNET_CONTAINER_multipeermap_create (i, GNUNET_NO))); memset (&k1, 0, sizeof (k1)); memset (&k2, 1, sizeof (k2)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k1)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k1, NULL)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_remove (m, &k2, NULL)); CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k1)); CHECK (NULL == GNUNET_CONTAINER_multipeermap_get (m, &k2)); CHECK (0 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1)); CHECK (0 == GNUNET_CONTAINER_multipeermap_size (m)); CHECK (0 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL)); CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1", GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m)); ret = GNUNET_CONTAINER_multipeermap_get (m, &k1); GNUNET_assert (ret != NULL); CHECK (0 == strcmp ("v1", ret)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_put (m, &k1, "v1", GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); CHECK (1 == GNUNET_CONTAINER_multipeermap_size (m)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (m, &k1, "v3", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); CHECK (3 == GNUNET_CONTAINER_multipeermap_size (m)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (m, &k1, "v3")); CHECK (2 == GNUNET_CONTAINER_multipeermap_size (m)); CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (m, &k1)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (m, &k2)); CHECK (2 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k1, NULL, NULL)); CHECK (0 == GNUNET_CONTAINER_multipeermap_get_multiple (m, &k2, NULL, NULL)); CHECK (2 == GNUNET_CONTAINER_multipeermap_iterate (m, NULL, NULL)); iter = GNUNET_CONTAINER_multipeermap_iterator_create (m); CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, &key_ret, (const void **)&ret)); CHECK (0 == memcmp (&key_ret, &k1, sizeof (key_ret))); CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, &key_ret, (const void **)&ret)); CHECK (0 == memcmp (&key_ret, &k1, sizeof (key_ret))); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL)); GNUNET_free (iter); CHECK (2 == GNUNET_CONTAINER_multipeermap_remove_all (m, &k1)); for (j = 0; j < 1024; j++) CHECK (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (m, &k1, "v2", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); iter = GNUNET_CONTAINER_multipeermap_iterator_create (m); for (j = 0; j < GNUNET_CONTAINER_multipeermap_size (m); j++) CHECK (GNUNET_YES == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multipeermap_iterator_next (iter, NULL, NULL)); GNUNET_free (iter); GNUNET_CONTAINER_multipeermap_destroy (m); return 0; }
/** * Stop server offering our hostlist. */ void GNUNET_HOSTLIST_server_stop () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); if (NULL != hostlist_task_v6) { GNUNET_SCHEDULER_cancel (hostlist_task_v6); hostlist_task_v6 = NULL; } if (NULL != hostlist_task_v4) { GNUNET_SCHEDULER_cancel (hostlist_task_v4); hostlist_task_v4 = NULL; } if (NULL != daemon_handle_v4) { MHD_stop_daemon (daemon_handle_v4); daemon_handle_v4 = NULL; } if (NULL != daemon_handle_v6) { MHD_stop_daemon (daemon_handle_v6); daemon_handle_v6 = NULL; } if (NULL != response) { MHD_destroy_response (response); response = NULL; } if (NULL != notify) { GNUNET_PEERINFO_notify_cancel (notify); notify = NULL; } if (NULL != builder) { if (NULL != builder->pitr) { GNUNET_PEERINFO_iterate_cancel (builder->pitr); builder->pitr = NULL; } GNUNET_free_non_null (builder->data); GNUNET_free (builder); builder = NULL; } if (NULL != peerinfo) { GNUNET_PEERINFO_disconnect (peerinfo); peerinfo = NULL; } if (NULL != advertisements) { GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (advertisements)); GNUNET_CONTAINER_multipeermap_destroy (advertisements); advertisements = NULL; } cfg = NULL; stats = NULL; core = NULL; }