trying to fix #3576
[oweals/gnunet.git] / src / fs / gnunet-service-fs_cp.c
index f5b5213bc16ac899c7d19e1a490649202c4c2696..bca07db328459d798ccb46dc46ca10995ef7141f 100644 (file)
  * @author Christian Grothoff
  */
 #include "platform.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_load_lib.h"
 #include "gnunet-service-fs.h"
 #include "gnunet-service-fs_cp.h"
 #include "gnunet-service-fs_pe.h"
 #include "gnunet-service-fs_pr.h"
 #include "gnunet-service-fs_push.h"
+#include "gnunet_peerstore_service.h"
 
 
 /**
@@ -97,7 +99,7 @@ struct GSF_PeerTransmitHandle
   struct GSF_ConnectedPeer *cp;
 
   /**
-   * Closure for 'gmc'.
+   * Closure for @e gmc.
    */
   void *gmc_cls;
 
@@ -107,7 +109,7 @@ struct GSF_PeerTransmitHandle
   size_t size;
 
   /**
-   * GNUNET_YES if this is a query, GNUNET_NO for content.
+   * #GNUNET_YES if this is a query, #GNUNET_NO for content.
    */
   int is_query;
 
@@ -267,7 +269,7 @@ struct GSF_ConnectedPeer
 
   /**
    * Set to 1 if we're currently in the process of calling
-   * 'GNUNET_CORE_notify_transmit_ready' (so while cth is
+   * #GNUNET_CORE_notify_transmit_ready() (so while @e cth is
    * NULL, we should not call notify_transmit_ready for this
    * handle right now).
    */
@@ -301,37 +303,33 @@ struct GSF_ConnectedPeer
    */
   int did_reserve;
 
+  /**
+   * Function called when the creation of this record is complete.
+   */
+  GSF_ConnectedPeerCreationCallback creation_cb;
+
+  /**
+   * Closure for @e creation_cb
+   */
+  void *creation_cb_cls;
+
+  /**
+   * Handle to the PEERSTORE iterate request for peer respect value
+   */
+  struct GNUNET_PEERSTORE_IterateContext *respect_iterate_req;
+
 };
 
 
 /**
  * Map from peer identities to 'struct GSF_ConnectPeer' entries.
  */
-static struct GNUNET_CONTAINER_MultiHashMap *cp_map;
+static struct GNUNET_CONTAINER_MultiPeerMap *cp_map;
 
 /**
- * Where do we store respect information?
+ * Handle to peerstore service.
  */
-static char *respectDirectory;
-
-
-/**
- * Get the filename under which we would store respect
- * for the given peer.
- *
- * @param id peer to get the filename for
- * @return filename of the form DIRECTORY/PEERID
- */
-static char *
-get_respect_filename (const struct GNUNET_PeerIdentity *id)
-{
-  struct GNUNET_CRYPTO_HashAsciiEncoded fil;
-  char *fn;
-
-  GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil);
-  GNUNET_asprintf (&fn, "%s%s%s", respectDirectory, DIR_SEPARATOR_STR, &fil);
-  return fn;
-}
+static struct GNUNET_PEERSTORE_Handle *peerstore;
 
 
 /**
@@ -436,7 +434,8 @@ schedule_transmission (struct GSF_PeerTransmitHandle *pth)
   GNUNET_assert (NULL == cp->cth);
   cp->cth_in_progress++;
   cp->cth =
-    GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority,
+    GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES,
+                                       GNUNET_CORE_PRIO_BACKGROUND,
                                       GNUNET_TIME_absolute_get_remaining
                                       (pth->timeout), &target, pth->size,
                                       &peer_transmit_ready_cb, cp);
@@ -539,7 +538,7 @@ ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Reserved %d bytes / need to wait %s for reservation\n",
-              (int) amount, 
+              (int) amount,
              GNUNET_STRINGS_relative_time_to_string (res_delay, GNUNET_YES));
   cp->rc = NULL;
   if (0 == amount)
@@ -555,7 +554,8 @@ ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
     /* reservation success, try transmission now! */
     cp->cth_in_progress++;
     cp->cth =
-        GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority,
+        GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES,
+                                           GNUNET_CORE_PRIO_BACKGROUND,
                                            GNUNET_TIME_absolute_get_remaining
                                            (pth->timeout), peer, pth->size,
                                            &peer_transmit_ready_cb, cp);
@@ -564,20 +564,42 @@ ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
   }
 }
 
+/**
+ * Function called by PEERSTORE with peer respect record
+ *
+ * @param cls handle to connected peer entry
+ * @param record peerstore record information
+ * @param emsg error message, or NULL if no errors
+ * @return #GNUNET_NO to stop iterating since we only expect 0 or 1 records
+ */
+static int
+peer_respect_cb (void *cls, struct GNUNET_PEERSTORE_Record *record, char *emsg)
+{
+  struct GSF_ConnectedPeer *cp = cls;
+
+  cp->respect_iterate_req = NULL;
+  if ((NULL != record) && (sizeof (cp->disk_respect) == record->value_size))
+    cp->disk_respect = cp->ppd.respect = *((uint32_t *)record->value);
+  GSF_push_start_ (cp);
+  if (NULL != cp->creation_cb)
+    cp->creation_cb (cp->creation_cb_cls, cp);
+  return GNUNET_NO;
+}
 
 /**
  * A peer connected to us.  Setup the connected peer
  * records.
  *
  * @param peer identity of peer that connected
- * @return handle to connected peer entry
+ * @param creation_cb callback function when the record is created.
+ * @param creation_cb_cls closure for @creation_cb
  */
-struct GSF_ConnectedPeer *
-GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer)
+void
+GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer,
+                           GSF_ConnectedPeerCreationCallback creation_cb,
+                           void *creation_cb_cls)
 {
   struct GSF_ConnectedPeer *cp;
-  char *fn;
-  uint32_t respect;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %s\n",
               GNUNET_i2s (peer));
@@ -587,22 +609,21 @@ GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer)
   cp->rc =
       GNUNET_ATS_reserve_bandwidth (GSF_ats, peer, DBLOCK_SIZE,
                                     &ats_reserve_callback, cp);
-  fn = get_respect_filename (peer);
-  if ((GNUNET_YES == GNUNET_DISK_file_test (fn)) &&
-      (sizeof (respect) == GNUNET_DISK_fn_read (fn, &respect, sizeof (respect))))
-    cp->disk_respect = cp->ppd.respect = ntohl (respect);
-  GNUNET_free (fn);
   cp->request_map = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
   GNUNET_break (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap_put (cp_map, 
-                                                  &GSF_connected_peer_get_identity2_ (cp)->hashPubKey,
+                GNUNET_CONTAINER_multipeermap_put (cp_map,
+               GSF_connected_peer_get_identity2_ (cp),
                                                    cp,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"),
-                         GNUNET_CONTAINER_multihashmap_size (cp_map),
+                         GNUNET_CONTAINER_multipeermap_size (cp_map),
                          GNUNET_NO);
-  GSF_push_start_ (cp);
-  return cp;
+  cp->creation_cb = creation_cb;
+  cp->creation_cb_cls = creation_cb_cls;
+  cp->respect_iterate_req =
+      GNUNET_PEERSTORE_iterate (peerstore, "fs", peer, "respect",
+                                GNUNET_TIME_UNIT_FOREVER_REL, &peer_respect_cb,
+                                cp);
 }
 
 
@@ -643,7 +664,7 @@ GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer)
 {
   if (NULL == cp_map)
     return NULL;
-  return GNUNET_CONTAINER_multihashmap_get (cp_map, &peer->hashPubKey);
+  return GNUNET_CONTAINER_multipeermap_get (cp_map, peer);
 }
 
 
@@ -679,7 +700,7 @@ GSF_handle_p2p_migration_stop_ (void *cls,
   bt = GNUNET_TIME_relative_ntoh (msm->duration);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               _("Migration of content to peer `%s' blocked for %s\n"),
-              GNUNET_i2s (other), 
+              GNUNET_i2s (other),
              GNUNET_STRINGS_relative_time_to_string (bt, GNUNET_YES));
   cp->ppd.migration_blocked_until = GNUNET_TIME_relative_to_absolute (bt);
   if (GNUNET_SCHEDULER_NO_TASK == cp->mig_revive_task)
@@ -1113,7 +1134,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
   uint16_t msize;
   const struct GetMessage *gm;
   unsigned int bits;
-  const struct GNUNET_HashCode *opt;
+  const struct GNUNET_PeerIdentity *opt;
   uint32_t bm;
   size_t bfsize;
   uint32_t ttl_decrement;
@@ -1143,13 +1164,13 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
       bits++;
     bm >>= 1;
   }
-  if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_HashCode))
+  if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_PeerIdentity))
   {
     GNUNET_break_op (0);
     return NULL;
   }
-  opt = (const struct GNUNET_HashCode *) &gm[1];
-  bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_HashCode);
+  opt = (const struct GNUNET_PeerIdentity *) &gm[1];
+  bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_PeerIdentity);
   /* bfsize must be power of 2, check! */
   if (0 != ((bfsize - 1) & bfsize))
   {
@@ -1170,7 +1191,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
     return NULL;
   }
   if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO))
-    cp = GSF_peer_get_ ((const struct GNUNET_PeerIdentity *) &opt[bits++]);
+    cp = GSF_peer_get_ (&opt[bits++]);
   else
     cp = cps;
   if (NULL == cp)
@@ -1178,8 +1199,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
     if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO))
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Failed to find RETURN-TO peer `%4s' in connection set. Dropping query.\n",
-                  GNUNET_i2s ((const struct GNUNET_PeerIdentity *)
-                              &opt[bits - 1]));
+                  GNUNET_i2s (&opt[bits - 1]));
 
     else
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1206,12 +1226,13 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received request for `%s' of type %u from peer `%4s' with flags %u\n",
-              GNUNET_h2s (&gm->query), (unsigned int) type, GNUNET_i2s (other),
+              GNUNET_h2s (&gm->query),
+              (unsigned int) type,
+              GNUNET_i2s (other),
               (unsigned int) bm);
   target =
       (0 !=
-       (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? ((const struct GNUNET_PeerIdentity
-                                               *) &opt[bits++]) : NULL;
+       (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? (&opt[bits++]) : NULL;
   options = GSF_PRO_DEFAULTS;
   spid = 0;
   if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 + priority))
@@ -1251,7 +1272,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
   {
     pr = peerreq->pr;
     prd = GSF_pending_request_get_data_ (pr);
-    if (prd->type == type) 
+    if (prd->type == type)
     {
       if (prd->ttl.abs_value_us >= GNUNET_TIME_absolute_get ().abs_value_us + ttl * 1000LL)
       {
@@ -1275,7 +1296,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
 
   peerreq = GNUNET_new (struct PeerRequest);
   peerreq->cp = cp;
-  pr = GSF_pending_request_create_ (options, type, &gm->query, 
+  pr = GSF_pending_request_create_ (options, type, &gm->query,
                                     target,
                                     (bfsize >
                                      0) ? (const char *) &opt[bits] : NULL,
@@ -1490,11 +1511,17 @@ GSF_peer_disconnect_handler_ (void *cls, const struct GNUNET_PeerIdentity *peer)
     return;                     /* must have been disconnect from core with
                                  * 'peer' == my_id, ignore */
   GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (cp_map,
-                                                       &peer->hashPubKey, cp));
+                 GNUNET_CONTAINER_multipeermap_remove (cp_map,
+                                                       peer,
+                                                      cp));
   GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"),
-                         GNUNET_CONTAINER_multihashmap_size (cp_map),
+                         GNUNET_CONTAINER_multipeermap_size (cp_map),
                          GNUNET_NO);
+  if (NULL != cp->respect_iterate_req)
+  {
+    GNUNET_PEERSTORE_iterate_cancel (cp->respect_iterate_req);
+    cp->respect_iterate_req = NULL;
+  }
   if (NULL != cp->migration_pth)
   {
     GSF_peer_transmit_cancel_ (cp->migration_pth);
@@ -1579,7 +1606,7 @@ struct IterationContext
  * @return #GNUNET_YES to continue iteration
  */
 static int
-call_iterator (void *cls, const struct GNUNET_HashCode * key, void *value)
+call_iterator (void *cls, const struct GNUNET_PeerIdentity * key, void *value)
 {
   struct IterationContext *ic = cls;
   struct GSF_ConnectedPeer *cp = value;
@@ -1602,7 +1629,7 @@ GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls)
 
   ic.it = it;
   ic.it_cls = it_cls;
-  GNUNET_CONTAINER_multihashmap_iterate (cp_map, &call_iterator, &ic);
+  GNUNET_CONTAINER_multipeermap_iterate (cp_map, &call_iterator, &ic);
 }
 
 
@@ -1709,36 +1736,19 @@ GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp,
  * @return GNUNET_OK to continue iteration
  */
 static int
-flush_respect (void *cls, const struct GNUNET_HashCode * key, void *value)
+flush_respect (void *cls, const struct GNUNET_PeerIdentity * key, void *value)
 {
   struct GSF_ConnectedPeer *cp = value;
-  char *fn;
-  uint32_t respect;
   struct GNUNET_PeerIdentity pid;
 
   if (cp->ppd.respect == cp->disk_respect)
     return GNUNET_OK;           /* unchanged */
   GNUNET_assert (0 != cp->ppd.pid);
   GNUNET_PEER_resolve (cp->ppd.pid, &pid);
-  fn = get_respect_filename (&pid);
-  if (cp->ppd.respect == 0)
-  {
-    if ((0 != UNLINK (fn)) && (errno != ENOENT))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
-                                GNUNET_ERROR_TYPE_BULK, "unlink", fn);
-  }
-  else
-  {
-    respect = htonl (cp->ppd.respect);
-    if (sizeof (uint32_t) ==
-        GNUNET_DISK_fn_write (fn, &respect, sizeof (uint32_t),
-                              GNUNET_DISK_PERM_USER_READ |
-                              GNUNET_DISK_PERM_USER_WRITE |
-                              GNUNET_DISK_PERM_GROUP_READ |
-                              GNUNET_DISK_PERM_OTHER_READ))
-      cp->disk_respect = cp->ppd.respect;
-  }
-  GNUNET_free (fn);
+  GNUNET_PEERSTORE_store (peerstore, "fs", &pid, "respect", &cp->ppd.respect,
+                          sizeof (cp->ppd.respect),
+                          GNUNET_TIME_UNIT_FOREVER_ABS,
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL);
   return GNUNET_OK;
 }
 
@@ -1772,7 +1782,7 @@ cron_flush_respect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   if (NULL == cp_map)
     return;
-  GNUNET_CONTAINER_multihashmap_iterate (cp_map, &flush_respect, NULL);
+  GNUNET_CONTAINER_multipeermap_iterate (cp_map, &flush_respect, NULL);
   if (NULL == tc)
     return;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
@@ -1789,12 +1799,8 @@ cron_flush_respect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 void
 GSF_connected_peer_init_ ()
 {
-  cp_map = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONFIGURATION_get_value_filename (GSF_cfg, "fs",
-                                                          "RESPECT",
-                                                          &respectDirectory));
-  GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_create (respectDirectory));
+  cp_map = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
+  peerstore = GNUNET_PEERSTORE_connect (GSF_cfg);
   GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_HIGH,
                                       &cron_flush_respect, NULL);
 }
@@ -1809,9 +1815,11 @@ GSF_connected_peer_init_ ()
  * @return #GNUNET_YES (we should continue to iterate)
  */
 static int
-clean_peer (void *cls, const struct GNUNET_HashCode * key, void *value)
+clean_peer (void *cls,
+           const struct GNUNET_PeerIdentity *key,
+           void *value)
 {
-  GSF_peer_disconnect_handler_ (NULL, (const struct GNUNET_PeerIdentity *) key);
+  GSF_peer_disconnect_handler_ (NULL, key);
   return GNUNET_YES;
 }
 
@@ -1823,11 +1831,10 @@ void
 GSF_connected_peer_done_ ()
 {
   cron_flush_respect (NULL, NULL);
-  GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_peer, NULL);
-  GNUNET_CONTAINER_multihashmap_destroy (cp_map);
+  GNUNET_CONTAINER_multipeermap_iterate (cp_map, &clean_peer, NULL);
+  GNUNET_CONTAINER_multipeermap_destroy (cp_map);
   cp_map = NULL;
-  GNUNET_free (respectDirectory);
-  respectDirectory = NULL;
+  GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
 }
 
 
@@ -1840,7 +1847,9 @@ GSF_connected_peer_done_ ()
  * @return #GNUNET_YES (we should continue to iterate)
  */
 static int
-clean_local_client (void *cls, const struct GNUNET_HashCode * key, void *value)
+clean_local_client (void *cls,
+                   const struct GNUNET_PeerIdentity *key,
+                   void *value)
 {
   const struct GSF_LocalClient *lc = cls;
   struct GSF_ConnectedPeer *cp = value;
@@ -1864,7 +1873,7 @@ GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc)
 {
   if (NULL == cp_map)
     return;                     /* already cleaned up */
-  GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_local_client,
+  GNUNET_CONTAINER_multipeermap_iterate (cp_map, &clean_local_client,
                                          (void *) lc);
 }