/**
 * Called every time there is data to read from the scanner.
 * Calls the scanner progress handler.
 *
 * @param cls the closure (directory scanner object)
 * @param client always NULL
 * @param msg message from the helper process
 */
static int
process_helper_msgs (void *cls, 
		     void *client,
		     const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_FS_DirScanner *ds = cls;
  const char *filename;
  size_t left;

#if 0
  fprintf (stderr, "DMS parses %u-byte message of type %u\n",
	   (unsigned int) ntohs (msg->size),
	   (unsigned int) ntohs (msg->type));
#endif
  left = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
  filename = (const char*) &msg[1];
  switch (ntohs (msg->type))
  {
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE:
    if (filename[left-1] != '\0')
    {
      GNUNET_break (0);
      break;
    }
    ds->progress_callback (ds->progress_callback_cls, 
			   filename, GNUNET_NO,
			   GNUNET_FS_DIRSCANNER_FILE_START);
    if (NULL == ds->toplevel)
      ds->toplevel = expand_tree (ds->pos,
				  filename, GNUNET_NO);
    else
      (void) expand_tree (ds->pos,
			  filename, GNUNET_NO);
    return GNUNET_OK;
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY:
    if (filename[left-1] != '\0')
    {
      GNUNET_break (0);
      break;
    }
    if (0 == strcmp ("..", filename))
    {
      if (NULL == ds->pos)
      {
	GNUNET_break (0);
	break;
      }
      ds->pos = ds->pos->parent;
      return GNUNET_OK;
    }
    ds->progress_callback (ds->progress_callback_cls, 
			   filename, GNUNET_YES,
			   GNUNET_FS_DIRSCANNER_FILE_START);
    ds->pos = expand_tree (ds->pos,
			   filename, GNUNET_YES);
    if (NULL == ds->toplevel)
      ds->toplevel = ds->pos;
    return GNUNET_OK;
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR:
    break;
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE:
    if ('\0' != filename[left-1])
      break;
    ds->progress_callback (ds->progress_callback_cls, 
			   filename, GNUNET_SYSERR,
			   GNUNET_FS_DIRSCANNER_FILE_IGNORED);
    return GNUNET_OK;
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE:
    if (0 != left)
    {
      GNUNET_break (0);
      break;
    }
    if (NULL == ds->toplevel)
    {
      GNUNET_break (0);
      break;
    }
    ds->progress_callback (ds->progress_callback_cls, 
			   NULL, GNUNET_SYSERR,
			   GNUNET_FS_DIRSCANNER_ALL_COUNTED);
    ds->pos = ds->toplevel;
    if (GNUNET_YES == ds->pos->is_directory)
      ds->pos = advance (ds->pos);
    return GNUNET_OK;
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA:
    {
      size_t nlen;
      const char *end;
      
      if (NULL == ds->pos)
      {
	GNUNET_break (0);
	break;
      }
      end = memchr (filename, 0, left);
      if (NULL == end)
      {
	GNUNET_break (0);
	break;
      }
      end++;
      nlen = end - filename;
      left -= nlen;
      if (0 != strcmp (filename,
		       ds->pos->filename))
      {
	GNUNET_break (0);
	break;
      }
      ds->progress_callback (ds->progress_callback_cls, 
			     filename, GNUNET_YES,
			     GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED);
      if (0 < left)
      {
	ds->pos->meta = GNUNET_CONTAINER_meta_data_deserialize (end, left);
	if (NULL == ds->pos->meta)
	{
	  GNUNET_break (0);
	  break;
	}
	/* having full filenames is too dangerous; always make sure we clean them up */
	GNUNET_CONTAINER_meta_data_delete (ds->pos->meta, 
					   EXTRACTOR_METATYPE_FILENAME,
					   NULL, 0);
	/* instead, put in our 'safer' original filename */
	GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, "<libgnunetfs>",
					   EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
					   EXTRACTOR_METAFORMAT_UTF8, "text/plain",
					   ds->pos->short_filename, 
					   strlen (ds->pos->short_filename) + 1);
      }
      ds->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (ds->pos->meta);
      ds->pos = advance (ds->pos);      
      return GNUNET_OK;
    }
  case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED:
    if (NULL != ds->pos)
    {
      GNUNET_break (0);
      break;
    }
    if (0 != left)
    {
      GNUNET_break (0);
      break;
    }   
    if (NULL == ds->toplevel)
    {
      GNUNET_break (0);
      break;
    }
    ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan,
					      ds);
    return GNUNET_OK;
  default:
    GNUNET_break (0);
    break;
  }
  ds->progress_callback (ds->progress_callback_cls, 
			 NULL, GNUNET_SYSERR,
			 GNUNET_FS_DIRSCANNER_INTERNAL_ERROR);
  return GNUNET_OK;
}
Exemple #2
0
/**
 * Iterate over all entries in a directory.  Note that directories
 * are structured such that it is possible to iterate over the
 * individual blocks as well as over the entire directory.  Thus
 * a client can call this function on the buffer in the
 * GNUNET_FS_ProgressCallback.  Also, directories can optionally
 * include the contents of (small) files embedded in the directory
 * itself; for those files, the processor may be given the
 * contents of the file directly by this function.
 * <p>
 *
 * Note that this function maybe called on parts of directories.  Thus
 * parser errors should not be reported _at all_ (with GNUNET_break).
 * Still, if some entries can be recovered despite these parsing
 * errors, the function should try to do this.
 *
 * @param size number of bytes in data
 * @param data pointer to the beginning of the directory
 * @param offset offset of data in the directory
 * @param dep function to call on each entry
 * @param dep_cls closure for dep
 * @return GNUNET_OK if this could be a block in a directory,
 *         GNUNET_NO if this could be part of a directory (but not 100% OK)
 *         GNUNET_SYSERR if 'data' does not represent a directory
 */
int
GNUNET_FS_directory_list_contents (size_t size, const void *data,
                                   uint64_t offset,
                                   GNUNET_FS_DirectoryEntryProcessor dep,
                                   void *dep_cls)
{
  struct GetFullDataClosure full_data;
  const char *cdata = data;
  char *emsg;
  uint64_t pos;
  uint64_t align;
  uint32_t mdSize;
  uint64_t epos;
  struct GNUNET_FS_Uri *uri;
  struct GNUNET_CONTAINER_MetaData *md;
  char *filename;

  if ((offset == 0) &&
      ((size < 8 + sizeof (uint32_t)) ||
       (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8))))
    return GNUNET_SYSERR;
  pos = offset;
  if (offset == 0)
  {
    GNUNET_memcpy (&mdSize, &cdata[8], sizeof (uint32_t));
    mdSize = ntohl (mdSize);
    if (mdSize > size - 8 - sizeof (uint32_t))
    {
      /* invalid size */
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _("MAGIC mismatch.  This is not a GNUnet directory.\n"));
      return GNUNET_SYSERR;
    }
    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 + sizeof (uint32_t)],
                                                 mdSize);
    if (md == NULL)
    {
      GNUNET_break (0);
      return GNUNET_SYSERR;     /* malformed ! */
    }
    dep (dep_cls, NULL, NULL, md, 0, NULL);
    GNUNET_CONTAINER_meta_data_destroy (md);
    pos = 8 + sizeof (uint32_t) + mdSize;
  }
  while (pos < size)
  {
    /* find end of URI */
    if (cdata[pos] == '\0')
    {
      /* URI is never empty, must be end of block,
       * skip to next alignment */
      align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE;
      if (align == pos)
      {
        /* if we were already aligned, still skip a block! */
        align += DBLOCK_SIZE;
      }
      pos = align;
      if (pos >= size)
      {
        /* malformed - or partial download... */
        break;
      }
    }
    epos = pos;
    while ((epos < size) && (cdata[epos] != '\0'))
      epos++;
    if (epos >= size)
      return GNUNET_NO;         /* malformed - or partial download */

    uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg);
    pos = epos + 1;
    if (uri == NULL)
    {
      GNUNET_free (emsg);
      pos--;                    /* go back to '\0' to force going to next alignment */
      continue;
    }
    if (GNUNET_FS_uri_test_ksk (uri))
    {
      GNUNET_FS_uri_destroy (uri);
      GNUNET_break (0);
      return GNUNET_NO;         /* illegal in directory! */
    }

    GNUNET_memcpy (&mdSize, &cdata[pos], sizeof (uint32_t));
    mdSize = ntohl (mdSize);
    pos += sizeof (uint32_t);
    if (pos + mdSize > size)
    {
      GNUNET_FS_uri_destroy (uri);
      return GNUNET_NO;         /* malformed - or partial download */
    }

    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize);
    if (md == NULL)
    {
      GNUNET_FS_uri_destroy (uri);
      GNUNET_break (0);
      return GNUNET_NO;         /* malformed ! */
    }
    pos += mdSize;
    filename =
        GNUNET_CONTAINER_meta_data_get_by_type (md,
                                                EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
    full_data.size = 0;
    full_data.data = NULL;
    GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data);
    if (dep != NULL)
    {
      dep (dep_cls, filename, uri, md, full_data.size, full_data.data);
    }
    GNUNET_free_non_null (full_data.data);
    GNUNET_free_non_null (filename);
    GNUNET_CONTAINER_meta_data_destroy (md);
    GNUNET_FS_uri_destroy (uri);
  }
  return GNUNET_OK;
}
Exemple #3
0
/**
 * Handles messages received from the service.  Calls the proper client
 * callback.
 */
static void
process_result (struct GNUNET_CHAT_Room *room,
                const struct GNUNET_MessageHeader *reply)
{
  struct LeaveNotificationMessage *leave_msg;
  struct JoinNotificationMessage *join_msg;
  struct ReceiveNotificationMessage *received_msg;
  struct ConfirmationReceiptMessage *receipt;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
  GNUNET_HashCode id;
  const GNUNET_HashCode *sender;
  struct GNUNET_CONTAINER_MetaData *meta;
  struct GNUNET_CHAT_SendReceiptContext *src;
  struct MemberList *pos;
  struct MemberList *prev;
  struct GNUNET_CRYPTO_AesSessionKey key;
  char decrypted_msg[MAX_MESSAGE_LENGTH];
  uint16_t size;
  uint16_t meta_len;
  uint16_t msg_len;
  char *message_content;

  size = ntohs (reply->size);
  switch (ntohs (reply->type))
  {
  case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION:
#if DEBUG_CHAT
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n");
#endif
    if (size < sizeof (struct JoinNotificationMessage))
    {
      GNUNET_break (0);
      return;
    }
    join_msg = (struct JoinNotificationMessage *) reply;
    meta_len = size - sizeof (struct JoinNotificationMessage);
    meta =
        GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1],
                                                meta_len);
    if (NULL == meta)
    {
      GNUNET_break (0);
      return;
    }
    pos = GNUNET_malloc (sizeof (struct MemberList));
    pos->meta = meta;
    GNUNET_CRYPTO_hash (&join_msg->public_key,
                        sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                        &pos->id);
    GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta);
    pos->next = room->members;
    room->members = pos;
    if (GNUNET_NO == room->is_joined)
    {
      GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey);
      if (0 ==
          memcmp (&join_msg->public_key, &pkey,
                  sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
      {
        room->join_callback (room->join_callback_cls);
        room->is_joined = GNUNET_YES;
      }
      else
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("The current user must be the the first one joined\n"));
        GNUNET_break (0);
        return;
      }
    }
    else
      room->member_list_callback (room->member_list_callback_cls, meta,
                                  &join_msg->public_key,
                                  ntohl (join_msg->msg_options));
    break;
  case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION:
#if DEBUG_CHAT
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n");
#endif
    if (size < sizeof (struct LeaveNotificationMessage))
    {
      GNUNET_break (0);
      return;
    }
    leave_msg = (struct LeaveNotificationMessage *) reply;
    room->member_list_callback (room->member_list_callback_cls, NULL,
                                &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE);
    GNUNET_CRYPTO_hash (&leave_msg->user,
                        sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                        &id);
    prev = NULL;
    pos = room->members;
    while ((NULL != pos) &&
           (0 != memcmp (&pos->id, &id, sizeof (GNUNET_HashCode))))
    {
      prev = pos;
      pos = pos->next;
    }
    GNUNET_assert (NULL != pos);
    if (NULL == prev)
      room->members = pos->next;
    else
      prev->next = pos->next;
    GNUNET_CONTAINER_meta_data_destroy (pos->meta);
    GNUNET_free (pos);
    break;
  case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION:
#if DEBUG_CHAT
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n");
#endif
    if (size <= sizeof (struct ReceiveNotificationMessage))
    {
      GNUNET_break (0);
      return;
    }
    received_msg = (struct ReceiveNotificationMessage *) reply;
    if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED))
    {
      src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext));
      src->chat_room = room;
      src->received_msg = GNUNET_memdup (received_msg, size);
      GNUNET_CLIENT_notify_transmit_ready (room->client,
                                           sizeof (struct
                                                   ConfirmationReceiptMessage),
                                           GNUNET_CONSTANTS_SERVICE_TIMEOUT,
                                           GNUNET_YES,
                                           &transmit_acknowledge_request, src);
    }
    msg_len = size - sizeof (struct ReceiveNotificationMessage);
    if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE))
    {
      if (-1 ==
          GNUNET_CRYPTO_rsa_decrypt (room->my_private_key,
                                     &received_msg->encrypted_key, &key,
                                     sizeof (struct
                                             GNUNET_CRYPTO_AesSessionKey)))
      {
        GNUNET_break (0);
        return;
      }
      msg_len =
          GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key,
                                     (const struct
                                      GNUNET_CRYPTO_AesInitializationVector *)
                                     INITVALUE, decrypted_msg);
      message_content = decrypted_msg;
    }
    else
    {
      message_content = GNUNET_malloc (msg_len + 1);
      memcpy (message_content, &received_msg[1], msg_len);
    }
    message_content[msg_len] = '\0';
    if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS))
    {
      sender = NULL;
      meta = NULL;
    }
    else
    {
      pos = room->members;
      while ((NULL != pos) &&
             (0 !=
              memcmp (&pos->id, &received_msg->sender,
                      sizeof (GNUNET_HashCode))))
        pos = pos->next;
      GNUNET_assert (NULL != pos);
      sender = &received_msg->sender;
      meta = pos->meta;
    }
    room->message_callback (room->message_callback_cls, room, sender, meta,
                            message_content,
                            GNUNET_TIME_absolute_ntoh (received_msg->timestamp),
                            ntohl (received_msg->msg_options));
    if (message_content != decrypted_msg)
      GNUNET_free (message_content);
    break;
  case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION:
#if DEBUG_CHAT
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n");
#endif
    if (size < sizeof (struct ConfirmationReceiptMessage))
    {
      GNUNET_break (0);
      return;
    }
    receipt = (struct ConfirmationReceiptMessage *) reply;
    if (NULL != room->confirmation_callback)
      room->confirmation_callback (room->confirmation_cls, room,
                                   ntohl (receipt->sequence_number),
                                   GNUNET_TIME_absolute_ntoh
                                   (receipt->timestamp), &receipt->target);
    break;
  default:
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"),
                ntohs (reply->type));
    GNUNET_break_op (0);
    break;
  }
}