gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r12490 - in gnunet: . src/fs


From: gnunet
Subject: [GNUnet-SVN] r12490 - in gnunet: . src/fs
Date: Sat, 7 Aug 2010 18:54:29 +0200

Author: grothoff
Date: 2010-08-07 18:54:29 +0200 (Sat, 07 Aug 2010)
New Revision: 12490

Modified:
   gnunet/TODO
   gnunet/src/fs/fs.h
   gnunet/src/fs/fs_namespace.c
   gnunet/src/fs/fs_publish.c
Log:
implement update api

Modified: gnunet/TODO
===================================================================
--- gnunet/TODO 2010-08-07 09:13:22 UTC (rev 12489)
+++ gnunet/TODO 2010-08-07 16:54:29 UTC (rev 12490)
@@ -17,8 +17,6 @@
   - derived key generation [Nils]
 * PWNAT: [Nate/MW/Nils]
   - W32 port
-* FS: [CG]
-  - implement 'GNUNET_FS_namespace_list_updateable', reconsider API!
 * GNUNET-GTK: [CG]
   - namespaces:
     + namespace publishing
@@ -34,8 +32,6 @@
     + handle 'lost parent' case for recursive downloads (need to move 
children!)
     + clean up TreeStores in main_window_file_publish on dialog close
     + clean up ListStores in main_window_adv_pseudonym 
-* DATASTORE:
-  - modify testcases to not fail if database is not configured (i.e. 
'mysqlcheck' DB does not exist)
 
 0.9.0pre3:
 * Determine RC bugs and fix those!

Modified: gnunet/src/fs/fs.h
===================================================================
--- gnunet/src/fs/fs.h  2010-08-07 09:13:22 UTC (rev 12489)
+++ gnunet/src/fs/fs.h  2010-08-07 16:54:29 UTC (rev 12490)
@@ -1839,15 +1839,72 @@
   int tried_full_data;
 };
 
+
+/**
+ * Information about an (updateable) node in the
+ * namespace.
+ */
+struct NamespaceUpdateNode
+{
+  /**
+   * Identifier for this node.
+   */
+  char *id;
+
+  /**
+   * Identifier of children of this node.
+   */
+  char *update;
+
+  /**
+   * Metadata for this entry.
+   */
+  struct GNUNET_CONTAINER_MetaData *md;
+
+  /**
+   * URI of this entry in the namespace.
+   */
+  struct GNUNET_FS_Uri *uri;
+
+  /**
+   * Namespace update generation ID.  Used to ensure
+   * freshness of the scc_id.
+   */
+  unsigned int nug;
+  
+  /**
+   * SCC this entry belongs to (if nug is current).
+   */
+  unsigned int scc_id;
+
+};
+
+
 struct GNUNET_FS_Namespace
 {
 
   /**
+   * Handle to the FS service context.
+   */
+  struct GNUNET_FS_Handle *h;
+  
+  /**
+   * Array with information about nodes in the namespace.
+   */
+  struct NamespaceUpdateNode **update_nodes;
+
+  /**
    * Private key for the namespace.
    */
   struct GNUNET_CRYPTO_RsaPrivateKey *key;
 
   /**
+   * Hash map mapping identifiers of update nodes
+   * to the update nodes (initialized on-demand).
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *update_map;
+
+  /**
    * Name of the file with the private key.
    */
   char *filename;
@@ -1858,9 +1915,19 @@
   char *name;
 
   /**
+   * Size of the update nodes array.
+   */
+  unsigned int update_node_count;
+
+  /**
    * Reference counter.
    */
   unsigned int rc;
+
+  /**
+   * Generator for unique nug numbers.
+   */
+  unsigned int nug_gen;
 };
 
 

Modified: gnunet/src/fs/fs_namespace.c
===================================================================
--- gnunet/src/fs/fs_namespace.c        2010-08-07 09:13:22 UTC (rev 12489)
+++ gnunet/src/fs/fs_namespace.c        2010-08-07 16:54:29 UTC (rev 12490)
@@ -59,6 +59,184 @@
 
 
 /**
+ * Return the name of the directory in which we store
+ * the update information graph for the given local namespace.
+ *
+ * @param ns namespace handle 
+ * @return NULL on error, otherwise the name of the directory
+ */
+static char *
+get_update_information_directory (struct GNUNET_FS_Namespace *ns)
+{
+  char *dn;
+  char *ret;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg,
+                                              "FS",
+                                              "UPDATE_DIR",
+                                              &dn))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Configuration fails to specify `%s' in section `%s'\n"),
+                 "UPDATE_DIR",
+                 "fs");
+      return NULL;
+    }
+  GNUNET_asprintf (&ret,
+                  "%s%s%s",
+                  dn,
+                  DIR_SEPARATOR_STR,
+                  ns->name);
+  GNUNET_free (dn);
+  return ret;
+}
+
+
+/**
+ * Write the namespace update node graph to a file.
+ * 
+ * @param ns namespace to dump
+ */
+static void
+write_update_information_graph (struct GNUNET_FS_Namespace *ns)
+{
+  char * fn;
+  struct GNUNET_BIO_WriteHandle *wh;
+  unsigned int i;
+  struct NamespaceUpdateNode *n;
+  char *uris;
+
+  fn = get_update_information_directory (ns);
+  wh = GNUNET_BIO_write_open (fn);
+  if (wh == NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Failed to open `%s' for writing: %s\n"),
+                 STRERROR (errno));
+      GNUNET_free (fn);
+      return;
+    }
+  if (GNUNET_OK != 
+      GNUNET_BIO_write_int32 (wh, ns->update_node_count))
+    goto END;
+  for (i=0;i<ns->update_node_count;i++)
+    {
+      n = ns->update_nodes[i];
+      uris = GNUNET_FS_uri_to_string (n->uri);
+      if ( (GNUNET_OK !=
+           GNUNET_BIO_write_string (wh, n->id)) ||
+          (GNUNET_OK != 
+           GNUNET_BIO_write_meta_data (wh, n->md)) ||
+          (GNUNET_OK !=
+           GNUNET_BIO_write_string (wh, n->update)) ||
+          (GNUNET_OK !=
+           GNUNET_BIO_write_string (wh, uris)) )
+       {
+         GNUNET_free (uris);
+         break;
+       }
+      GNUNET_free (uris);
+    }
+ END:
+  if (GNUNET_OK != GNUNET_BIO_write_close (wh))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               _("Failed to write `%s': %s\n"),
+               STRERROR (errno));
+  GNUNET_free (fn);
+}
+
+
+/**
+ * Read the namespace update node graph from a file.
+ * 
+ * @param ns namespace to read
+ */
+static void
+read_update_information_graph (struct GNUNET_FS_Namespace *ns)
+{
+  char * fn;
+  struct GNUNET_BIO_ReadHandle *rh;
+  unsigned int i;
+  struct NamespaceUpdateNode *n;
+  char *uris;
+  uint32_t count;
+  char *emsg;
+  
+  fn = get_update_information_directory (ns);
+  rh = GNUNET_BIO_read_open (fn);
+  if (rh == NULL)
+    {
+      GNUNET_free (fn);
+      return;
+    }
+  if (GNUNET_OK != 
+      GNUNET_BIO_read_int32 (rh, &count))
+    {
+      GNUNET_break (0);
+      goto END;
+    }
+  if (count > 1024 * 1024)
+    {
+      GNUNET_break (0);
+      goto END;
+    }
+  if (count == 0)
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
+      GNUNET_free (fn);
+      return;
+    }
+  ns->update_nodes = GNUNET_malloc (count * sizeof (struct 
NamespaceUpdateNode*));
+  
+  for (i=0;i<count;i++)
+    {
+      n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
+      if ( (GNUNET_OK !=
+           GNUNET_BIO_read_string (rh,  "identifier", &n->id, 1024)) ||
+          (GNUNET_OK != 
+           GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) ||
+          (GNUNET_OK !=
+           GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) ||
+          (GNUNET_OK !=
+           GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)) )
+       {
+         GNUNET_break (0);
+         GNUNET_free_non_null (n->id);
+         GNUNET_free_non_null (n->update);
+         if (n->md != NULL)
+           GNUNET_CONTAINER_meta_data_destroy (n->md);
+         GNUNET_free (n);
+         break;
+       }
+      n->uri = GNUNET_FS_uri_parse (uris, &emsg);
+      GNUNET_free (uris);
+      if (n->uri == NULL)
+       {
+         GNUNET_break (0);
+         GNUNET_free (emsg);
+         GNUNET_free (n->id);
+         GNUNET_free (n->update);
+         GNUNET_CONTAINER_meta_data_destroy (n->md);
+         GNUNET_free (n);
+         break;
+       }
+      ns->update_nodes[i] = n;
+    }
+  ns->update_node_count = i;
+ END:
+  if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Failed to write `%s': %s\n"),
+                 emsg);
+      GNUNET_free (emsg);
+    }
+  GNUNET_free (fn);
+}
+
+
+/**
  * Context for advertising a namespace.
  */
 struct AdvertisementContext
@@ -363,6 +541,7 @@
                   name);
   GNUNET_free (dn);
   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
+  ret->h = h;
   ret->rc = 1;
   ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
   if (ret->key == NULL)
@@ -395,6 +574,9 @@
 GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace,
                            int freeze)
 {
+  unsigned int i;
+  struct NamespaceUpdateNode *nsn;
+
   namespace->rc--;
   if (freeze)
     {
@@ -408,6 +590,20 @@
       GNUNET_CRYPTO_rsa_key_free (namespace->key);
       GNUNET_free (namespace->filename);
       GNUNET_free (namespace->name);
+      for (i=0;i<namespace->update_node_count;i++)
+       {
+         nsn = namespace->update_nodes[i];
+         GNUNET_CONTAINER_meta_data_destroy (nsn->md);
+         GNUNET_FS_uri_destroy (nsn->uri);
+         GNUNET_free (nsn->id);
+         GNUNET_free (nsn->update);
+         GNUNET_free (nsn);
+       }
+      GNUNET_array_grow (namespace->update_nodes,
+                        namespace->update_node_count,
+                        0);
+      if (namespace->update_map != NULL)
+       GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map);
       GNUNET_free (namespace);
     }
   return GNUNET_OK;
@@ -507,23 +703,551 @@
 
 
 
+
 /**
- * List all of the identifiers in the namespace for 
- * which we could produce an update.
+ * Context for the SKS publication.
+ */
+struct PublishSksContext
+{
+
+  /**
+   * URI of the new entry in the namespace.
+   */
+  struct GNUNET_FS_Uri *uri;
+
+  /**
+   * Namespace update node to add to namespace on success (or to be
+   * deleted if publishing failed).
+   */
+  struct NamespaceUpdateNode *nsn;
+
+  /**
+   * Namespace we're publishing to.
+   */
+  struct GNUNET_FS_Namespace *namespace;
+
+  /**
+   * Handle to the datastore.
+   */
+  struct GNUNET_DATASTORE_Handle *dsh;
+
+  /**
+   * Function to call once we're done.
+   */
+  GNUNET_FS_PublishContinuation cont;
+
+  /**
+   * Closure for cont.
+   */ 
+  void *cont_cls;
+
+};
+
+
+/**
+ * Function called by the datastore API with
+ * the result from the PUT (SBlock) request.
  *
+ * @param cls closure of type "struct PublishSksContext*"
+ * @param success GNUNET_OK on success
+ * @param msg error message (or NULL)
+ */
+static void
+sb_put_cont (void *cls,
+            int success,
+            const char *msg)
+{
+  struct PublishSksContext *psc = cls;
+  GNUNET_HashCode hc;
+
+  if (NULL != psc->dsh)
+    {
+      GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
+      psc->dsh = NULL;
+    }
+  if (GNUNET_OK != success)
+    {
+      psc->cont (psc->cont_cls,
+                NULL,
+                msg);
+    }
+  else
+    {
+      if (psc->nsn != NULL)
+       {
+         /* FIXME: this can be done much more
+            efficiently by simply appending to the
+            file and overwriting the 4-byte header */
+         if (psc->namespace->update_nodes == NULL)
+           read_update_information_graph (psc->namespace);
+         GNUNET_array_append (psc->namespace->update_nodes,
+                              psc->namespace->update_node_count,
+                              psc->nsn);
+         if (psc->namespace->update_map != NULL)
+           {
+             GNUNET_CRYPTO_hash (psc->nsn->id,
+                                 strlen (psc->nsn->id),
+                                 &hc);
+             GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map,
+                                                &hc,
+                                                psc->nsn,
+                                                
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+           }
+         psc->nsn = NULL;
+         write_update_information_graph (psc->namespace);
+       }
+      psc->cont (psc->cont_cls,
+                psc->uri,
+                NULL);
+    }
+  GNUNET_FS_namespace_delete (psc->namespace,
+                             GNUNET_NO);
+  GNUNET_FS_uri_destroy (psc->uri);
+  if (psc->nsn != NULL)
+    {
+      GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
+      GNUNET_FS_uri_destroy (psc->nsn->uri);
+      GNUNET_free (psc->nsn->id);
+      GNUNET_free (psc->nsn->update);
+      GNUNET_free (psc->nsn);
+    }
+  GNUNET_free (psc);
+}
+
+
+/**
+ * Publish an SBlock on GNUnet.
+ *
+ * @param h handle to the file sharing subsystem
+ * @param namespace namespace to publish in
+ * @param identifier identifier to use
+ * @param update update identifier to use
+ * @param meta metadata to use
+ * @param uri URI to refer to in the SBlock
+ * @param expirationTime when the SBlock expires
+ * @param anonymity anonymity level for the SBlock
+ * @param priority priority for the SBlock
+ * @param options publication options
+ * @param cont continuation
+ * @param cont_cls closure for cont
+ */
+void
+GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
+                      struct GNUNET_FS_Namespace *namespace,
+                      const char *identifier,
+                      const char *update,
+                      const struct GNUNET_CONTAINER_MetaData *meta,
+                      const struct GNUNET_FS_Uri *uri,
+                      struct GNUNET_TIME_Absolute expirationTime,
+                      uint32_t anonymity,
+                      uint32_t priority,
+                      enum GNUNET_FS_PublishOptions options,
+                      GNUNET_FS_PublishContinuation cont,
+                      void *cont_cls)
+{
+  struct PublishSksContext *psc;
+  struct GNUNET_CRYPTO_AesSessionKey sk;
+  struct GNUNET_CRYPTO_AesInitializationVector iv;
+  struct GNUNET_FS_Uri *sks_uri;
+  char *uris;
+  size_t size;
+  size_t slen;
+  size_t nidlen;
+  size_t idlen;
+  ssize_t mdsize;
+  struct SBlock *sb;
+  struct SBlock *sb_enc;
+  char *dest;
+  struct GNUNET_CONTAINER_MetaData *mmeta;
+  GNUNET_HashCode key;         /* hash of thisId = key */
+  GNUNET_HashCode id;          /* hash of hc = identifier */
+  GNUNET_HashCode query;       /* id ^ nsid = DB query */
+
+  if (NULL == meta)
+    mmeta = GNUNET_CONTAINER_meta_data_create ();
+  else
+    mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
+  uris = GNUNET_FS_uri_to_string (uri);
+  slen = strlen (uris) + 1;
+  idlen = strlen (identifier);
+  if (update == NULL)
+    update = "";
+  nidlen = strlen (update) + 1;
+  mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
+  size = sizeof (struct SBlock) + slen + nidlen + mdsize;
+  if (size > MAX_SBLOCK_SIZE)
+    {
+      size = MAX_SBLOCK_SIZE;
+      mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
+    }
+  sb = GNUNET_malloc (sizeof (struct SBlock) + size);
+  dest = (char *) &sb[1];
+  memcpy (dest, update, nidlen);
+  dest += nidlen;
+  memcpy (dest, uris, slen);
+  GNUNET_free (uris);
+  dest += slen;
+  mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta,
+                                                &dest,
+                                                mdsize, 
+                                                
GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
+  GNUNET_CONTAINER_meta_data_destroy (mmeta);
+  if (mdsize == -1)
+    {
+      GNUNET_break (0);
+      GNUNET_free (sb);
+      cont (cont_cls,
+           NULL,
+           _("Internal error."));
+      return;
+    }
+  size = sizeof (struct SBlock) + mdsize + slen + nidlen;
+  sb_enc = GNUNET_malloc (size);
+  GNUNET_CRYPTO_hash (identifier, idlen, &key);
+  GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
+  sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+  sks_uri->type = sks;
+  GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
+  GNUNET_CRYPTO_hash (&sb_enc->subspace,
+                     sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                     &sks_uri->data.sks.namespace);
+  sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
+  GNUNET_CRYPTO_hash_xor (&id, 
+                         &sks_uri->data.sks.namespace, 
+                         &sb_enc->identifier);
+  GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
+  GNUNET_CRYPTO_aes_encrypt (&sb[1],
+                            size - sizeof (struct SBlock),
+                            &sk,
+                            &iv,
+                            &sb_enc[1]);
+  sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
+  sb_enc->purpose.size = htonl(slen + mdsize + nidlen
+                              + sizeof(struct SBlock)
+                              - sizeof(struct GNUNET_CRYPTO_RsaSignature));
+  GNUNET_assert (GNUNET_OK == 
+                GNUNET_CRYPTO_rsa_sign (namespace->key,
+                                        &sb_enc->purpose,
+                                        &sb_enc->signature));
+  psc = GNUNET_malloc (sizeof(struct PublishSksContext));
+  psc->uri = sks_uri;
+  psc->cont = cont;
+  psc->namespace = namespace;
+  namespace->rc++;
+  psc->cont_cls = cont_cls;
+  if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
+    {
+      GNUNET_free (sb_enc);
+      GNUNET_free (sb);
+      sb_put_cont (psc,
+                  GNUNET_OK,
+                  NULL);
+      return;
+    }
+  psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
+  if (NULL == psc->dsh)
+    {
+      GNUNET_free (sb_enc);
+      GNUNET_free (sb);
+      sb_put_cont (psc,
+                  GNUNET_NO,
+                  _("Failed to connect to datastore."));
+      return;
+    }
+  GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace,
+                         &id,
+                         &query);  
+  if (NULL != update)
+    {
+      psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
+      psc->nsn->id = GNUNET_strdup (identifier);
+      psc->nsn->update = GNUNET_strdup (update);
+      psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
+      psc->nsn->uri = GNUNET_FS_uri_dup (uri);
+    }
+  GNUNET_DATASTORE_put (psc->dsh,
+                       0,
+                       &sb_enc->identifier,
+                       size,
+                       sb_enc,
+                       GNUNET_BLOCK_TYPE_SBLOCK, 
+                       priority,
+                       anonymity,
+                       expirationTime,
+                       -2, 1,
+                       GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+                       &sb_put_cont,
+                       psc);
+  GNUNET_free (sb);
+  GNUNET_free (sb_enc);
+}
+
+
+/**
+ * Closure for 'process_update_node'.
+ */
+struct ProcessUpdateClosure 
+{
+  /**
+   * Function to call for each node.
+   */
+  GNUNET_FS_IdentifierProcessor ip;
+
+  /**
+   * Closure for 'ip'.
+   */
+  void *ip_cls;
+};
+
+
+/**
+ * Call the iterator in the closure for each node.
+ *
+ * @param cls closure (of type 'struct ProcessUpdateClosure *')
+ * @param key current key code
+ * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
+ * @return GNUNET_YES if we should continue to
+ *         iterate,
+ *         GNUNET_NO if not.
+ */
+static int
+process_update_node (void *cls,
+                    const GNUNET_HashCode * key,
+                    void *value)
+{
+  struct ProcessUpdateClosure *pc = cls;
+  struct NamespaceUpdateNode *nsn = value;
+
+  pc->ip (pc->ip_cls,
+         nsn->id,
+         nsn->uri,
+         nsn->md,
+         nsn->update);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Closure for 'find_sccs'.
+ */
+struct FindSccClosure 
+{
+  /**
+   * Namespace we are operating on.
+   */
+  struct GNUNET_FS_Namespace *namespace;
+
+  /**
+   * Array with 'head's of SCCs.
+   */
+  struct NamespaceUpdateNode **scc_array;
+
+  /**
+   * Size of 'scc_array'
+   */
+  unsigned int scc_array_size;
+
+  /**
+   * Current generational ID used.
+   */
+  unsigned int nug;
+
+  /**
+   * Identifier for the current SCC, or UINT_MAX for none yet.
+   */
+  unsigned int id;
+};
+
+
+/**
+ * Find all nodes reachable from the current node (including the
+ * current node itself).  If they are in no SCC, add them to the
+ * current one.   If they are the head of another SCC, merge the
+ * SCCs.  If they are in the middle of another SCC, let them be.
+ * We can tell that a node is already in an SCC by checking if
+ * its 'nug' field is set to the current 'nug' value.  It is the
+ * head of an SCC if it is in the 'scc_array' under its respective
+ * 'scc_id'.
+ *
+ * @param cls closure (of type 'struct FindSccClosure')
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ *         iterate,
+ *         GNUNET_NO if not.
+ */
+static int
+find_sccs (void *cls,
+          const GNUNET_HashCode * key,
+          void *value)
+{
+  struct FindSccClosure *fc = cls;
+  struct NamespaceUpdateNode *nsn = value;
+  GNUNET_HashCode hc;
+
+  if (nsn->nug == fc->nug)
+    {
+      if (fc->scc_array[nsn->scc_id] != nsn)
+       return GNUNET_YES; /* part of another SCC, end trace */
+      fc->scc_array[nsn->scc_id] = NULL;
+      if (fc->id == UINT_MAX)
+       fc->id = nsn->scc_id; /* take over ID */
+    }
+  else
+    {
+      nsn->nug = fc->nug;
+      /* trace */
+      GNUNET_CRYPTO_hash (nsn->update,
+                         strlen (nsn->update),
+                         &hc);
+      GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map,
+                                                 &hc,
+                                                 &find_sccs,
+                                                 fc);
+    }
+  return GNUNET_YES;
+}
+
+
+/**
+ * List all of the identifiers in the namespace for which we could
+ * produce an update.  Namespace updates form a graph where each node
+ * has a name.  Each node can have any number of URI/meta-data entries
+ * which can each be linked to other nodes.  Cycles are possible.
+ * 
+ * Calling this function with "next_id" NULL will cause the library to
+ * call "ip" with a root for each strongly connected component of the
+ * graph (a root being a node from which all other nodes in the Scc
+ * are reachable).
+ * 
+ * Calling this function with "next_id" being the name of a node will
+ * cause the library to call "ip" with all children of the node.  Note
+ * that cycles within an SCC are possible (including self-loops).
+ *
  * @param namespace namespace to inspect for updateable content
+ * @param next_id ID to look for; use NULL to look for SCC roots
  * @param ip function to call on each updateable identifier
  * @param ip_cls closure for ip
  */
 void
 GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace,
+                                    const char *next_id,
                                     GNUNET_FS_IdentifierProcessor ip, 
                                     void *ip_cls)
 {
-  GNUNET_break (0);
+  unsigned int i;
+  unsigned int nug;
+  GNUNET_HashCode hc;
+  struct NamespaceUpdateNode *nsn;
+  struct ProcessUpdateClosure pc;
+  struct FindSccClosure fc;
+
+  if (namespace->update_nodes == NULL)
+    read_update_information_graph (namespace);
+  if (namespace->update_nodes == NULL)
+    return; /* no nodes */
+  if (namespace->update_map == NULL)
+    {
+      /* need to construct */
+      namespace->update_map = GNUNET_CONTAINER_multihashmap_create (2 + 3 * 
namespace->update_node_count / 4);
+      for (i=0;i<namespace->update_node_count;i++)
+       {
+         nsn = namespace->update_nodes[i];
+         GNUNET_CRYPTO_hash (nsn->id,
+                             strlen (nsn->id),
+                             &hc);
+         GNUNET_CONTAINER_multihashmap_put (namespace->update_map,
+                                            &hc,
+                                            nsn,
+                                            
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);                         
+       }
+    }
+  if (next_id != NULL)
+    {
+      GNUNET_CRYPTO_hash (next_id,
+                         strlen (next_id),
+                         &hc);
+      pc.ip = ip;
+      pc.ip_cls = ip_cls;
+      GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
+                                                 &hc,
+                                                 &process_update_node,
+                                                 &pc);
+      return;
+    }
+  /* Find heads of SCCs in update graph */
+  nug = ++namespace->nug_gen;
+  fc.scc_array = NULL;
+  fc.scc_array_size = 0;
+
+  for (i=0;i<namespace->update_node_count;i++)
+    {
+      nsn = namespace->update_nodes[i];
+      if (nsn->nug == nug)
+       continue; /* already placed in SCC */
+      GNUNET_CRYPTO_hash (nsn->update,
+                         strlen (nsn->update),
+                         &hc);
+      nsn->nug = nug;
+      fc.id = UINT_MAX;
+      fc.nug = nug;
+      fc.namespace = namespace;
+      GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
+                                                 &hc,
+                                                 &find_sccs,
+                                                 &fc);
+      if (fc.id == UINT_MAX)
+       {
+         /* start new SCC */
+         for (fc.id=0;fc.id<fc.scc_array_size;fc.id++)
+           {
+             if (fc.scc_array[fc.id] == NULL)
+               {
+                 fc.scc_array[fc.id] = nsn;
+                 nsn->scc_id = fc.id;
+                 break;
+               }
+           }
+         if (fc.id == fc.scc_array_size)
+           {
+             GNUNET_array_append (fc.scc_array,
+                                  fc.scc_array_size,
+                                  nsn);
+             nsn->scc_id = fc.id;
+           }
+         /* put all nodes with same identifier into this SCC */
+         GNUNET_CRYPTO_hash (nsn->id,
+                             strlen (nsn->id),
+                             &hc);
+         fc.id = nsn->scc_id;
+         fc.nug = nug;
+         fc.namespace = namespace;
+         GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
+                                                     &hc,
+                                                     &find_sccs,
+                                                     &fc);
+       }
+      else
+       {
+         /* make head of SCC "id" */
+         fc.scc_array[fc.id] = nsn;
+         nsn->scc_id = fc.id;
+       }
+    }
+  for (i=0;i<fc.scc_array_size;i++)
+    {
+      nsn = fc.scc_array[i];
+      ip (ip_cls,
+         nsn->id,
+         nsn->uri,
+         nsn->md,
+         nsn->update);
+    }
+  GNUNET_array_grow (fc.scc_array,
+                    fc.scc_array_size,
+                    0);
 }
 
 
-
 /* end of fs_namespace.c */
 

Modified: gnunet/src/fs/fs_publish.c
===================================================================
--- gnunet/src/fs/fs_publish.c  2010-08-07 09:13:22 UTC (rev 12489)
+++ gnunet/src/fs/fs_publish.c  2010-08-07 16:54:29 UTC (rev 12490)
@@ -1709,223 +1709,4 @@
 }
 
 
-/**
- * Context for the SKS publication.
- */
-struct PublishSksContext
-{
-
-  /**
-   * Global FS context.
-   */
-  struct GNUNET_FS_Uri *uri;
-
-  /**
-   * Handle to the datastore.
-   */
-  struct GNUNET_DATASTORE_Handle *dsh;
-
-  /**
-   * Function to call once we're done.
-   */
-  GNUNET_FS_PublishContinuation cont;
-
-  /**
-   * Closure for cont.
-   */ 
-  void *cont_cls;
-
-};
-
-
-/**
- * Function called by the datastore API with
- * the result from the PUT (SBlock) request.
- *
- * @param cls closure of type "struct PublishSksContext*"
- * @param success GNUNET_OK on success
- * @param msg error message (or NULL)
- */
-static void
-sb_put_cont (void *cls,
-            int success,
-            const char *msg)
-{
-  struct PublishSksContext *psc = cls;
-
-  if (NULL != psc->dsh)
-    {
-      GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
-      psc->dsh = NULL;
-    }
-  if (GNUNET_OK != success)
-    psc->cont (psc->cont_cls,
-              NULL,
-              msg);
-  else
-    psc->cont (psc->cont_cls,
-              psc->uri,
-              NULL);
-  GNUNET_FS_uri_destroy (psc->uri);
-  GNUNET_free (psc);
-}
-
-
-/**
- * Publish an SBlock on GNUnet.
- *
- * @param h handle to the file sharing subsystem
- * @param namespace namespace to publish in
- * @param identifier identifier to use
- * @param update update identifier to use
- * @param meta metadata to use
- * @param uri URI to refer to in the SBlock
- * @param expirationTime when the SBlock expires
- * @param anonymity anonymity level for the SBlock
- * @param priority priority for the SBlock
- * @param options publication options
- * @param cont continuation
- * @param cont_cls closure for cont
- */
-void
-GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
-                      struct GNUNET_FS_Namespace *namespace,
-                      const char *identifier,
-                      const char *update,
-                      const struct GNUNET_CONTAINER_MetaData *meta,
-                      const struct GNUNET_FS_Uri *uri,
-                      struct GNUNET_TIME_Absolute expirationTime,
-                      uint32_t anonymity,
-                      uint32_t priority,
-                      enum GNUNET_FS_PublishOptions options,
-                      GNUNET_FS_PublishContinuation cont,
-                      void *cont_cls)
-{
-  struct PublishSksContext *psc;
-  struct GNUNET_CRYPTO_AesSessionKey sk;
-  struct GNUNET_CRYPTO_AesInitializationVector iv;
-  struct GNUNET_FS_Uri *sks_uri;
-  char *uris;
-  size_t size;
-  size_t slen;
-  size_t nidlen;
-  size_t idlen;
-  ssize_t mdsize;
-  struct SBlock *sb;
-  struct SBlock *sb_enc;
-  char *dest;
-  struct GNUNET_CONTAINER_MetaData *mmeta;
-  GNUNET_HashCode key;         /* hash of thisId = key */
-  GNUNET_HashCode id;          /* hash of hc = identifier */
-  GNUNET_HashCode query;       /* id ^ nsid = DB query */
-
-  if (NULL == meta)
-    mmeta = GNUNET_CONTAINER_meta_data_create ();
-  else
-    mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
-  uris = GNUNET_FS_uri_to_string (uri);
-  slen = strlen (uris) + 1;
-  idlen = strlen (identifier);
-  if (update == NULL)
-    update = "";
-  nidlen = strlen (update) + 1;
-  mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
-  size = sizeof (struct SBlock) + slen + nidlen + mdsize;
-  if (size > MAX_SBLOCK_SIZE)
-    {
-      size = MAX_SBLOCK_SIZE;
-      mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
-    }
-  sb = GNUNET_malloc (sizeof (struct SBlock) + size);
-  dest = (char *) &sb[1];
-  memcpy (dest, update, nidlen);
-  dest += nidlen;
-  memcpy (dest, uris, slen);
-  GNUNET_free (uris);
-  dest += slen;
-  mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta,
-                                                &dest,
-                                                mdsize, 
-                                                
GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
-  GNUNET_CONTAINER_meta_data_destroy (mmeta);
-  if (mdsize == -1)
-    {
-      GNUNET_break (0);
-      GNUNET_free (sb);
-      cont (cont_cls,
-           NULL,
-           _("Internal error."));
-      return;
-    }
-  size = sizeof (struct SBlock) + mdsize + slen + nidlen;
-  sb_enc = GNUNET_malloc (size);
-  GNUNET_CRYPTO_hash (identifier, idlen, &key);
-  GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
-  sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
-  sks_uri->type = sks;
-  GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
-  GNUNET_CRYPTO_hash (&sb_enc->subspace,
-                     sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                     &sks_uri->data.sks.namespace);
-  sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
-  GNUNET_CRYPTO_hash_xor (&id, 
-                         &sks_uri->data.sks.namespace, 
-                         &sb_enc->identifier);
-  GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
-  GNUNET_CRYPTO_aes_encrypt (&sb[1],
-                            size - sizeof (struct SBlock),
-                            &sk,
-                            &iv,
-                            &sb_enc[1]);
-  sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
-  sb_enc->purpose.size = htonl(slen + mdsize + nidlen
-                              + sizeof(struct SBlock)
-                              - sizeof(struct GNUNET_CRYPTO_RsaSignature));
-  GNUNET_assert (GNUNET_OK == 
-                GNUNET_CRYPTO_rsa_sign (namespace->key,
-                                        &sb_enc->purpose,
-                                        &sb_enc->signature));
-  psc = GNUNET_malloc (sizeof(struct PublishSksContext));
-  psc->uri = sks_uri;
-  psc->cont = cont;
-  psc->cont_cls = cont_cls;
-  if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
-    {
-      GNUNET_free (sb_enc);
-      GNUNET_free (sb);
-      sb_put_cont (psc,
-                  GNUNET_OK,
-                  NULL);
-      return;
-    }
-  psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
-  if (NULL == psc->dsh)
-    {
-      GNUNET_free (sb_enc);
-      GNUNET_free (sb);
-      sb_put_cont (psc,
-                  GNUNET_NO,
-                  _("Failed to connect to datastore."));
-      return;
-    }
-  GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace,
-                         &id,
-                         &query);  
-  GNUNET_DATASTORE_put (psc->dsh,
-                       0,
-                       &sb_enc->identifier,
-                       size,
-                       sb_enc,
-                       GNUNET_BLOCK_TYPE_SBLOCK, 
-                       priority,
-                       anonymity,
-                       expirationTime,
-                       -2, 1,
-                       GNUNET_CONSTANTS_SERVICE_TIMEOUT,
-                       &sb_put_cont,
-                       psc);
-  GNUNET_free (sb);
-  GNUNET_free (sb_enc);
-}
-
 /* end of fs_publish.c */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]