/** * Main state machine. Executes the next step of the benchmark * depending on the current state. * * @param cls the `struct CpsRunContext` */ static void run_continuation (void *cls) { struct CpsRunContext *crc = cls; size_t size; static struct GNUNET_HashCode key; static char data[65536]; char gstr[128]; ok = (int) crc->phase; switch (crc->phase) { case RP_PUT: memset (&key, 256 - crc->i, sizeof (struct GNUNET_HashCode)); /* most content is 32k */ size = 32 * 1024; if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) /* but some of it is less! */ size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); crc->size = size = size - (size & 7); /* always multiple of 8 */ GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &key); memset (data, (int) crc->j, size); if (crc->j > 255) memset (data, (int) (crc->j - 255), size / 2); data[0] = crc->i; GNUNET_assert (NULL != GNUNET_DATASTORE_put (datastore, 0, &key, size, data, crc->j + 1, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100), crc->j, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), 1, 1, &check_success, crc)); break; case RP_CUT: /* trim down below MAX_SIZE again */ GNUNET_assert (NULL != GNUNET_DATASTORE_get_for_replication (datastore, 1, 1, &delete_value, crc)); break; case RP_REPORT: printf ( #if REPORT_ID "\n" #endif "Stored %llu kB / %lluk ops / %llu ops/s\n", stored_bytes / 1024, /* used size in k */ stored_ops / 1024, /* total operations (in k) */ 1000LL * 1000LL * stored_ops / (1 + GNUNET_TIME_absolute_get_duration (start_time).rel_value_us)); crc->phase = RP_PUT; crc->j = 0; GNUNET_SCHEDULER_add_now (&run_continuation, crc); break; case RP_PUT_QUOTA: memset (&key, 256 - crc->i, sizeof (struct GNUNET_HashCode)); /* most content is 32k */ size = 32 * 1024; if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) /* but some of it is less! */ size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); crc->size = size = size - (size & 7); /* always multiple of 8 */ GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &key); memset (data, (int) crc->j, size); if (crc->j > 255) memset (data, (int) (crc->j - 255), size / 2); data[0] = crc->i; GNUNET_assert (NULL != GNUNET_DATASTORE_put (datastore, 0, /* reservation ID */ &key, size, data, crc->j + 1, /* type */ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100), /* priority */ crc->j, /* anonymity */ 0, /* replication */ GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), 1, 1, &check_success, crc)); break; case RP_DONE: GNUNET_snprintf (gstr, sizeof (gstr), "DATASTORE-%s", plugin_name); if ((crc->i == ITERATIONS) && (stored_ops > 0)) { GAUGER (gstr, "PUT operation duration", GNUNET_TIME_absolute_get_duration (start_time).rel_value_us / 1000LL / stored_ops, "ms/operation"); fprintf (stdout, "\nPUT performance: %s for %llu operations\n", GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start_time), GNUNET_YES), stored_ops); fprintf (stdout, "PUT performance: %llu ms/operation\n", GNUNET_TIME_absolute_get_duration (start_time).rel_value_us / 1000LL / stored_ops); } GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 0; break; case RP_ERROR: GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 1; break; default: GNUNET_assert (0); } }
/** * Evaluate RSA performance. * * @param len keylength to evaluate with */ static void eval (unsigned int len) { struct GNUNET_TIME_Absolute start; struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_CRYPTO_RsaSignature *rsig; struct GNUNET_CRYPTO_RsaPublicKey *public_key; struct GNUNET_CRYPTO_RsaPrivateKey *private_key; struct GNUNET_CRYPTO_RsaBlindingKeySecret bsec[10]; unsigned int i; char sbuf[128]; char *bbuf; size_t bbuf_len; struct GNUNET_HashCode hc; start = GNUNET_TIME_absolute_get (); for (i=0;i<10;i++) { private_key = GNUNET_CRYPTO_rsa_private_key_create (len); GNUNET_CRYPTO_rsa_private_key_free (private_key); } printf ("10x %u-key generation took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-key generation", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "keys/ms"); private_key = GNUNET_CRYPTO_rsa_private_key_create (len); public_key = GNUNET_CRYPTO_rsa_private_key_get_public (private_key); for (i=0;i<10;i++) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &bsec[i], sizeof (bsec[0])); /* start = GNUNET_TIME_absolute_get (); for (i=0;i<10;i++) rsa_blinding_key_derive(public_key, &bsec[i]); printf ("10x %u-blinding key generation took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-blinding key generation", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "keys/ms"); */ start = GNUNET_TIME_absolute_get (); GNUNET_CRYPTO_hash ("test", 4, &hc); for (i=0;i<10;i++) { GNUNET_CRYPTO_rsa_blind (&hc, &bsec[i], public_key, &bbuf, &bbuf_len); GNUNET_free (bbuf); } printf ("10x %u-blinding took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-blinding", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "ops/ms"); GNUNET_CRYPTO_rsa_blind (&hc, &bsec[0], public_key, &bbuf, &bbuf_len); start = GNUNET_TIME_absolute_get (); for (i=0;i<10;i++) { sig = GNUNET_CRYPTO_rsa_sign_blinded (private_key, bbuf, bbuf_len); GNUNET_CRYPTO_rsa_signature_free (sig); } printf ("10x %u-signing took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-signing", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "ops/ms"); sig = GNUNET_CRYPTO_rsa_sign_blinded (private_key, bbuf, bbuf_len); start = GNUNET_TIME_absolute_get (); for (i=0;i<10;i++) { rsig = GNUNET_CRYPTO_rsa_unblind (sig, &bsec[0], public_key); GNUNET_CRYPTO_rsa_signature_free (rsig); } printf ("10x %u-unblinding took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-unblinding", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "ops/ms"); rsig = GNUNET_CRYPTO_rsa_unblind (sig, &bsec[0], public_key); start = GNUNET_TIME_absolute_get (); for (i=0;i<10;i++) { GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_verify (&hc, rsig, public_key)); } printf ("10x %u-verifying took %s\n", len, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (sbuf, sizeof (sbuf), "RSA %u-verification", len); GAUGER ("UTIL", sbuf, 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "ops/ms"); GNUNET_CRYPTO_rsa_signature_free (sig); GNUNET_CRYPTO_rsa_public_key_free (public_key); GNUNET_CRYPTO_rsa_private_key_free (private_key); GNUNET_free (bbuf); }
static int testDirectory (unsigned int i) { struct GNUNET_FS_DirectoryBuilder *db; char *data; size_t dlen; struct GNUNET_FS_Uri **uris; struct GNUNET_CONTAINER_MetaData **mds; struct GNUNET_CONTAINER_MetaData *meta; struct PCLS cls; char *emsg; int p; int q; char uri[512]; char txt[128]; int ret = 0; struct GNUNET_TIME_Absolute start; const char *s; cls.max = i; uris = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri *) * i); mds = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData *) * i); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (meta, "<test>", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "A title", strlen ("A title") + 1); GNUNET_CONTAINER_meta_data_insert (meta, "<test>", EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "An author", strlen ("An author") + 1); for (p = 0; p < i; p++) { mds[p] = GNUNET_CONTAINER_meta_data_create (); for (q = 0; q <= p; q++) { GNUNET_snprintf (txt, sizeof (txt), "%u -- %u\n", p, q); GNUNET_CONTAINER_meta_data_insert (mds[p], "<test>", #if HAVE_EXTRACTOR_H q % EXTRACTOR_metatype_get_max (), #else q % 128, #endif EXTRACTOR_METAFORMAT_UTF8, "text/plain", txt, strlen (txt) + 1); } GNUNET_snprintf (uri, sizeof (uri), "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.%u", p); emsg = NULL; uris[p] = GNUNET_FS_uri_parse (uri, &emsg); if (uris[p] == NULL) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); while (--p > 0) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); GNUNET_FS_uri_destroy (uris[p]); } GNUNET_free (mds); GNUNET_free (uris); GNUNET_free (emsg); GNUNET_CONTAINER_meta_data_destroy (meta); ABORT (); /* error in testcase */ } GNUNET_assert (emsg == NULL); } start = GNUNET_TIME_absolute_get (); db = GNUNET_FS_directory_builder_create (meta); for (p = 0; p < i; p++) GNUNET_FS_directory_builder_add (db, uris[p], mds[p], NULL); GNUNET_FS_directory_builder_finish (db, &dlen, (void **) &data); s = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES); FPRINTF (stdout, "Creating directory with %u entires and total size %llu took %s\n", i, (unsigned long long) dlen, s); if (i < 100) { cls.pos = 0; cls.uri = uris; cls.md = mds; GNUNET_FS_directory_list_contents (dlen, data, 0, &processor, &cls); GNUNET_assert (cls.pos == i); } GNUNET_free (data); GNUNET_CONTAINER_meta_data_destroy (meta); for (p = 0; p < i; p++) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); GNUNET_FS_uri_destroy (uris[p]); } GNUNET_free (uris); GNUNET_free (mds); return ret; }
/** * Called by FS client to give information about the progress of an * operation. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the `struct GNUNET_FS_ProgressInfo` */ static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { char *s; const char *s2; char *t; switch (info->status) { case GNUNET_FS_STATUS_DOWNLOAD_START: if (verbose > 1) FPRINTF (stderr, _("Starting download `%s'.\n"), info->value.download.filename); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: if (verbose) { s = GNUNET_strdup (GNUNET_STRINGS_relative_time_to_string (info->value.download.eta, GNUNET_YES)); if (info->value.download.specifics.progress.block_download_duration.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) s2 = _("<unknown time>"); else s2 = GNUNET_STRINGS_relative_time_to_string ( info->value.download.specifics.progress.block_download_duration, GNUNET_YES); t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000LL / (info->value.download. duration.rel_value_us + 1)); FPRINTF (stdout, _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), info->value.download.filename, (unsigned long long) info->value.download.completed, (unsigned long long) info->value.download.size, s, t, s2); GNUNET_free (s); GNUNET_free (t); } else { display_bar (info->value.download.completed, info->value.download.size, 60); } break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: #if !WINDOWS if (0 != isatty (1)) fprintf (stdout, "\n"); #else if (FILE_TYPE_CHAR == GetFileType (GetStdHandle (STD_OUTPUT_HANDLE))) fprintf (stdout, "\n"); #endif FPRINTF (stderr, _("Error downloading: %s.\n"), info->value.download.specifics.error.message); GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: s = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000 / (info->value.download. duration.rel_value_us + 1)); #if !WINDOWS if (0 != isatty (1)) fprintf (stdout, "\n"); #else if (FILE_TYPE_CHAR == GetFileType (GetStdHandle (STD_OUTPUT_HANDLE))) fprintf (stdout, "\n"); #endif FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"), info->value.download.filename, s); GNUNET_free (s); if (info->value.download.dc == dc) GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: if (info->value.download.dc == dc) GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: break; default: FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); break; } return NULL; }
static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_DATACACHE_Handle *h; struct GNUNET_HashCode k; struct GNUNET_HashCode n; struct GNUNET_TIME_Absolute exp; struct GNUNET_TIME_Absolute start; unsigned int i; char gstr[128]; ok = 0; h = GNUNET_DATACACHE_create (cfg, "perfcache"); if (h == NULL) { FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); ok = 77; /* mark test as skipped */ return; } exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); start = GNUNET_TIME_absolute_get (); memset (&k, 0, sizeof (struct GNUNET_HashCode)); for (i = 0; i < ITERATIONS; i++) { if (0 == i % (ITERATIONS / 80)) FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), (const char *) &n, 1 + i % 16, exp, 0, NULL)); k = n; } FPRINTF (stderr, "%s", "\n"); FPRINTF (stdout, "Stored %u items in %s\n", ITERATIONS, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES)); GNUNET_snprintf (gstr, sizeof (gstr), "DATACACHE-%s", plugin_name); GAUGER (gstr, "Time to PUT item in datacache", GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL / ITERATIONS, "ms/item"); start = GNUNET_TIME_absolute_get (); memset (&k, 0, sizeof (struct GNUNET_HashCode)); for (i = 0; i < ITERATIONS; i++) { if (0 == i % (ITERATIONS / 80)) FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n); k = n; } FPRINTF (stderr, "%s", "\n"); FPRINTF (stdout, "Found %u/%u items in %s (%u were deleted during storage processing)\n", found, ITERATIONS, GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start), GNUNET_YES), ITERATIONS - found); if (found > 0) GAUGER (gstr, "Time to GET item from datacache", GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL / found, "ms/item"); GNUNET_DATACACHE_destroy (h); ASSERT (ok == 0); return; FAILURE: if (h != NULL) GNUNET_DATACACHE_destroy (h); ok = GNUNET_SYSERR; }
/** * Function called when the transport service is ready to receive a * message for the respective peer * * @param cls neighbour to use message from * @param size number of bytes we can transmit * @param buf where to copy the message * @return number of bytes transmitted */ static size_t transmit_ready (void *cls, size_t size, void *buf) { struct Neighbour *n = cls; struct NeighbourMessageEntry *m; size_t ret; char *cbuf; struct GNUNET_TIME_Relative delay; struct GNUNET_TIME_Relative overdue; n->th = NULL; m = n->message_head; if (NULL == m) { GNUNET_break (0); return 0; } GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); n->queue_size--; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission of message of type %u and size %u failed\n", (unsigned int) ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), (unsigned int) m->size); GNUNET_free (m); process_queue (n); return 0; } delay = GNUNET_TIME_absolute_get_duration (m->submission_time); overdue = GNUNET_TIME_absolute_get_duration (m->deadline); cbuf = buf; GNUNET_assert (size >= m->size); memcpy (cbuf, &m[1], m->size); ret = m->size; if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Copied overdue message of type %u and size %u into transport buffer for `%s' with delay of %s\n", (unsigned int) ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), (unsigned int) ret, GNUNET_i2s (&n->peer), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copied message of type %u and size %u into transport buffer for `%s' with delay of %s\n", (unsigned int) ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), (unsigned int) ret, GNUNET_i2s (&n->peer), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); GNUNET_free (m); n->has_excess_bandwidth = GNUNET_NO; process_queue (n); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# encrypted bytes given to transport"), ret, GNUNET_NO); return ret; }
/** * Recalculate when we might need to call the excess callback. */ static void update_excess (struct GNUNET_BANDWIDTH_Tracker *av) { struct GNUNET_TIME_Relative delay; struct GNUNET_TIME_Absolute now; uint64_t delta_time; uint64_t delta_avail; int64_t left_bytes; uint64_t max_carry; int64_t current_consumption; if (NULL == av->excess_cb) return; /* nothing to do */ now = GNUNET_TIME_absolute_get (); delta_time = now.abs_value_us - av->last_update__.abs_value_us; delta_avail = (delta_time * ((unsigned long long) av->available_bytes_per_s__) + 500000LL) / 1000000LL; current_consumption = av->consumption_since_last_update__ - delta_avail; if (current_consumption > av->consumption_since_last_update__) { /* integer underflow, cap! */ current_consumption = INT64_MIN; } /* negative current_consumption means that we have savings */ max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__; if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; if (max_carry > INT64_MAX) max_carry = INT64_MAX; left_bytes = current_consumption + max_carry; if (left_bytes < current_consumption) { /* integer overflow, cap! */ left_bytes = INT64_MAX; } /* left_bytes now contains the number of bytes needed until we have more savings than allowed */ if (left_bytes < 0) { /* having excess already */ delay = GNUNET_TIME_UNIT_ZERO; } else { double factor = 1.0 * left_bytes / (double) av->available_bytes_per_s__; delay = GNUNET_TIME_relative_saturating_multiply (GNUNET_TIME_UNIT_SECONDS, (unsigned long long) factor); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n", (unsigned long long) av->available_bytes_per_s__, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO), (long long) left_bytes); if (NULL != av->excess_task) GNUNET_SCHEDULER_cancel (av->excess_task); av->excess_task = GNUNET_SCHEDULER_add_delayed (delay, &excess_trigger, av); }
/** * Figure out when and how to transmit to the given peer. * * @param cls the `struct PeerPlan` */ static void schedule_peer_transmission (void *cls) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; struct GNUNET_TIME_Relative delay; if (NULL != pp->task) { pp->task = NULL; } else { GNUNET_assert (NULL != pp->env); pp->env = NULL; } /* move ready requests to priority queue */ while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && (0 == GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value_us)) { GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); } if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) { /* priority heap (still) empty, check for delay... */ rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); if (NULL == rp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", pp); return; /* both queues empty */ } delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sleeping for %s before retrying requests on plan %p.\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout (ms)"), delay.rel_value_us / 1000LL, GNUNET_NO); pp->task = GNUNET_SCHEDULER_add_at (rp->earliest_transmission, &schedule_peer_transmission, pp); return; } #if INSANE_STATISTICS GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), 1, GNUNET_NO); #endif /* process from priority heap */ rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); GNUNET_assert (NULL != rp); rp->hn = NULL; rp->last_transmission = GNUNET_TIME_absolute_get (); rp->transmission_counter++; total_delay++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing plan %p executed %u times, planning retransmission\n", rp, rp->transmission_counter); GNUNET_assert (NULL == pp->env); pp->env = GSF_pending_request_get_message_ (get_latest (rp)); GNUNET_MQ_notify_sent (pp->env, &schedule_peer_transmission, pp); GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, pp->env); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query messages sent to other peers"), 1, GNUNET_NO); plan (pp, rp); }
/** * Insert the given request plan into the heap with the appropriate weight. * * @param pp associated peer's plan * @param rp request to plan */ static void plan (struct PeerPlan *pp, struct GSF_RequestPlan *rp) { #define N ((double)128.0) /** * Running average delay we currently impose. */ static double avg_delay; struct GSF_PendingRequestData *prd; struct GNUNET_TIME_Relative delay; GNUNET_assert (rp->pp == pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# average retransmission delay (ms)"), total_delay * 1000LL / plan_count, GNUNET_NO); prd = GSF_pending_request_get_data_ (rp->pe_head->pr); if (rp->transmission_counter < 8) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, rp->transmission_counter); else if (rp->transmission_counter < 32) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << (rp->transmission_counter - 8))); else delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << 24)); delay.rel_value_us = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value_us + 1); /* Add 0.01 to avg_delay to avoid division-by-zero later */ avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value_us) / N) + 0.01; /* * For the priority, we need to consider a few basic rules: * 1) if we just started requesting (delay is small), we should * virtually always have a priority of zero. * 2) for requests with average latency, our priority should match * the average priority observed on the network * 3) even the longest-running requests should not be WAY out of * the observed average (thus we bound by a factor of 2) * 4) we add +1 to the observed average priority to avoid everyone * staying put at zero (2 * 0 = 0...). * * Using the specific calculation below, we get: * * delay = 0 => priority = 0; * delay = avg delay => priority = running-average-observed-priority; * delay >> avg_delay => priority = 2 * running-average-observed-priority; * * which satisfies all of the rules above. * * Note: M_PI_4 = PI/4 = arctan(1) */ rp->priority = round ((GSF_current_priorities + 1.0) * atan (delay.rel_value_us / avg_delay)) / M_PI_4; /* Note: usage of 'round' and 'atan' requires -lm */ if (rp->transmission_counter != 0) delay.rel_value_us += TTL_DECREMENT * 1000; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering (re)transmission number %u in %s\n", (unsigned int) rp->transmission_counter, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Earliest (re)transmission for `%s' in %us\n", GNUNET_h2s (&prd->query), rp->transmission_counter); GNUNET_assert (rp->hn == NULL); if (0 == GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value_us) rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); else rp->hn = GNUNET_CONTAINER_heap_insert (pp->delay_heap, rp, rp->earliest_transmission.abs_value_us); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map, get_rp_key (rp), rp)); #undef N }
/** * Request for a service to be started. * * @param h handle to ARM * @param service_name name of the service * @param std_inheritance inheritance of std streams * @param timeout how long to wait before failing for good * @param cont callback to invoke after request is sent or not sent * @param cont_cls closure for callback */ void GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h, const char *service_name, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cont, void *cont_cls) { struct ARMControlMessage *cm; size_t slen; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to start service `%s' within %s\n", service_name, GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); if (0 == strcasecmp ("arm", service_name)) { /* Possible cases: * 1) We're connected to ARM already. Invoke the callback immediately. * 2) We're not connected to ARM. * Cancel any reconnection attempts temporarily, then perform * a service test. */ if (GNUNET_NO == h->currently_down) { LOG (GNUNET_ERROR_TYPE_DEBUG, "ARM is already running\n"); if (NULL != cont) cont (cont_cls, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_STARTED_ALREADY); } else if (GNUNET_NO == h->service_test_is_active) { if (NULL != h->cth) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); h->cth = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) { GNUNET_SCHEDULER_cancel (h->reconnect_task); h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Not connected to ARM, will do a service test\n"); slen = strlen ("arm") + 1; cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); cm->h = h; cm->result_cont = cont; cm->cont_cls = cont_cls; cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); cm->std_inheritance = std_inheritance; memcpy (&cm[1], service_name, slen); h->service_test_is_active = GNUNET_YES; GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, cm); } else { /* Service test is already running - tell user to chill out and try * again later. */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service test is already in progress, we're busy\n"); if (NULL != cont) cont (cont_cls, GNUNET_ARM_REQUEST_BUSY, NULL, 0); } return; } change_service (h, service_name, timeout, cont, cont_cls, GNUNET_MESSAGE_TYPE_ARM_START); }