static int
watch_1 (void *cls, const char *subsystem, const char *name, uint64_t value,
         int is_persistent)
{
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value `%s' `%s' %llu\n",
      subsystem, name, value);
  GNUNET_assert (0 == strcmp (name, "test-1"));
  if ((0 == value) && (3 == ok))
  {
    ok--;
    GNUNET_STATISTICS_set (h, "test-1", 42, GNUNET_NO);
  }

  if ((42 == value) && (2 == ok))
  {
    ok--;
    GNUNET_STATISTICS_set (h, "test-1", 0, GNUNET_NO);
  }

  if ((0 == value) && (1 == ok))
  {
    ok--;
  }
  if ((0 == ok) && (0 == ok2))
  {
    GNUNET_SCHEDULER_cancel (shutdown_task);
    GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL);
  }

  return GNUNET_OK;
}
/**
 * Synchronize our utilization statistics with the
 * statistics service.
 */
static void
sync_stats ()
{
  GNUNET_STATISTICS_set (stats, quota_stat_name, payload, GNUNET_YES);
  GNUNET_STATISTICS_set (stats, "# utilization by current datastore", payload, GNUNET_NO);
  lastSync = 0;
}
Esempio n. 3
0
/**
 * Method called whenever a peer connects.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 * @param mq message queue for communicating with @a peer
 * @return our `struct Peer` for @a peer
 */
static void *
connect_notify (void *cls,
                const struct GNUNET_PeerIdentity *peer,
		struct GNUNET_MQ_Handle *mq)
{
  struct Peer *pos;
  uint64_t flags;
  const void *extra;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we are connecting to `%s'\n",
              GNUNET_i2s (peer));
  if (0 == memcmp (&my_identity,
                   peer,
                   sizeof (struct GNUNET_PeerIdentity)))
    return NULL;
  extra = GNUNET_CORE_get_mq_options (GNUNET_YES,
				      GNUNET_CORE_PRIO_BEST_EFFORT,
				      &flags);
  GNUNET_MQ_set_options (mq,
			 flags,
			 extra);
  connection_count++;
  GNUNET_STATISTICS_set (stats,
                         gettext_noop ("# peers connected"),
                         connection_count,
                         GNUNET_NO);
  pos = GNUNET_CONTAINER_multipeermap_get (peers,
                                           peer);
  if (NULL == pos)
  {
    pos = make_peer (peer,
                     NULL,
                     GNUNET_NO);
  }
  else
  {
    GNUNET_assert (NULL == pos->mq);
  }
  pos->mq = mq;
  if (pos->is_friend)
  {
    friend_count++;
    if ( (friend_count == minimum_friend_count) &&
         (GNUNET_YES != friends_only) )
      whitelist_peers ();
    GNUNET_STATISTICS_set (stats,
                           gettext_noop ("# friends connected"),
                           friend_count,
                           GNUNET_NO);
  }
  reschedule_hellos (NULL,
                     peer,
                     pos);
  return pos;
}
/**
 * Provide an update on the `p2a` map size to statistics.
 * This function should be called whenever the `p2a` map
 * is changed.
 */
static void
publish_p2a_stat_update ()
{
  GNUNET_STATISTICS_set (GST_stats,
			 gettext_noop ("# Addresses given to ATS"),
			 GNUNET_CONTAINER_multipeermap_size (p2a) - num_blocked,
			 GNUNET_NO);
  GNUNET_STATISTICS_set (GST_stats,
                         "# blocked addresses",
                         num_blocked,
                         GNUNET_NO);
}
Esempio n. 5
0
static void
run (void *cls, char *const *args, const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  h = GNUNET_STATISTICS_create ("test-statistics-api", cfg);
  GNUNET_STATISTICS_set (h, "test-1", 1, GNUNET_NO);
  GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO);
  GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO);
  GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n");
  GNUNET_break (NULL !=
                GNUNET_STATISTICS_get (h, NULL, "test-1",
                                       GNUNET_TIME_UNIT_SECONDS, &next,
                                       &check_1, cls));
}
/**
 * Method called whenever a peer disconnects.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 */
static void
disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
{
  struct Peer *pos;

  if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
    return;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we disconnected from `%s'\n",
              GNUNET_i2s (peer));
  pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
  if (NULL == pos)
  {
    GNUNET_break (0);
    return;
  }
  if (pos->is_connected != GNUNET_YES)
  {
    GNUNET_break (0);
    return;
  }
  pos->is_connected = GNUNET_NO;
  connection_count--;
  if (NULL != pos->hello_req)
  {
    GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
    pos->hello_req = NULL;
  }
  if (GNUNET_SCHEDULER_NO_TASK != pos->hello_delay_task)
  {
    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
    pos->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
  }
  GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"),
                         connection_count, GNUNET_NO);
  if (pos->is_friend)
  {
    friend_count--;
    GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"),
                           friend_count, GNUNET_NO);
  }
  if (((connection_count < target_connection_count) ||
       (friend_count < minimum_friend_count)) &&
      (GNUNET_SCHEDULER_NO_TASK == add_task))
    add_task = GNUNET_SCHEDULER_add_now (&add_peer_task, NULL);
  if ((friend_count < minimum_friend_count) && (blacklist == NULL))
    blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL);
}
/**
 * Notify the plan about a request being done; destroy all entries
 * associated with this request.
 *
 * @param pr request that is done
 */
void
GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr)
{
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestData *prd;
  struct GSF_PendingRequestPlanBijection *bi;

  prd = GSF_pending_request_get_data_ (pr);
  while (NULL != (bi = prd->pr_head))
  {
    rp = bi->rp;
    GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
    GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
    if (NULL == rp->pe_head)
    {
      GNUNET_CONTAINER_heap_remove_node (rp->hn);
      plan_count--;
      GNUNET_break (GNUNET_YES ==
                    GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map,
							  &GSF_pending_request_get_data_
							  (bi->pr)->query,
                                                          rp));
      GNUNET_free (rp);
    }
    GNUNET_free (bi);
  }
  GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"),
                         plan_count, GNUNET_NO);
}
/**
 * Create a session, a key exchange was just completed.
 *
 * @param peer peer that is now connected
 * @param kx key exchange that completed
 */
void
GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer,
                     struct GSC_KeyExchangeInfo *kx)
{
  struct Session *session;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Creating session for peer `%4s'\n",
              GNUNET_i2s (peer));
  session = GNUNET_new (struct Session);
  session->tmap = GSC_TYPEMAP_create ();
  session->peer = *peer;
  session->kxinfo = kx;
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_put (sessions,
                                                    &session->peer,
                                                    session,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"),
                         GNUNET_CONTAINER_multipeermap_size (sessions),
                         GNUNET_NO);
  GSC_CLIENTS_notify_clients_about_neighbour (peer,
                                              NULL,
                                              session->tmap);
  start_typemap_task (session);
}
Esempio n. 9
0
/**
 * Method called whenever a peer disconnects.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 * @param internal_cls the `struct Peer` for this peer
 */
static void
disconnect_notify (void *cls,
                   const struct GNUNET_PeerIdentity *peer,
		   void *internal_cls)
{
  struct Peer *pos = internal_cls;

  if (NULL == pos)
    return; /* myself, we're shutting down */
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we disconnected from `%s'\n",
              GNUNET_i2s (peer));
  if (NULL == pos->mq)
  {
    GNUNET_break (0);
    return;
  }
  pos->mq = NULL;
  connection_count--;
  if (NULL != pos->hello_delay_task)
  {
    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
    pos->hello_delay_task = NULL;
  }
  GNUNET_STATISTICS_set (stats,
                         gettext_noop ("# peers connected"),
                         connection_count,
                         GNUNET_NO);
  if (pos->is_friend)
  {
    friend_count--;
    GNUNET_STATISTICS_set (stats,
                           gettext_noop ("# friends connected"),
                           friend_count,
                           GNUNET_NO);
  }
  if ( ( (connection_count < target_connection_count) ||
         (friend_count < minimum_friend_count)) &&
       (NULL == add_task) )
    add_task = GNUNET_SCHEDULER_add_now (&add_peer_task,
                                         NULL);
  if ( (friend_count < minimum_friend_count) &&
       (NULL == blacklist))
    blacklist = GNUNET_TRANSPORT_blacklist (cfg,
                                            &blacklist_check,
                                            NULL);
}
Esempio n. 10
0
/**
 * Figure out when and how to transmit to the given peer.
 *
 * @param cls the 'struct PeerPlan'
 * @param tc scheduler context
 */
static void
schedule_peer_transmission (void *cls,
                            const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct PeerPlan *pp = cls;
  struct GSF_RequestPlan *rp;
  size_t msize;
  struct GNUNET_TIME_Relative delay;

  pp->task = GNUNET_SCHEDULER_NO_TASK;
  if (NULL != pp->pth)
  {
    GSF_peer_transmit_cancel_ (pp->pth);
    pp->pth = NULL;
  }
  /* move ready requests to priority queue */
  while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) &&
         (GNUNET_TIME_absolute_get_remaining
          (rp->earliest_transmission).rel_value == 0))
  {
    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 %llu ms before retrying requests on plan %p.\n",
                (unsigned long long) delay.rel_value, pp);
    GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"),
                           delay.rel_value, GNUNET_NO);

    pp->task =
        GNUNET_SCHEDULER_add_delayed (delay, &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_peek (pp->priority_heap);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp);
  GNUNET_assert (NULL != rp);
  msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL);
  pp->pth =
      GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority,
                          GNUNET_TIME_UNIT_FOREVER_REL, msize,
                          &transmit_message_callback, pp);
  GNUNET_assert (NULL != pp->pth);
}
/**
 * Connect both PUT and GET connection for a session
 * 
 * @param s the session to connect
 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
 */
static int
client_connect (struct Session *s)
{

  struct HTTP_Client_Plugin *plugin = s->plugin;
  int res = GNUNET_OK;


  /* create url */
  if (NULL == http_common_plugin_address_to_string (NULL, s->addr, s->addrlen))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                     "Invalid address peer `%s'\n",
                     GNUNET_i2s (&s->target));
    return GNUNET_SYSERR;
  }

  GNUNET_asprintf (&s->url, "%s/%s;%u",
      http_common_plugin_address_to_string (plugin, s->addr, s->addrlen),
                   GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey),
                   plugin->last_tag);

  plugin->last_tag++;

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                   "Initiating outbound session peer `%s' using address `%s'\n",
                   GNUNET_i2s (&s->target), s->url);

  if ((GNUNET_SYSERR == client_connect_get (s)) ||
      (GNUNET_SYSERR == client_connect_put (s)))
  {
      GNUNET_break (0);
      return GNUNET_SYSERR;
  }

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
               "Session %p: connected with connections GET %p and PUT %p\n",
               s, s->client_get, s->client_put);

  /* Perform connect */
  plugin->cur_connections += 2;
  GNUNET_STATISTICS_set (plugin->env->stats,
      "# HTTP client connections",
      plugin->cur_connections,
      GNUNET_NO);

  /* Re-schedule since handles have changed */
  if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
    plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
  }
  plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin);
  return res;
}
/**
 * Some (significant) input changed, recalculate bandwidth assignment
 * for all peers.
 */
static void
recalculate_assigned_bw ()
{
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Recalculating bandwidth for all active connections\n");
  GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
                            1, GNUNET_NO);
  GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count,
                         GNUNET_NO);

  GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL);
}
Esempio n. 13
0
static void
run (void *cls,
     char *const *args,
     const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  h = GNUNET_STATISTICS_create ("dummy", cfg);
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_STATISTICS_watch (h, "test-statistics-api-watch",
                                          "test-1", &watch_1, NULL));
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_STATISTICS_watch (h, "test-statistics-api-watch",
                                          "test-2", &watch_2, NULL));
  h2 = GNUNET_STATISTICS_create ("test-statistics-api-watch", cfg);
  GNUNET_STATISTICS_set (h2, "test-1", 42, GNUNET_NO);
  GNUNET_STATISTICS_set (h2, "test-2", 43, GNUNET_NO);
  shutdown_task =
      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
				    &force_shutdown,
                                    NULL);
}
/**
 * Method called whenever a peer connects.
 *
 * @param cls closure
 * @param peer peer identity this notification is about
 * @param atsi performance data
 * @param atsi_count number of records in 'atsi'
 */
static void
connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer,
                const struct GNUNET_ATS_Information *atsi,
                unsigned int atsi_count)
{
  struct Peer *pos;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we are connecting to `%s'\n",
              GNUNET_i2s (peer));
  if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
    return;

  connection_count++;
  GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"),
                         connection_count, GNUNET_NO);
  pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
  if (NULL == pos)
  {
    pos = make_peer (peer, NULL, GNUNET_NO);
    GNUNET_break (GNUNET_OK == is_connection_allowed (pos));
  }
  else
  {
    GNUNET_assert (GNUNET_NO == pos->is_connected);
    pos->greylisted_until.abs_value = 0;        /* remove greylisting */
  }
  pos->is_connected = GNUNET_YES;
  pos->connect_attempts = 0;    /* re-set back-off factor */
  if (pos->is_friend)
  {
    if ((friend_count == minimum_friend_count - 1) &&
        (GNUNET_YES != friends_only))
      whitelist_peers ();
    friend_count++;
    GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"),
                           friend_count, GNUNET_NO);
  }
  reschedule_hellos (NULL, &peer->hashPubKey, pos);
}
/**
 * End the session with the given peer (we are no longer
 * connected).
 *
 * @param pid identity of peer to kill session with
 */
void
GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid)
{
  struct Session *session;
  struct GSC_ClientActiveRequest *car;
  struct SessionMessageEntry *sme;

  session = find_session (pid);
  if (NULL == session)
    return;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Destroying session for peer `%4s'\n",
              GNUNET_i2s (&session->peer));
  if (NULL != session->cork_task)
  {
    GNUNET_SCHEDULER_cancel (session->cork_task);
    session->cork_task = NULL;
  }
  while (NULL != (car = session->active_client_request_head))
  {
    GNUNET_CONTAINER_DLL_remove (session->active_client_request_head,
                                 session->active_client_request_tail, car);
    GSC_CLIENTS_reject_request (car,
                                GNUNET_NO);
  }
  while (NULL != (sme = session->sme_head))
  {
    GNUNET_CONTAINER_DLL_remove (session->sme_head,
                                 session->sme_tail,
                                 sme);
    GNUNET_free (sme);
  }
  if (NULL != session->typemap_task)
  {
    GNUNET_SCHEDULER_cancel (session->typemap_task);
    session->typemap_task = NULL;
  }
  GSC_CLIENTS_notify_clients_about_neighbour (&session->peer,
                                              session->tmap, NULL);
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multipeermap_remove (sessions,
                                                       &session->peer,
                                                       session));
  GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"),
                         GNUNET_CONTAINER_multipeermap_size (sessions),
                         GNUNET_NO);
  GSC_TYPEMAP_destroy (session->tmap);
  session->tmap = NULL;
  GNUNET_free (session);
}
/**
 * Update statistics
 *
 * @param m peermap to update values from
 */
static void
update_stats (struct GNUNET_CONTAINER_MultiPeerMap *m)
{
  GNUNET_assert (NULL != m);
  GNUNET_assert (NULL != GED_stats);

  if (m == nodes_active)
  {
    GNUNET_STATISTICS_set (GED_stats, "# nodes active",
			   GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO);
  }
  else if (m == nodes_inactive)
  {
    GNUNET_STATISTICS_set (GED_stats, "# nodes inactive",
			   GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO);
  }
  else if (m == nodes_requested)
  {
    GNUNET_STATISTICS_set (GED_stats, "# nodes requested",
			   GNUNET_CONTAINER_multipeermap_size(m), GNUNET_NO);
  }
  else
    GNUNET_break (0);
}
/**
 * Free the given entry for the neighbour.
 *
 * @param n neighbour to free
 */
static void
free_neighbour (struct Neighbour *n)
{
  struct NeighbourMessageEntry *m;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Destroying neighbour entry for peer `%s'\n",
              GNUNET_i2s (&n->peer));
  while (NULL != (m = n->message_head))
  {
    GNUNET_CONTAINER_DLL_remove (n->message_head,
                                 n->message_tail,
                                 m);
    n->queue_size--;
    GNUNET_free (m);
  }
  GNUNET_assert (0 == n->queue_size);
  if (NULL != n->th)
  {
    GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
    n->th = NULL;
  }
  GNUNET_STATISTICS_update (GSC_stats,
                            gettext_noop
                            ("# sessions terminated by transport disconnect"),
                            1, GNUNET_NO);
  if (NULL != n->kxinfo)
  {
    GSC_KX_stop (n->kxinfo);
    n->kxinfo = NULL;
  }
  if (NULL != n->retry_plaintext_task)
  {
    GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
    n->retry_plaintext_task = NULL;
  }
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_remove (neighbours,
                                                       &n->peer, n));
  GNUNET_STATISTICS_set (GSC_stats,
                         gettext_noop ("# neighbour entries allocated"),
                         GNUNET_CONTAINER_multipeermap_size (neighbours),
                         GNUNET_NO);
  GNUNET_free (n);
}
static int
put_property (struct SysmonProperty *sp)
{
  if (v_numeric ==sp->value_type)
  {
      GNUNET_STATISTICS_set (stats, sp->desc, sp->num_val, GNUNET_NO);
  }
  else if (v_string ==sp->value_type)
  {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
  }
  else
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  return GNUNET_OK;
}
/**
 * Function called by transport to notify us that
 * a peer connected to us (on the network level).
 *
 * @param cls closure
 * @param peer the peer that connected
 */
static void
handle_transport_notify_connect (void *cls,
                                 const struct GNUNET_PeerIdentity *peer)
{
  struct Neighbour *n;

  if (0 == memcmp (peer,
                   &GSC_my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break (0);
    return;
  }
  n = find_neighbour (peer);
  if (NULL != n)
  {
    /* duplicate connect notification!? */
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s exists already\n",
                GNUNET_i2s (peer));
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received connection from `%s'.\n",
              GNUNET_i2s (peer));
  n = GNUNET_new (struct Neighbour);
  n->peer = *peer;
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_put (neighbours,
                                                    &n->peer,
                                                    n,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  GNUNET_STATISTICS_set (GSC_stats,
                         gettext_noop ("# neighbour entries allocated"),
                         GNUNET_CONTAINER_multipeermap_size (neighbours),
                         GNUNET_NO);
  n->kxinfo = GSC_KX_start (peer);
}
/**
 * Function that assembles our response.
 */
static void
finish_response ()
{
  if (NULL != response)
    MHD_destroy_response (response);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Creating hostlist response with %u bytes\n",
              (unsigned int) builder->size);
  response =
      MHD_create_response_from_buffer (builder->size,
                                       builder->data,
                                       MHD_RESPMEM_MUST_FREE);
  add_cors_headers (response);
  if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6))
  {
    MHD_destroy_response (response);
    response = NULL;
  }
  GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"),
                         builder->size, GNUNET_YES);
  GNUNET_free (builder);
  builder = NULL;
}
Esempio n. 21
0
static void
run (void *cls,
     char *const *args,
     const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  unsigned int i;
  char name[128];

  h = GNUNET_STATISTICS_create ("test-statistics-api-loop", cfg);
  for (i = 0; i < ROUNDS; i++)
  {
    GNUNET_snprintf (name, sizeof (name), "test-%d", i % 32);
    GNUNET_STATISTICS_set (h, name, i, GNUNET_NO);
    GNUNET_snprintf (name, sizeof (name), "test-%d", i % 16);
    GNUNET_STATISTICS_update (h, name, 1, GNUNET_NO);
  }
  i = 0;
  GNUNET_break (NULL !=
                GNUNET_STATISTICS_get (h, NULL, "test-0",
                                       &next,
                                       &check_1, cls));
}
int
client_disconnect (struct Session *s)
{
  int res = GNUNET_OK;
  CURLMcode mret;
  struct Plugin *plugin = s->plugin;
  struct HTTP_Message *msg;
  struct HTTP_Message *t;

  if (GNUNET_YES != exist_session(plugin, s))
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }

  if (s->client_put != NULL)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                     "Client: %p Deleting outbound PUT session to peer `%s'\n",
                     s->client_put, GNUNET_i2s (&s->target));

    mret = curl_multi_remove_handle (plugin->client_mh, s->client_put);
    if (mret != CURLM_OK)
    {
      curl_easy_cleanup (s->client_put);
      res = GNUNET_SYSERR;
      GNUNET_break (0);
    }
    curl_easy_cleanup (s->client_put);
    s->client_put = NULL;
  }


  if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
    s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
  }

  if (s->client_get != NULL)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                     "Client: %p Deleting outbound GET session to peer `%s'\n",
                     s->client_get, GNUNET_i2s (&s->target));

    mret = curl_multi_remove_handle (plugin->client_mh, s->client_get);
    if (mret != CURLM_OK)
    {
      curl_easy_cleanup (s->client_get);
      res = GNUNET_SYSERR;
      GNUNET_break (0);
    }
    curl_easy_cleanup (s->client_get);
    s->client_get = NULL;
  }

  msg = s->msg_head;
  while (msg != NULL)
  {
    t = msg->next;
    if (NULL != msg->transmit_cont)
      msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
    GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
    GNUNET_free (msg);
    msg = t;
  }

  plugin->cur_connections -= 2;

  GNUNET_assert (plugin->outbound_sessions > 0);
  plugin->outbound_sessions --;
  GNUNET_STATISTICS_set (plugin->env->stats,
      "# HTTP outbound sessions",
      plugin->outbound_sessions,
      GNUNET_NO);

  /* Re-schedule since handles have changed */
  if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
    plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
  }

  client_schedule (plugin, GNUNET_YES);

  return res;
}
Esempio n. 23
0
/**
 * Initialize a message to clients with the current network
 * size estimate.
 *
 * @param em message to fill in
 */
static void
setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
{
  double mean;
  double sum;
  double std_dev;
  double variance;
  double val;
  double nsize;

#define WEST 1
  /* Weighted incremental algorithm for stddev according to West (1979) */
#if WEST
  double sumweight;
  double weight;
  double q;
  double r;
  double temp;

  mean = 0.0;
  sum = 0.0;
  sumweight = 0.0;
  variance = 0.0;
  for (unsigned int i = 0; i < estimate_count; i++)
  {
    unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;

    val = htonl (size_estimate_messages[j].matching_bits);
    weight = estimate_count + 1 - i;

    temp = weight + sumweight;
    q = val - mean;
    r = q * weight / temp;
    mean += r;
    sum += sumweight * q * r;
    sumweight = temp;
  }
  if (estimate_count > 0)
    variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
#else
  /* trivial version for debugging */
  double vsq;

  /* non-weighted trivial version */
  sum = 0.0;
  vsq = 0.0;
  variance = 0.0;
  mean = 0.0;

  for (unsigned int i = 0; i < estimate_count; i++)
  {
    unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;

    val = htonl (size_estimate_messages[j].matching_bits);
    sum += val;
    vsq += val * val;
  }
  if (0 != estimate_count)
  {
    mean = sum / estimate_count;
    variance = (vsq - mean * sum) / (estimate_count - 1.0);     // terrible for numerical stability...
  }
#endif
  if (variance >= 0)
    std_dev = sqrt (variance);
  else
    std_dev = variance;         /* must be infinity due to estimate_count == 0 */
  current_std_dev = std_dev;
  current_size_estimate = mean;

  em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage));
  em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
  em->reserved = htonl (0);
  em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
  {
    double se = mean - 0.332747;
    unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
    if (0 == j)
      j = 1; /* Avoid log2(0); can only happen if CORE didn't report
		connection to self yet */
    nsize = log2 (j);
    em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se,
							nsize));
    em->std_deviation = GNUNET_hton_double (std_dev);
    GNUNET_STATISTICS_set (stats,
			   "# nodes in the network (estimate)",
			   (uint64_t) pow (2, GNUNET_MAX (se,
							  nsize)),
			   GNUNET_NO);
  }
}
/**
 * Solves the LP problem
 *
 * @param mlp the MLP Handle
 * @param s_ctx context to return results
 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
 */
static int
mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
{
  int res;
  struct GNUNET_TIME_Relative duration;
  struct GNUNET_TIME_Absolute end;
  struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();

  /* LP presolver?
   * Presolver is required if the problem was modified and an existing
   * valid basis is now invalid */
  if (mlp->presolver_required == GNUNET_YES)
    mlp->control_param_lp.presolve = GLP_ON;
  else
    mlp->control_param_lp.presolve = GLP_OFF;

  /* Solve LP problem to have initial valid solution */
lp_solv:
  res = glp_simplex(mlp->prob, &mlp->control_param_lp);
  if (res == 0)
  {
    /* The LP problem instance has been successfully solved. */
  }
  else if (res == GLP_EITLIM)
  {
    /* simplex iteration limit has been exceeded. */
    // TODO Increase iteration limit?
  }
  else if (res == GLP_ETMLIM)
  {
    /* Time limit has been exceeded.  */
    // TODO Increase time limit?
  }
  else
  {
    /* Problem was ill-defined, retry with presolver */
    if (mlp->presolver_required == GNUNET_NO)
    {
      mlp->presolver_required = GNUNET_YES;
      goto lp_solv;
    }
    else
    {
      /* Problem was ill-defined, no way to handle that */
      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
          "ats-mlp",
          "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
      return GNUNET_SYSERR;
    }
  }

  end = GNUNET_TIME_absolute_get ();
  duration = GNUNET_TIME_absolute_get_difference (start, end);
  mlp->lp_solved++;
  mlp->lp_total_duration =+ duration.rel_value;
  s_ctx->lp_duration = duration;

  GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
  GNUNET_STATISTICS_set (mlp->stats,"# LP execution time (ms)", duration.rel_value, GNUNET_NO);
  GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average (ms)",
                         mlp->lp_total_duration / mlp->lp_solved,  GNUNET_NO);

  /* Analyze problem status  */
  res = glp_get_status (mlp->prob);
  switch (res) {
    /* solution is optimal */
    case GLP_OPT:
    /* solution is feasible */
    case GLP_FEAS:
      break;

    /* Problem was ill-defined, no way to handle that */
    default:
      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
          "ats-mlp",
          "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
      return GNUNET_SYSERR;
      break;
  }

  /* solved sucessfully, no presolver required next time */
  mlp->presolver_required = GNUNET_NO;

  return GNUNET_OK;
}
/**
 * Solves the MLP problem
 *
 * @param mlp the MLP Handle
 * @param s_ctx context to return results
 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
 */
int
mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx)
{
  int res;
  struct GNUNET_TIME_Relative duration;
  struct GNUNET_TIME_Absolute end;
  struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();

  /* solve MLP problem */
  res = glp_intopt(mlp->prob, &mlp->control_param_mlp);

  if (res == 0)
  {
    /* The MLP problem instance has been successfully solved. */
  }
  else if (res == GLP_EITLIM)
  {
    /* simplex iteration limit has been exceeded. */
    // TODO Increase iteration limit?
  }
  else if (res == GLP_ETMLIM)
  {
    /* Time limit has been exceeded.  */
    // TODO Increase time limit?
  }
  else
  {
    /* Problem was ill-defined, no way to handle that */
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
        "ats-mlp",
        "Solving MLP problem failed:  %s\n", mlp_solve_to_string(res));
    return GNUNET_SYSERR;
  }

  end = GNUNET_TIME_absolute_get ();
  duration = GNUNET_TIME_absolute_get_difference (start, end);
  mlp->mlp_solved++;
  mlp->mlp_total_duration =+ duration.rel_value;
  s_ctx->mlp_duration = duration;

  GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
  GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time (ms)", duration.rel_value, GNUNET_NO);
  GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average (ms)",
                         mlp->mlp_total_duration / mlp->mlp_solved,  GNUNET_NO);

  /* Analyze problem status  */
  res = glp_mip_status(mlp->prob);
  switch (res) {
    /* solution is optimal */
    case GLP_OPT:
    /* solution is feasible */
    case GLP_FEAS:
      break;

    /* Problem was ill-defined, no way to handle that */
    default:
      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
          "ats-mlp",
          "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
      return GNUNET_SYSERR;
      break;
  }

  return GNUNET_OK;
}
int
client_connect (struct Session *s)
{
  struct Plugin *plugin = s->plugin;
  int res = GNUNET_OK;
  char *url;
  CURLMcode mret;

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                   "Initiating outbound session peer `%s'\n",
                   GNUNET_i2s (&s->target));
  s->inbound = GNUNET_NO;
  plugin->last_tag++;
  /* create url */
  GNUNET_asprintf (&url, "%s%s;%u",
                   http_plugin_address_to_string (plugin, s->addr, s->addrlen),
                   GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey),
                   plugin->last_tag);
#if 0
  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url);
#endif
  /* create get connection */
  s->client_get = curl_easy_init ();
#if VERBOSE_CURL
  curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log);
  curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get);
#endif
#if BUILD_HTTPS
  curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0);
#endif
  curl_easy_setopt (s->client_get, CURLOPT_URL, url);
  //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
  //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps);
  curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb);
  curl_easy_setopt (s->client_get, CURLOPT_READDATA, s);
  curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive);
  curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s);
  curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS,
                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s);
  curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS,
                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE,
                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
#if CURL_TCP_NODELAY
  curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1);
#endif

  /* create put connection */
  s->client_put = curl_easy_init ();
#if VERBOSE_CURL
  curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L);
  curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log);
  curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put);
#endif
#if BUILD_HTTPS
  curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0);
#endif
  curl_easy_setopt (s->client_put, CURLOPT_URL, url);
  curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L);
  //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
  //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps);
  curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb);
  curl_easy_setopt (s->client_put, CURLOPT_READDATA, s);
  curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive);
  curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s);
  curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS,
                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s);
  curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS,
                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
  curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE,
                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
#if CURL_TCP_NODELAY
  curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1);
#endif

  GNUNET_free (url);

  mret = curl_multi_add_handle (plugin->client_mh, s->client_get);
  if (mret != CURLM_OK)
  {
    curl_easy_cleanup (s->client_get);
    res = GNUNET_SYSERR;
    GNUNET_break (0);
  }

  mret = curl_multi_add_handle (plugin->client_mh, s->client_put);
  if (mret != CURLM_OK)
  {
    curl_multi_remove_handle (plugin->client_mh, s->client_get);
    curl_easy_cleanup (s->client_get);
    curl_easy_cleanup (s->client_put);
    res = GNUNET_SYSERR;
    GNUNET_break (0);
  }

  /* Perform connect */
  plugin->cur_connections += 2;

  plugin->outbound_sessions ++;
  GNUNET_STATISTICS_set (plugin->env->stats,
      "# HTTP outbound sessions",
      plugin->outbound_sessions,
      GNUNET_NO);

  /* Re-schedule since handles have changed */
  if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
  {
    GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
    plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
  }
  plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin);

  return res;
}
Esempio n. 27
0
/**
 * Notify the plan about a peer being no longer available;
 * destroy all entries associated with this peer.
 *
 * @param cp connected peer
 */
void
GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp)
{
  const struct GNUNET_PeerIdentity *id;
  struct PeerPlan *pp;
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestData *prd;
  struct GSF_PendingRequestPlanBijection *bi;

  id = GSF_connected_peer_get_identity2_ (cp);
  pp = GNUNET_CONTAINER_multihashmap_get (plans, &id->hashPubKey);
  if (NULL == pp)
    return;                     /* nothing was ever planned for this peer */
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_remove (plans, &id->hashPubKey,
                                                       pp));
  if (NULL != pp->pth)
  {
    GSF_peer_transmit_cancel_ (pp->pth);
    pp->pth = NULL;
  }
  if (GNUNET_SCHEDULER_NO_TASK != pp->task)
  {
    GNUNET_SCHEDULER_cancel (pp->task);
    pp->task = GNUNET_SCHEDULER_NO_TASK;
  }
  while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap)))
  {
    GNUNET_break (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
                                                        get_rp_key (rp), rp));
    while (NULL != (bi = rp->pe_head))
    {
      GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
      prd = GSF_pending_request_get_data_ (bi->pr);
      GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
      GNUNET_free (bi);
    }
    plan_count--;
    GNUNET_free (rp);
  }
  GNUNET_CONTAINER_heap_destroy (pp->priority_heap);
  while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)))
  {
    GNUNET_break (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
                                                        get_rp_key (rp), rp));
    while (NULL != (bi = rp->pe_head))
    {
      prd = GSF_pending_request_get_data_ (bi->pr);
      GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
      GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
      GNUNET_free (bi);
    }
    plan_count--;
    GNUNET_free (rp);
  }
  GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"),
                         plan_count, GNUNET_NO);
  GNUNET_CONTAINER_heap_destroy (pp->delay_heap);
  GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map);
  GNUNET_free (pp);
}
Esempio n. 28
0
/**
 * 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_delayed (delay,
                                      &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);
}
Esempio n. 29
0
/**
 * 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 =
      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
                                delay.rel_value + 1);
  /* Add 0.01 to avg_delay to avoid division-by-zero later */
  avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value) / 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 / avg_delay)) / M_PI_4;
  /* Note: usage of 'round' and 'atan' requires -lm */

  if (rp->transmission_counter != 0)
    delay.rel_value += TTL_DECREMENT;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Considering (re)transmission number %u in %llu ms\n",
              (unsigned int) rp->transmission_counter,
              (unsigned long long) delay.rel_value);
  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 (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value
      == 0)
    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);
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map,
                                                               get_rp_key (rp),
                                                               rp));
  if (GNUNET_SCHEDULER_NO_TASK != pp->task)
    GNUNET_SCHEDULER_cancel (pp->task);
  pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp);
#undef N
}
/**
 * Try to perform a transmission on the given session. Will solicit
 * additional messages if the 'sme' queue is not full enough or has
 * only low-priority messages.
 *
 * @param session session to transmit messages from
 */
static void
try_transmission (struct Session *session)
{
  struct SessionMessageEntry *pos;
  size_t msize;
  struct GNUNET_TIME_Absolute now;
  struct GNUNET_TIME_Absolute min_deadline;
  enum GNUNET_CORE_Priority maxp;
  enum GNUNET_CORE_Priority maxpc;
  struct GSC_ClientActiveRequest *car;
  int excess;

  if (GNUNET_YES != session->ready_to_transmit)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Already ready to transmit, not evaluating queue\n");
    return;
  }
  msize = 0;
  min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
  /* if the peer has excess bandwidth, background traffic is allowed,
     otherwise not */
  if (MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE <=
      GSC_NEIGHBOURS_get_queue_size (&session->peer))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Transmission queue already very long, waiting...\n");
    return; /* queue already too long */
  }
  excess = GSC_NEIGHBOURS_check_excess_bandwidth (&session->peer);
  if (GNUNET_YES == excess)
    maxp = GNUNET_CORE_PRIO_BACKGROUND;
  else
    maxp = GNUNET_CORE_PRIO_BEST_EFFORT;
  /* determine highest priority of 'ready' messages we already solicited from clients */
  pos = session->sme_head;
  while ((NULL != pos) &&
         (msize + pos->size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE))
  {
    GNUNET_assert (pos->size < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE);
    msize += pos->size;
    maxp = GNUNET_MAX (maxp, pos->priority);
    min_deadline = GNUNET_TIME_absolute_min (min_deadline,
                                             pos->deadline);
    pos = pos->next;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Calculating transmission set with %u priority (%s) and %s earliest deadline\n",
              maxp,
              (GNUNET_YES == excess) ? "excess bandwidth" : "limited bandwidth",
              GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                      GNUNET_YES));

  if (maxp < GNUNET_CORE_PRIO_CRITICAL_CONTROL)
  {
    /* if highest already solicited priority from clients is not critical,
       check if there are higher-priority messages to be solicited from clients */
    if (GNUNET_YES == excess)
      maxpc = GNUNET_CORE_PRIO_BACKGROUND;
    else
      maxpc = GNUNET_CORE_PRIO_BEST_EFFORT;
    for (car = session->active_client_request_head; NULL != car; car = car->next)
    {
      if (GNUNET_YES == car->was_solicited)
        continue;
      maxpc = GNUNET_MAX (maxpc,
                          car->priority);
    }
    if (maxpc > maxp)
    {
      /* we have messages waiting for solicitation that have a higher
         priority than those that we already accepted; solicit the
         high-priority messages first */
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Soliciting messages based on priority (%u > %u)\n",
                  maxpc,
                  maxp);
      solicit_messages (session, 0);
      return;
    }
  }
  else
  {
    /* never solicit more, we have critical messages to process */
    excess = GNUNET_NO;
    maxpc = GNUNET_CORE_PRIO_BACKGROUND;
  }
  now = GNUNET_TIME_absolute_get ();
  if ( ( (GNUNET_YES == excess) ||
         (maxpc >= GNUNET_CORE_PRIO_BEST_EFFORT) ) &&
       ( (0 == msize) ||
         ( (msize < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / 2) &&
           (min_deadline.abs_value_us > now.abs_value_us))) )
  {
    /* not enough ready yet (tiny message & cork possible), or no messages at all,
       and either excess bandwidth or best-effort or higher message waiting at
       client; in this case, we try to solicit more */
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Soliciting messages (excess %d, maxpc %d, message size %u, deadline %s)\n",
                excess,
                maxpc,
                msize,
                GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                        GNUNET_YES));
    solicit_messages (session,
                      msize);
    if (msize > 0)
    {
      /* if there is data to send, just not yet, make sure we do transmit
       * it once the deadline is reached */
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Corking until %s\n",
                  GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                                          GNUNET_YES));
      if (NULL != session->cork_task)
        GNUNET_SCHEDULER_cancel (session->cork_task);
      session->cork_task =
          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (min_deadline),
                                        &pop_cork_task,
                                        session);
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Queue empty, waiting for solicitations\n");
    }
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Building combined plaintext buffer to transmit message!\n");
  /* create plaintext buffer of all messages (that fit), encrypt and
     transmit */
  {
    static unsigned long long total_bytes;
    static unsigned int total_msgs;
    char pbuf[msize];           /* plaintext */
    size_t used;

    used = 0;
    while ( (NULL != (pos = session->sme_head)) &&
            (used + pos->size <= msize) )
    {
      memcpy (&pbuf[used], &pos[1], pos->size);
      used += pos->size;
      GNUNET_CONTAINER_DLL_remove (session->sme_head,
                                   session->sme_tail,
                                   pos);
      GNUNET_free (pos);
    }
    /* compute average payload size */
    total_bytes += used;
    total_msgs++;
    if (0 == total_msgs)
    {
      /* 2^32 messages, wrap around... */
      total_msgs = 1;
      total_bytes = used;
    }
    GNUNET_STATISTICS_set (GSC_stats,
                           "# avg payload per encrypted message",
                           total_bytes / total_msgs,
                           GNUNET_NO);
    /* now actually transmit... */
    session->ready_to_transmit = GNUNET_NO;
    GSC_KX_encrypt_and_transmit (session->kxinfo,
                                 pbuf,
                                 used);
  }
}