Example #1
0
/**
 * 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;
}
Example #4
0
/**
 * 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;
  }
}
Example #5
0
/**
 * 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);
}
Example #6
0
/**
 * 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 */
}
Example #9
0
/**
 * 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);
}
Example #10
0
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 */
}