/** * File hashing task. * * @param cls closure * @param tc context */ static void file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CRYPTO_FileHashContext *fhc = cls; struct GNUNET_HashCode *res; size_t delta; fhc->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (fhc->offset <= fhc->fsize); delta = fhc->bsize; if (fhc->fsize - fhc->offset < delta) delta = fhc->fsize - fhc->offset; if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename); file_hash_finish (fhc, NULL); return; } gcry_md_write (fhc->md, fhc->buffer, delta); fhc->offset += delta; if (fhc->offset == fhc->fsize) { res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512); file_hash_finish (fhc, res); return; } fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority, &file_hash_task, fhc); }
/** * Start up peerinfo service. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_hello, NULL, GNUNET_MESSAGE_TYPE_HELLO, 0}, {&handle_get, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET, sizeof (struct ListPeerMessage)}, {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL, sizeof (struct GNUNET_MessageHeader)}, {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; char *peerdir; char *ip; hostmap = GNUNET_CONTAINER_multihashmap_create (1024); stats = GNUNET_STATISTICS_create ("peerinfo", cfg); notify_list = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "peerinfo", "HOSTS", &networkIdDirectory)); GNUNET_DISK_directory_create (networkIdDirectory); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_scan_directory_data_hosts, NULL); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_clean_data_hosts, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); GNUNET_SERVER_add_handlers (server, handlers); ip = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); GNUNET_asprintf (&peerdir, "%shellos", ip); GNUNET_free (ip); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Importing HELLOs from `%s'\n"), peerdir); GNUNET_DISK_directory_scan (peerdir, &hosts_directory_scan_callback, NULL); GNUNET_free (peerdir); }
/** * Consider scheduling the restart-task. * Only runs the restart task once per event * category. * * @param ev type of the event to consider */ static void consider_restart (int ev) { static int prev[32]; static int off; int i; for (i = 0; i < off; i++) if (prev[i] == ev) return; prev[off++] = ev; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, &restart_fs_task, NULL); }
/** * Compute the hash of an entire file. * * @param priority scheduling priority to use * @param filename name of file to hash * @param blocksize number of bytes to process in one task * @param callback function to call upon completion * @param callback_cls closure for callback * @return NULL on (immediate) errror */ struct GNUNET_CRYPTO_FileHashContext * GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, const char *filename, size_t blocksize, GNUNET_CRYPTO_HashCompletedCallback callback, void *callback_cls) { struct GNUNET_CRYPTO_FileHashContext *fhc; GNUNET_assert (blocksize > 0); fhc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize); fhc->callback = callback; fhc->callback_cls = callback_cls; fhc->buffer = (unsigned char *) &fhc[1]; fhc->filename = GNUNET_strdup (filename); if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0)) { GNUNET_break (0); GNUNET_free (fhc); return NULL; } fhc->bsize = blocksize; if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_free (fhc->filename); GNUNET_free (fhc); return NULL; } fhc->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (!fhc->fh) { GNUNET_free (fhc->filename); GNUNET_free (fhc); return NULL; } fhc->priority = priority; fhc->task = GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc); return fhc; }
/** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { struct GNUNET_CRYPTO_EddsaPrivateKey *pk; char *pids; cfg = config; /* load proof of work */ if (NULL == pwfn) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &pwfn)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE"); GNUNET_SCHEDULER_shutdown (); return; } } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Proof of Work file: %s\n", pwfn); if ( (GNUNET_YES != GNUNET_DISK_file_test (pwfn)) || (sizeof (proof) != GNUNET_DISK_fn_read (pwfn, &proof, sizeof (proof)))) proof = 0; /* load private key */ if (NULL == pkfn) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &pkfn)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "PEER", "PRIVATE_KEY"); return; } } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Private Key file: %s\n", pkfn); if (NULL == (pk = GNUNET_CRYPTO_eddsa_key_create_from_file (pkfn))) { FPRINTF (stderr, _("Loading hostkey from `%s' failed.\n"), pkfn); GNUNET_free (pkfn); return; } GNUNET_free (pkfn); GNUNET_CRYPTO_eddsa_key_get_public (pk, &pub); GNUNET_free (pk); pids = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer ID: %s\n", pids); GNUNET_free (pids); /* get target bit amount */ if (0 == nse_work_required) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS", &nse_work_required)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS"); GNUNET_SCHEDULER_shutdown (); return; } if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS", _("Value is too large.\n")); GNUNET_SCHEDULER_shutdown (); return; } else if (0 == nse_work_required) { write_proof (); GNUNET_SCHEDULER_shutdown (); return; } } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bits: %llu\n", nse_work_required); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delay between tries: %s\n", GNUNET_STRINGS_relative_time_to_string (proof_find_delay, 1)); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &find_proof, NULL); }
/** * Task triggered whenever we receive a SIGCHLD (child * process died). * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *pos; struct ServiceList *next; struct ServiceListeningInfo *sli; const char *statstr; int statcode; int ret; char c[16]; enum GNUNET_OS_ProcessStatusType statusType; unsigned long statusCode; const struct GNUNET_DISK_FileHandle *pr; pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); child_death_task = GNUNET_SCHEDULER_NO_TASK; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) { /* shutdown scheduled us, ignore! */ child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); return; } /* consume the signal */ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); /* check for services that died (WAITPID) */ next = running_head; while (NULL != (pos = next)) { next = pos->next; if (pos->proc == NULL) { if (GNUNET_YES == in_shutdown) free_service (pos); continue; } if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->proc, &statusType, &statusCode))) || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) || (statusType == GNUNET_OS_PROCESS_RUNNING))) continue; if (statusType == GNUNET_OS_PROCESS_EXITED) { statstr = _( /* process termination method */ "exit"); statcode = statusCode; } else if (statusType == GNUNET_OS_PROCESS_SIGNALED) { statstr = _( /* process termination method */ "signal"); statcode = statusCode; } else { statstr = _( /* process termination method */ "unknown"); statcode = 0; } if (0 != pos->killed_at.abs_value) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' took %llu ms to terminate\n"), pos->name, GNUNET_TIME_absolute_get_duration (pos->killed_at).rel_value); } GNUNET_OS_process_destroy (pos->proc); pos->proc = NULL; if (NULL != pos->killing_client) { signal_result (pos->killing_client, pos->name, GNUNET_ARM_PROCESS_DOWN); GNUNET_SERVER_client_drop (pos->killing_client); pos->killing_client = NULL; /* process can still be re-started on-demand, ensure it is re-started if there is demand */ for (sli = pos->listen_head; NULL != sli; sli = sli->next) { GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, &accept_connection, sli); } continue; } if (GNUNET_YES != in_shutdown) { if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) { /* process terminated normally, allow restart at any time */ pos->restart_at.abs_value = 0; } else { if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"), pos->name, statstr, statcode, pos->backoff.rel_value); /* schedule restart */ pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); pos->backoff = GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD, GNUNET_TIME_relative_multiply (pos->backoff, 2)); } if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) GNUNET_SCHEDULER_cancel (child_restart_task); child_restart_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); } else { free_service (pos); } } child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) do_shutdown (); }
/** * Handle network size estimate clients. * * @param cls closure * @param c configuration to use * @param service the initialized service */ static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service) { struct GNUNET_MQ_MessageHandler core_handlers[] = { GNUNET_MQ_hd_fixed_size (p2p_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, struct GNUNET_NSE_FloodMessage, NULL), GNUNET_MQ_handler_end () }; char *proof; struct GNUNET_CRYPTO_EddsaPrivateKey *pk; cfg = c; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL", &gnunet_nse_interval)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "INTERVAL"); GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY", &proof_find_delay)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKDELAY"); GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS", &nse_work_required)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS"); GNUNET_SCHEDULER_shutdown (); return; } if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS", _("Value is too large.\n")); GNUNET_SCHEDULER_shutdown (); return; } #if ENABLE_NSE_HISTOGRAM { char *histogram_dir; char *histogram_fn; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM_DIR", &histogram_dir)) { GNUNET_assert (0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir)); GNUNET_free (histogram_dir); histogram = GNUNET_BIO_write_open (histogram_fn); if (NULL == histogram) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to open histogram file `%s'\n", histogram_fn); GNUNET_free (histogram_fn); } logger_test = GNUNET_CLIENT_service_test ("testbed-logger", cfg, GNUNET_TIME_UNIT_SECONDS, &status_cb, NULL); } #endif GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); pk = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg); GNUNET_assert (NULL != pk); my_private_key = pk; GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE"); GNUNET_free (my_private_key); my_private_key = NULL; GNUNET_SCHEDULER_shutdown (); return; } if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) || (sizeof (my_proof) != GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof)))) my_proof = 0; GNUNET_free (proof); proof_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &find_proof, NULL); peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); nc = GNUNET_notification_context_create (1); /* Connect to core service and register core handlers */ core_api = GNUNET_CORE_connect (cfg, /* Main configuration */ NULL, /* Closure passed to functions */ &core_init, /* Call core_init once connected */ &handle_core_connect, /* Handle connects */ &handle_core_disconnect, /* Handle disconnects */ core_handlers); /* Register these handlers */ if (NULL == core_api) { GNUNET_SCHEDULER_shutdown (); return; } stats = GNUNET_STATISTICS_create ("nse", cfg); }