/**
 * Read the friends file.
 */
static void
read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  char *fn;
  char *data;
  size_t pos;
  struct GNUNET_PeerIdentity pid;
  uint64_t fsize;
  struct GNUNET_CRYPTO_HashAsciiEncoded enc;
  unsigned int entries_found;
  struct Peer *fl;

  if (GNUNET_OK !=
      GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn))
  {
    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
			       "topology", "FRIENDS");
    return;
  }
  if (GNUNET_OK != GNUNET_DISK_file_test (fn))
    GNUNET_DISK_fn_write (fn, NULL, 0,
                          GNUNET_DISK_PERM_USER_READ |
                          GNUNET_DISK_PERM_USER_WRITE);
  if (GNUNET_OK != GNUNET_DISK_file_size (fn,
      &fsize, GNUNET_NO, GNUNET_YES))
  {
    if ((friends_only) || (minimum_friend_count > 0))
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Could not read friends list `%s'\n"), fn);
    GNUNET_free (fn);
    return;
  }
  if (fsize == 0)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Friends file `%s' is empty.\n"),
                fn);
    GNUNET_free (fn);
    return;
  }
  data = GNUNET_malloc_large (fsize);
  if (data == NULL)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to read friends list from `%s': out of memory\n"),
                fn);
    GNUNET_free (fn);
    return;
  }
  if (fsize != GNUNET_DISK_fn_read (fn, data, fsize))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to read friends list from `%s'\n"), fn);
    GNUNET_free (fn);
    GNUNET_free (data);
    return;
  }
  entries_found = 0;
  pos = 0;
  while ((pos < fsize) && isspace ((unsigned char) data[pos]))
    pos++;
  while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
         (pos <=
          fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
  {
    memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
    if (!isspace
        ((unsigned char)
         enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _
                  ("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
                  (unsigned long long) pos);
      pos++;
      while ((pos < fsize) && (!isspace ((unsigned char) data[pos])))
        pos++;
      continue;
    }
    enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
    if (GNUNET_OK !=
        GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _
                  ("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
                  (unsigned long long) pos, &enc);
    }
    else
    {
      if (0 != memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
      {
        entries_found++;
        fl = make_peer (&pid, NULL, GNUNET_YES);
        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                    _("Found friend `%s' in configuration\n"),
                    GNUNET_i2s (&fl->pid));
      }
      else
      {
        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                    _("Found myself `%s' in friend list (useless, ignored)\n"),
                    GNUNET_i2s (&pid));
      }
    }
    pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
    while ((pos < fsize) && isspace ((unsigned char) data[pos]))
      pos++;
  }
  GNUNET_free (data);
  GNUNET_free (fn);
  GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuration"),
                            entries_found, GNUNET_NO);
  if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _
                ("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
  }
  if ((minimum_friend_count > target_connection_count) &&
      (friends_only == GNUNET_NO))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _
                ("More friendly connections required than target total number of connections.\n"));
  }
}
/**
 * Try to read the HELLOs in the given filename and discard expired
 * addresses.  Removes the file if one the HELLO is malformed.  If all
 * addresses are expired, the HELLO is also removed (but the HELLO
 * with the public key is still returned if it was found and valid).
 * The file can contain multiple HELLO messages.
 *
 * @param fn name of the file
 * @param unlink_garbage if #GNUNET_YES, try to remove useless files
 * @param r ReadHostFileContext to store the resutl
 */
static void
read_host_file (const char *fn,
                int unlink_garbage,
                struct ReadHostFileContext *r)
{
  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  unsigned int size_total;
  struct GNUNET_TIME_Absolute now;
  unsigned int left;
  const struct GNUNET_HELLO_Message *hello;
  struct GNUNET_HELLO_Message *hello_clean;
  unsigned read_pos;
  int size_hello;

  r->friend_only_hello = NULL;
  r->hello = NULL;

  if (GNUNET_YES != GNUNET_DISK_file_test (fn))
    return;
  size_total = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Read %u bytes from `%s'\n",
              size_total,
              fn);
  if (size_total < sizeof (struct GNUNET_MessageHeader))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		_("Failed to parse HELLO in file `%s': %s\n"),
		fn, "Fail has invalid size");
    if ( (GNUNET_YES == unlink_garbage) &&
	 (0 != UNLINK (fn)) &&
	 (ENOENT != errno) )
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                "unlink",
                                fn);
    return;
  }

  read_pos = 0;
  while (read_pos < size_total)
  {
    hello = (const struct GNUNET_HELLO_Message *) &buffer[read_pos];
    size_hello = GNUNET_HELLO_size (hello);
    if (0 == size_hello)
      {
	GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		    _("Failed to parse HELLO in file `%s'\n"),
		    fn);
	if ((GNUNET_YES == unlink_garbage) &&
	    (0 != UNLINK (fn)) &&
	    (ENOENT != errno) )
	  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                    "unlink",
                                    fn);
	return;
      }

    now = GNUNET_TIME_absolute_get ();
    hello_clean = GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES,
						  &discard_expired, &now);
    if (NULL == hello_clean)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to parse HELLO in file `%s'\n"),
                  fn);
      if ((GNUNET_YES == unlink_garbage) &&
          (0 != UNLINK (fn)) &&
          (ENOENT != errno) )
        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                  "unlink",
                                  fn);
      return;
    }
    left = 0;
    (void) GNUNET_HELLO_iterate_addresses (hello_clean, GNUNET_NO,
					   &count_addresses, &left);

    if (0 == left)
    {
      GNUNET_free (hello_clean);
      break;
    }

    if (GNUNET_NO == GNUNET_HELLO_is_friend_only (hello_clean))
    {
      if (NULL == r->hello)
	r->hello = hello_clean;
      else
      {
	GNUNET_break (0);
	GNUNET_free (r->hello);
	r->hello = hello_clean;
      }
    }
    else
    {
      if (NULL == r->friend_only_hello)
	r->friend_only_hello = hello_clean;
      else
      {
	GNUNET_break (0);
	GNUNET_free (r->friend_only_hello);
	r->friend_only_hello = hello_clean;
      }
    }
    read_pos += size_hello;
  }

  if (0 == left)
  {
    /* no addresses left, remove from disk */
    if ( (GNUNET_YES == unlink_garbage) &&
         (0 != UNLINK (fn)) )
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                "unlink",
                                fn);
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Found `%s' and `%s' HELLO message in file\n",
	      (NULL != r->hello) ? "public" : "NON-public",
	      (NULL != r->friend_only_hello) ? "friend only" : "NO friend only");
}
Example #3
0
/**
 * Load a set of hosts from a configuration file.
 *
 * @param filename file with the host specification
 * @param cfg the configuration to use as a template while starting a controller
 *          on any of the loaded hosts.  Operation queue sizes specific to a host
 *          are also read from this configuration handle
 * @param hosts set to the hosts found in the file; caller must free this if
 *          number of hosts returned is greater than 0
 * @return number of hosts returned in 'hosts', 0 on error
 */
unsigned int
GNUNET_TESTBED_hosts_load_from_file (const char *filename,
                                     const struct GNUNET_CONFIGURATION_Handle
                                     *cfg,
                                     struct GNUNET_TESTBED_Host ***hosts)
{
  struct GNUNET_TESTBED_Host *starting_host;
  char *data;
  char *buf;
  char *username;
  char *hostname;
  regex_t rex;
  regmatch_t pmatch[6];
  uint64_t fs;
  short int port;
  unsigned int offset;
  unsigned int count;


  GNUNET_assert (NULL != filename);
  if (GNUNET_YES != GNUNET_DISK_file_test (filename))
  {
    LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s not found\n"), filename);
    return 0;
  }
  if (GNUNET_OK !=
      GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
    fs = 0;
  if (0 == fs)
  {
    LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s has no data\n"), filename);
    return 0;
  }
  data = GNUNET_malloc (fs);
  if (fs != GNUNET_DISK_fn_read (filename, data, fs))
  {
    GNUNET_free (data);
    LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s cannot be read\n"),
         filename);
    return 0;
  }
  buf = data;
  offset = 0;
  starting_host = NULL;
  count = 0;
  /* refer RFC 952 and RFC 1123 for valid hostnames */
  GNUNET_assert (0 == regcomp (&rex,
                               "^(([[:alnum:]]+)@)?" /* username */
                               "([[:alnum:]]+[-[:alnum:]_\\.]+)" /* hostname */
                               "(:([[:digit:]]{1,5}))?", /* port */
                               REG_EXTENDED | REG_ICASE));
  while (offset < (fs - 1))
  {
    offset++;
    if (((data[offset] == '\n')) && (buf != &data[offset]))
    {
      unsigned int size;

      data[offset] = '\0';
      username = NULL;
      hostname = NULL;
      port = 0;
      if ((REG_NOMATCH == regexec (&rex, buf, 6, pmatch, 0))
          || (-1 == pmatch[3].rm_so))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                    "Error reading line `%s' in hostfile\n", buf);
        buf = &data[offset + 1];
        continue;
      }
      if (-1 != pmatch[2].rm_so)
      {
        size = pmatch[2].rm_eo - pmatch[2].rm_so;
        username = GNUNET_malloc (size + 1);
        username[size] = '\0';
        GNUNET_assert (NULL != strncpy (username, buf + pmatch[2].rm_so, size));
      }
      if (-1 != pmatch[5].rm_so)
      {
        (void) SSCANF (buf + pmatch[5].rm_so, "%5hd", &port);
      }
      size = pmatch[3].rm_eo - pmatch[3].rm_so;
      hostname = GNUNET_malloc (size + 1);
      hostname[size] = '\0';
      GNUNET_assert (NULL != strncpy (hostname, buf + pmatch[3].rm_so, size));
      LOG (GNUNET_ERROR_TYPE_DEBUG,
           "Successfully read host %s, port %d and user %s from file\n",
           (NULL == hostname) ? "NULL" : hostname,
           port,
           (NULL == username) ? "NULL" : username);
      /* We store hosts in a static list; hence we only require the starting
       * host pointer in that list to access the newly created list of hosts */
      if (NULL == starting_host)
        starting_host = GNUNET_TESTBED_host_create (hostname, username, cfg,
                                                    port);
      else
        (void) GNUNET_TESTBED_host_create (hostname, username, cfg, port);
      count++;
      GNUNET_free_non_null (username);
      GNUNET_free (hostname);
      buf = &data[offset + 1];
    }
    else if ((data[offset] == '\n') || (data[offset] == '\0'))
      buf = &data[offset + 1];
  }
  regfree (&rex);
  GNUNET_free (data);
  if (NULL == starting_host)
    return 0;
  *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count);
  GNUNET_memcpy (*hosts,
                 &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
                 sizeof (struct GNUNET_TESTBED_Host *) * count);
  return count;
}
static void
run (void *cls, char *const *args, const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  struct GNUNET_TESTING_Host *hosts;
  struct GNUNET_TESTING_Host *hostpos;
  struct GNUNET_TESTING_Host *temphost;
  char *hostfile;
  struct stat frstat;
  char *buf;
  char *data;
  int count;
  int ret;

  ok = 1;
#if VERBOSE
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
#endif

  if (GNUNET_SYSERR ==
      GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
                                             &num_peers))
    num_peers = DEFAULT_NUM_PEERS;

  GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1);
  if (GNUNET_OK !=
      GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile",
                                             &hostfile))
    hostfile = NULL;

  hosts = NULL;
  data = NULL;
  if (hostfile != NULL)
  {
    if (GNUNET_OK != GNUNET_DISK_file_test (hostfile))
      GNUNET_DISK_fn_write (hostfile, NULL, 0,
                            GNUNET_DISK_PERM_USER_READ |
                            GNUNET_DISK_PERM_USER_WRITE);
    if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Could not open file specified for host list, ending test!");
      ok = 1119;
      GNUNET_free (hostfile);
      return;
    }

    data = GNUNET_malloc_large (frstat.st_size);
    GNUNET_assert (data != NULL);
    if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Could not read file %s specified for host list, ending test!",
                  hostfile);
      GNUNET_free (hostfile);
      GNUNET_free (data);
      return;
    }

    GNUNET_free_non_null (hostfile);

    buf = data;
    count = 0;
    while (count < frstat.st_size)
    {
      count++;
      if (count >= frstat.st_size)
        break;

      /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */
      if (((data[count] == '\n')) && (buf != &data[count]))
      {
        data[count] = '\0';
        temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host));
        ret =
            SSCANF (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd",
                    &temphost->username, &temphost->hostname, &temphost->port);
        if (3 == ret)
        {
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                      "Successfully read host %s, port %d and user %s from file\n",
                      temphost->hostname, temphost->port, temphost->username);
        }
        else
        {
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                      "Error reading line `%s' in hostfile\n", buf);
          GNUNET_free (temphost);
          buf = &data[count + 1];
          continue;
        }
        /* temphost->hostname = buf; */
        temphost->next = hosts;
        hosts = temphost;
        buf = &data[count + 1];
      }
      else if ((data[count] == '\n') || (data[count] == '\0'))
        buf = &data[count + 1];
    }
  }

  peers_left = num_peers;
  pg = GNUNET_TESTING_daemons_start (cfg, peers_left,   /* Total number of peers */
                                     peers_left,        /* Number of outstanding connections */
                                     peers_left,        /* Number of parallel ssh connections, or peers being started at once */
                                     TIMEOUT, NULL, NULL, &my_cb, NULL, NULL,
                                     NULL, hosts);
  hostpos = hosts;
  while (hostpos != NULL)
  {
    temphost = hostpos->next;
    GNUNET_free (hostpos->hostname);
    GNUNET_free (hostpos->username);
    GNUNET_free (hostpos);
    hostpos = temphost;
  }
  GNUNET_free_non_null (data);
  GNUNET_assert (pg != NULL);

}