/** * Connection notifies us about failure or success of a transmission * request. Either pass it on to our user or, if possible, retry. * * @param cls our "struct GNUNET_CLIENT_TransmissionHandle" * @param size number of bytes available for transmission * @param buf where to write them * @return number of bytes written to buf */ static size_t client_notify (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_TransmitHandle *th = cls; struct GNUNET_CLIENT_Connection *client = th->client; size_t ret; struct GNUNET_TIME_Relative delay; th->th = NULL; client->th = NULL; if (NULL == buf) { delay = GNUNET_TIME_absolute_get_remaining (th->timeout); delay.rel_value /= 2; if ((GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || (delay.rel_value < 1)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, giving up.\n", MAX_ATTEMPTS - th->attempts_left); GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); return 0; } /* auto-retry */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect to `%s', automatically trying again.\n", client->service_name); if (GNUNET_YES == client->in_receive) { GNUNET_CONNECTION_receive_cancel (client->connection); client->in_receive = GNUNET_NO; } GNUNET_CONNECTION_destroy (client->connection); client->connection = NULL; delay = GNUNET_TIME_relative_min (delay, client->back_off); client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %s.\n", MAX_ATTEMPTS - th->attempts_left, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); client->th = th; th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return 0; } GNUNET_assert (size >= th->size); ret = th->notify (th->notify_cls, size, buf); GNUNET_free (th); return ret; }
/** * Function called for all addresses and peers to find the minimum and * maximum (averaged) values for a given quality property. Given * those, we can then calculate the normalized score. * * @param cls the `struct PropertyRange` * @param h which peer are we looking at (ignored) * @param k the address for that peer * @return #GNUNET_OK (continue to iterate) */ static int find_min_max_it (void *cls, const struct GNUNET_PeerIdentity *h, void *k) { struct PropertyRange *pr = cls; const struct ATS_Address *a = k; pr->max.utilization_out = GNUNET_MAX (pr->max.utilization_out, a->properties.utilization_out); pr->max.utilization_in = GNUNET_MAX (pr->max.utilization_in, a->properties.utilization_in); pr->max.distance = GNUNET_MAX (pr->max.distance, a->properties.distance); pr->max.delay = GNUNET_TIME_relative_max (pr->max.delay, a->properties.delay); pr->min.utilization_out = GNUNET_MIN (pr->min.utilization_out, a->properties.utilization_out); pr->min.utilization_in = GNUNET_MIN (pr->min.utilization_in, a->properties.utilization_in); pr->min.distance = GNUNET_MIN (pr->min.distance, a->properties.distance); pr->min.delay = GNUNET_TIME_relative_min (pr->min.delay, a->properties.delay); return GNUNET_OK; }
/** * Find a peer that would be reasonable for advertising. * * @param cls closure * @param pid identity of a peer * @param value 'struct Peer*' for the peer we are considering * @return GNUNET_YES (continue iteration) */ static int find_advertisable_hello (void *cls, const struct GNUNET_HashCode * pid, void *value) { struct FindAdvHelloContext *fah = cls; struct Peer *pos = value; struct GNUNET_TIME_Relative rst_time; size_t hs; if (pos == fah->peer) return GNUNET_YES; if (pos->hello == NULL) return GNUNET_YES; rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); if (0 == rst_time.rel_value) { /* time to discard... */ GNUNET_CONTAINER_bloomfilter_free (pos->filter); setup_filter (pos); } fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv); hs = GNUNET_HELLO_size (pos->hello); if (hs > fah->max_size) return GNUNET_YES; if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (pos->filter, &fah->peer->pid.hashPubKey)) fah->result = pos; return GNUNET_YES; }
/** * This task is run if we should re-try connection to the * service after a while. * * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request * @param tc unused */ static void client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CLIENT_TransmitHandle *th = cls; struct GNUNET_TIME_Relative delay; th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; th->client->connection = do_connect (th->client->service_name, th->client->cfg, th->client->attempts++); th->client->first_message = GNUNET_YES; if (NULL == th->client->connection) { /* could happen if we're out of sockets */ delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (th->timeout), th->client->back_off); th->client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (th->client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %s.\n", MAX_ATTEMPTS - th->attempts_left, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return; } th->th = GNUNET_CONNECTION_notify_transmit_ready (th->client->connection, th->size, GNUNET_TIME_absolute_get_remaining (th->timeout), &client_notify, th); if (NULL == th->th) { GNUNET_break (0); th->client->th = NULL; th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); return; } }
/** * Calculate when to run the next PUT operation and schedule it. * * @param po put operator to schedule */ static void schedule_next_put (struct PutOperator *po) { struct GNUNET_TIME_Relative delay; if (po->zero_anonymity_count_estimate > 0) { delay = GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY, po->zero_anonymity_count_estimate); delay = GNUNET_TIME_relative_min (delay, MAX_DHT_PUT_FREQ); } else { /* if we have NO zero-anonymity content yet, wait 5 minutes for some to * (hopefully) appear */ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5); } po->dht_task = GNUNET_SCHEDULER_add_delayed (delay, &gather_dht_put_blocks, po); }
/** * Disconnect from the service (communication error) and reconnect later. * * @param vh handle to reconnect. */ static void reconnect (struct GNUNET_VPN_Handle *vh) { struct GNUNET_VPN_RedirectionRequest *rr; if (NULL != vh->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); vh->th = NULL; } GNUNET_CLIENT_disconnect (vh->client); vh->client = NULL; vh->request_id_gen = 0; for (rr = vh->rr_head; NULL != rr; rr = rr->next) rr->request_id = 0; vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff, &connect_task, vh); }
void GNUNET_ATS_TEST_traffic_handle_pong (struct BenchmarkPartner *p) { struct GNUNET_TIME_Relative left; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master [%u]: Received PONG from [%u], next message\n", p->me->no, p->dest->no); p->messages_received++; p->bytes_received += TEST_MESSAGE_SIZE; p->me->total_messages_received++; p->me->total_bytes_received += TEST_MESSAGE_SIZE; p->total_app_rtt += GNUNET_TIME_absolute_get_difference(p->last_message_sent, GNUNET_TIME_absolute_get()).rel_value_us; /* Schedule next send event */ if (NULL == p->tg) return; left = GNUNET_TIME_absolute_get_remaining(p->tg->next_ping_transmission); if (UINT32_MAX == p->tg->base_rate) { p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p); } else if (0 == left.rel_value_us) { p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p); } else { /* Enforce minimum transmission rate 1 msg / sec */ if (GNUNET_TIME_UNIT_SECONDS.rel_value_us == (left = GNUNET_TIME_relative_min (left, GNUNET_TIME_UNIT_SECONDS)).rel_value_us) GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Enforcing minimum send rate between master [%u] and slave [%u]\n", p->me->no, p->dest->no); p->tg->send_task = GNUNET_SCHEDULER_add_delayed (left, &comm_schedule_send, p); } }
/** * Try to connect to the specified peer. * * @param pos peer to connect to */ static void attempt_connect (struct Peer *pos) { struct GNUNET_TIME_Relative rem; if ((connection_count >= target_connection_count) && (friend_count >= minimum_friend_count)) return; if (GNUNET_YES == pos->is_connected) return; if (GNUNET_OK != is_connection_allowed (pos)) return; if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) return; if (GNUNET_YES == pos->is_friend) rem = GREYLIST_AFTER_ATTEMPT_FRIEND; else rem = GREYLIST_AFTER_ATTEMPT; rem = GNUNET_TIME_relative_multiply (rem, connection_count); rem = GNUNET_TIME_relative_divide (rem, target_connection_count); if (pos->connect_attempts > 30) pos->connect_attempts = 30; rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts)); rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN); rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX); pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem); if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); pos->greylist_clean_task = GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n", GNUNET_i2s (&pos->pid)); GNUNET_STATISTICS_update (stats, gettext_noop ("# connect requests issued to transport"), 1, GNUNET_NO); GNUNET_TRANSPORT_try_connect (transport, &pos->pid, NULL, NULL); /*FIXME TRY_CONNECT change */ }
/** * Try to establish a connection given the specified address. * This function is called by the resolver once we have a DNS reply. * * @param cls our "struct GNUNET_CONNECTION_Handle *" * @param addr address to try, NULL for "last call" * @param addrlen length of addr */ static void try_connect_using_address (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_CONNECTION_Handle *connection = cls; struct AddressProbe *ap; struct GNUNET_TIME_Relative delay; if (NULL == addr) { connection->dns_active = NULL; if ((NULL == connection->ap_head) && (NULL == connection->sock)) connect_fail_continuation (connection); return; } if (NULL != connection->sock) return; /* already connected */ GNUNET_assert (NULL == connection->addr); /* try to connect */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect using address `%s:%u/%s:%u'\n", connection->hostname, connection->port, GNUNET_a2s (addr, addrlen), connection->port); ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); ap->addr = (const struct sockaddr *) &ap[1]; memcpy (&ap[1], addr, addrlen); ap->addrlen = addrlen; ap->connection = connection; switch (ap->addr->sa_family) { case AF_INET: ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port); break; case AF_INET6: ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port); break; default: GNUNET_break (0); GNUNET_free (ap); return; /* not supported by us */ } ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0); if (NULL == ap->sock) { GNUNET_free (ap); return; /* not supported by OS */ } LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) && (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); #if 0 LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); #endif GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); return; } GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; if (NULL != connection->nth.notify_ready) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection-> nth.transmit_timeout)); if (NULL != connection->receiver) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection->receive_timeout)); ap->task = GNUNET_SCHEDULER_add_write_net (delay, ap->sock, &connect_probe_continuation, ap); }
int main (int argc, char *argv[]) { struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_AbsoluteNBO nown; struct GNUNET_TIME_Absolute future; struct GNUNET_TIME_Absolute past; struct GNUNET_TIME_Absolute last; struct GNUNET_TIME_Absolute forever; struct GNUNET_TIME_Absolute zero; struct GNUNET_TIME_Relative rel; struct GNUNET_TIME_Relative relForever; struct GNUNET_TIME_Relative relUnit; struct GNUNET_TIME_RelativeNBO reln; unsigned int i; GNUNET_log_setup ("test-time", "WARNING", NULL); forever = GNUNET_TIME_UNIT_FOREVER_ABS; relForever = GNUNET_TIME_UNIT_FOREVER_REL; relUnit = GNUNET_TIME_UNIT_MILLISECONDS; zero.abs_value_us = 0; last = now = GNUNET_TIME_absolute_get (); while (now.abs_value_us == last.abs_value_us) now = GNUNET_TIME_absolute_get (); GNUNET_assert (now.abs_value_us > last.abs_value_us); /* test overflow checking in multiply */ rel = GNUNET_TIME_UNIT_MILLISECONDS; GNUNET_log_skip (1, GNUNET_NO); for (i = 0; i < 55; i++) rel = GNUNET_TIME_relative_multiply (rel, 2); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us); /*check zero */ rel.rel_value_us = (UINT64_MAX) - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == GNUNET_TIME_relative_multiply (rel, 0).rel_value_us); /* test infinity-check for relative to absolute */ GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_assert (last.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us); GNUNET_log_skip (0, GNUNET_YES); /* check relative to absolute */ rel.rel_value_us = 1000000; GNUNET_assert (GNUNET_TIME_absolute_get ().abs_value_us < GNUNET_TIME_relative_to_absolute (rel).abs_value_us); /*check forever */ rel.rel_value_us = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == GNUNET_TIME_relative_to_absolute (rel).abs_value_us); /* check overflow for r2a */ rel.rel_value_us = (UINT64_MAX) - 1024; GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (last.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us); /* check overflow for relative add */ GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (rel, rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relForever, relForever); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == relForever.rel_value_us); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relUnit, relUnit); GNUNET_assert (rel.rel_value_us == 2 * relUnit.rel_value_us); /* check relation check in get_duration */ future.abs_value_us = now.abs_value_us + 1000000; GNUNET_assert (GNUNET_TIME_absolute_get_difference (now, future).rel_value_us == 1000000); GNUNET_assert (GNUNET_TIME_absolute_get_difference (future, now).rel_value_us == 0); GNUNET_assert (GNUNET_TIME_absolute_get_difference (zero, forever).rel_value_us == forever.abs_value_us); past.abs_value_us = now.abs_value_us - 1000000; rel = GNUNET_TIME_absolute_get_duration (future); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_duration (past); GNUNET_assert (rel.rel_value_us >= 1000000); /* check get remaining */ rel = GNUNET_TIME_absolute_get_remaining (now); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_remaining (past); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_remaining (future); GNUNET_assert (rel.rel_value_us > 0); GNUNET_assert (rel.rel_value_us <= 1000000); forever = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == GNUNET_TIME_absolute_get_remaining (forever).rel_value_us); /* check endianess */ reln = GNUNET_TIME_relative_hton (rel); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_relative_ntoh (reln).rel_value_us); nown = GNUNET_TIME_absolute_hton (now); GNUNET_assert (now.abs_value_us == GNUNET_TIME_absolute_ntoh (nown).abs_value_us); /* check absolute addition */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_SECONDS); GNUNET_assert (future.abs_value_us == now.abs_value_us + 1000 * 1000LL); future = GNUNET_TIME_absolute_add (forever, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value_us == forever.abs_value_us); rel.rel_value_us = (UINT64_MAX) - 1024; now.abs_value_us = rel.rel_value_us; future = GNUNET_TIME_absolute_add (now, rel); GNUNET_assert (future.abs_value_us == forever.abs_value_us); /* check zero */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value_us == now.abs_value_us); GNUNET_assert (forever.abs_value_us == GNUNET_TIME_absolute_subtract (forever, GNUNET_TIME_UNIT_MINUTES).abs_value_us); /*check absolute subtract */ now.abs_value_us = 50000; rel.rel_value_us = 100000; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value_us); rel.rel_value_us = 10000; GNUNET_assert (40000 == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value_us); /*check relative divide */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_relative_divide (rel, 0)).rel_value_us); rel = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_relative_divide (rel, 2)).rel_value_us); rel = GNUNET_TIME_relative_divide (relUnit, 2); GNUNET_assert (rel.rel_value_us == relUnit.rel_value_us / 2); /* check Return absolute time of 0ms */ zero = GNUNET_TIME_UNIT_ZERO_ABS; /* check GNUNET_TIME_calculate_eta */ last.abs_value_us = GNUNET_TIME_absolute_get ().abs_value_us - 1024; forever = GNUNET_TIME_UNIT_FOREVER_ABS; forever.abs_value_us = forever.abs_value_us - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == GNUNET_TIME_calculate_eta (forever, 50000, 100000).rel_value_us); /* check zero */ GNUNET_log_skip (1, GNUNET_NO); GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == (GNUNET_TIME_calculate_eta (last, 60000, 50000)).rel_value_us); GNUNET_log_skip (0, GNUNET_YES); /*check forever */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_calculate_eta (last, 0, 50000)).rel_value_us); /*check relative subtract */ now = GNUNET_TIME_absolute_get (); rel.rel_value_us = now.abs_value_us; relForever.rel_value_us = rel.rel_value_us + 1024; GNUNET_assert (1024 == GNUNET_TIME_relative_subtract (relForever, rel).rel_value_us); /*check zero */ GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us); /*check forever */ rel.rel_value_us = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us); /*check GNUNET_TIME_relative_min */ now = GNUNET_TIME_absolute_get (); rel.rel_value_us = now.abs_value_us; relForever.rel_value_us = rel.rel_value_us - 1024; GNUNET_assert (relForever.rel_value_us == GNUNET_TIME_relative_min (rel, relForever).rel_value_us); /*check GNUNET_TIME_relative_max */ GNUNET_assert (rel.rel_value_us == GNUNET_TIME_relative_max (rel, relForever).rel_value_us); /*check GNUNET_TIME_absolute_min */ now = GNUNET_TIME_absolute_get (); last.abs_value_us = now.abs_value_us - 1024; GNUNET_assert (last.abs_value_us == GNUNET_TIME_absolute_min (now, last).abs_value_us); /*check GNUNET_TIME_absolute_max */ GNUNET_assert (now.abs_value_us == GNUNET_TIME_absolute_max (now, last).abs_value_us); return 0; }
/** * 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 (); }
/** * Task run whenever it is time to restart a child that died. * * @param cls closure, always NULL * @param tc context */ static void delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *sl; struct GNUNET_TIME_Relative lowestRestartDelay; struct ServiceListeningInfo *sli; child_restart_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_assert (GNUNET_NO == in_shutdown); lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL; /* check for services that need to be restarted due to * configuration changes or because the last restart failed */ for (sl = running_head; NULL != sl; sl = sl->next) { if (NULL != sl->proc) continue; /* service is currently not running */ if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value == 0) { /* restart is now allowed */ if (sl->is_default) { /* process should run by default, start immediately */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Restarting service `%s'.\n"), sl->name); start_process (sl); } else { /* process is run on-demand, ensure it is re-started if there is demand */ for (sli = sl->listen_head; NULL != sli; sli = sli->next) if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task) { /* accept was actually paused, so start it again */ sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, &accept_connection, sli); } } } else { /* update calculation for earliest time to reactivate a service */ lowestRestartDelay = GNUNET_TIME_relative_min (lowestRestartDelay, GNUNET_TIME_absolute_get_remaining (sl->restart_at)); } } if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will restart process in %llums\n", (unsigned long long) lowestRestartDelay.rel_value); child_restart_task = GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay, GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); } }
/** * Periodically announce self id in the DHT * * @param cls closure */ static void announce_id (void *cls) { struct GNUNET_HashCode phash; const struct GNUNET_HELLO_Message *hello; size_t size; struct GNUNET_TIME_Absolute expiration; struct GNUNET_TIME_Relative next_put; hello = GCH_get_mine (); size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0; if (0 == size) { expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), announce_delay); announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay); } else { expiration = GNUNET_HELLO_get_last_expiration (hello); announce_delay = GNUNET_TIME_UNIT_SECONDS; } /* Call again in id_announce_time, unless HELLO expires first, * but wait at least 1s. */ next_put = GNUNET_TIME_absolute_get_remaining (expiration); next_put = GNUNET_TIME_relative_min (next_put, id_announce_time); next_put = GNUNET_TIME_relative_max (next_put, GNUNET_TIME_UNIT_SECONDS); announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put, &announce_id, cls); GNUNET_STATISTICS_update (stats, "# DHT announce", 1, GNUNET_NO); memset (&phash, 0, sizeof (phash)); GNUNET_memcpy (&phash, &my_full_id, sizeof (my_full_id)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Announcing my HELLO (%u bytes) in the DHT\n", size); GNUNET_DHT_put (dht_handle, /* DHT handle */ &phash, /* Key to use */ dht_replication_level, /* Replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ size, /* Size of the data */ (const char *) hello, /* Data itself */ expiration, /* Data expiration */ NULL, /* Continuation */ NULL); /* Continuation closure */ }