//TODO define other variables
#define GNUNET_REST_ERROR_UNKNOWN "Unkown Error"
+/**
+ * How long until we time out during address lookup?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
/**
* The configuration handle
*/
//TODO add specific structs
+/**
+ * Record we keep for each printable address.
+ */
+struct AddressRecord
+{
+ /**
+ * Current address-to-string context (if active, otherwise NULL).
+ */
+ struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
+
+ /**
+ * Address expiration time
+ */
+ struct GNUNET_TIME_Absolute expiration;
+
+ /**
+ * Printable address.
+ */
+ char *result;
+
+ /**
+ * Print context this address record belongs to.
+ */
+ struct PrintContext *pc;
+};
+
+
+/**
+ * Structure we use to collect printable address information.
+ */
+struct PrintContext
+{
+
+ /**
+ * Kept in DLL.
+ */
+ struct PrintContext *next;
+
+ /**
+ * Kept in DLL.
+ */
+ struct PrintContext *prev;
+
+ /**
+ * Identity of the peer.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * List of printable addresses.
+ */
+ struct AddressRecord *address_list;
+
+ /**
+ * Number of completed addresses in @e address_list.
+ */
+ unsigned int num_addresses;
+
+ /**
+ * Number of addresses allocated in @e address_list.
+ */
+ unsigned int address_list_size;
+
+ /**
+ * Current offset in @e address_list (counted down).
+ */
+ unsigned int off;
+
+ /**
+ * Hello was friend only, #GNUNET_YES or #GNUNET_NO
+ */
+ int friend_only;
+
+ /**
+ * RequestHandle
+ */
+ struct RequestHandle *handle;
+
+};
+
+/**
+ * Head of list of print contexts.
+ */
+static struct PrintContext *pc_head;
+
+/**
+ * Tail of list of print contexts.
+ */
+static struct PrintContext *pc_tail;
struct RequestHandle
{
{
struct RequestHandle *handle = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test: %i\n", NULL == handle);
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Cleaning up\n");
if (NULL != handle->timeout_task)
static void
peerinfo_list_finished (void *cls)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "6\n");
struct RequestHandle *handle = cls;
char *result_str;
struct MHD_Response *resp;
/**
- * Set @a cls to #GNUNET_YES (we have an address!).
+ * Iterator callback to go over all addresses and count them.
*
- * @param cls closure, an `int *`
- * @param address the address (ignored)
- * @param expiration expiration time (call is ignored if this is in the past)
- * @return #GNUNET_SYSERR to stop iterating (unless expiration has occured)
+ * @param cls `struct PrintContext *` with `off` to increment
+ * @param address the address
+ * @param expiration expiration time
+ * @return #GNUNET_OK to keep the address and continue
*/
static int
-check_has_addr (void *cls,
- const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Absolute expiration)
+count_address (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
{
- int *arg = cls;
+ struct PrintContext *pc = cls;
+
if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
{
- return GNUNET_YES; /* ignore this address */
+ return GNUNET_OK; /* ignore expired address */
}
- *arg = GNUNET_YES;
- return GNUNET_SYSERR;
-}
-static void
-create_array(void *cls)
-{
- struct RequestHandle *handle = cls;
-// json_t *object;
-// object = json_object();
-//
-// json_object_set(object,"address",json_string(handle->address));
-// json_object_set(object,"expires",json_string(handle->expiration_str));
-//
-// if(NULL == handle->temp_array)
-// {
-// handle->temp_array = json_array();
-// }
-//
-// json_array_append(handle->temp_array,object);
-//
-// json_decref(object);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "5\n");
- json_object_set(handle->response, handle->pubkey, handle->temp_array);
- json_decref (handle->temp_array);
+ pc->off++;
+ return GNUNET_OK;
}
+
+/**
+ * Print the collected address information to the console and free @a pc.
+ *
+ * @param pc printing context
+ */
static void
-create_tmp_array (void *cls)
+dump_pc (struct PrintContext *pc)
{
- struct RequestHandle *handle = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "4\n");
+ struct RequestHandle *handle;
+ unsigned int i;
+ json_t *temp_array;
json_t *object;
- json_t *address_json = json_string (handle->address);
- json_t *expires_json = json_string (handle->expiration_str);
- object = json_object ();
+ json_t *address;
+ json_t *expires;
+ char *friend_and_peer;
- json_object_set (object, "address", address_json);
- json_decref(address_json);
- json_object_set (object, "expires", expires_json);
- json_decref(expires_json);
- GNUNET_free(handle->expiration_str);
+ temp_array = json_array();
- if (NULL == handle->temp_array)
+// printf (_("%sPeer `%s'\n"),
+// (GNUNET_YES == pc->friend_only) ? "F2F: " : "",
+// GNUNET_i2s_full (&pc->peer));
+ for (i = 0; i < pc->num_addresses; i++)
{
- handle->temp_array = json_array ();
+ if (NULL != pc->address_list[i].result)
+ {
+ object = json_object ();
+ address = json_string(pc->address_list[i].result);
+ expires = json_string(
+ GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration));
+ json_object_set (object, "address", address);
+ json_object_set (object, "expires", expires);
+
+ json_decref(address);
+ json_decref(expires);
+
+ json_array_append(temp_array, object);
+ json_decref(object);
+ GNUNET_free (pc->address_list[i].result);
+ }
}
- json_array_append (handle->temp_array, object);
+ if (0 < json_array_size(temp_array))
+ {
+ GNUNET_asprintf(&friend_and_peer,
+ "%s%s",
+ (GNUNET_YES == pc->friend_only) ? "F2F:" : "",
+ GNUNET_i2s_full (&pc->peer));
+ json_object_set(pc->handle->response,
+ friend_and_peer,
+ temp_array);
+ GNUNET_free(friend_and_peer);
+ }
+
+ json_decref (temp_array);
+
+ GNUNET_free_non_null (pc->address_list);
+ GNUNET_CONTAINER_DLL_remove (pc_head,
+ pc_tail,
+ pc);
+ handle = pc->handle;
+ GNUNET_free (pc);
+
+ if ( (NULL == pc_head) &&
+ (NULL == handle->list_it) )
+ {
+ GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
+ }
- json_decref (object);
}
+
+/**
+ * Function to call with a human-readable format of an address
+ *
+ * @param cls closure
+ * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
+ * @param res result of the address to string conversion:
+ * if #GNUNET_OK: address was valid (conversion to
+ * string might still have failed)
+ * if #GNUNET_SYSERR: address is invalid
+ */
static void
-addr_to_str_cb (void *cls,
- const char *address,
- int res)
+process_resolved_address (void *cls,
+ const char *address,
+ int res)
{
- struct RequestHandle *handle = cls;
- if (NULL == address)
- {
- return;
- }
- if (GNUNET_OK != res)
+ struct AddressRecord *ar = cls;
+ struct PrintContext *pc = ar->pc;
+
+ if (NULL != address)
{
+ if (0 != strlen (address))
+ {
+ if (NULL != ar->result)
+ GNUNET_free (ar->result);
+ ar->result = GNUNET_strdup (address);
+ }
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "3\n");
- handle->address = GNUNET_strdup(address);
- GNUNET_assert(false);
+ ar->atsc = NULL;
+ if (GNUNET_SYSERR == res)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Failure: Cannot convert address to string for peer `%s'\n"),
+ GNUNET_i2s (&ar->pc->peer));
+ pc->num_addresses++;
+ if (pc->num_addresses == pc->address_list_size)
+ dump_pc (ar->pc);
}
+
/**
- * Set @a cls to #GNUNET_YES (we have an address!).
+ * Iterator callback to go over all addresses.
*
* @param cls closure
- * @param address the address (ignored)
- * @param expiration expiration time (call is ignored if this is in the past)
- * @return #GNUNET_SYSERR to stop iterating (unless expiration has occured)
+ * @param address the address
+ * @param expiration expiration time
+ * @return #GNUNET_OK to keep the address and continue
*/
static int
-address_iteration (void *cls,
- const struct GNUNET_HELLO_Address *address,
- struct GNUNET_TIME_Absolute expiration)
+print_address (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
{
- struct RequestHandle *handle = cls;
- char *expiration_tmp;
+ struct PrintContext *pc = cls;
+ struct AddressRecord *ar;
if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
{
- return GNUNET_YES; /* ignore this address */
+ return GNUNET_OK; /* ignore expired address */
}
- expiration_tmp = GNUNET_STRINGS_absolute_time_to_string(expiration);
- handle->expiration_str = GNUNET_strdup(expiration_tmp);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "2\n");
- GNUNET_TRANSPORT_address_to_string(cfg,
- address,
- GNUNET_NO,
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
- &addr_to_str_cb,
- handle);
-
- GNUNET_SCHEDULER_add_now(&create_tmp_array,handle);
-
-// GNUNET_SCHEDULER_add_delayed (
-// GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 11),
-// &create_array,
-// handle);
- return GNUNET_YES;
+
+ GNUNET_assert (0 < pc->off);
+ ar = &pc->address_list[--pc->off];
+ ar->pc = pc;
+ ar->expiration = expiration;
+ GNUNET_asprintf (&ar->result,
+ "%s:%u:%u",
+ address->transport_name,
+ address->address_length,
+ address->local_info);
+ ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
+ address,
+ GNUNET_NO,
+ TIMEOUT,
+ &process_resolved_address,
+ ar);
+ return GNUNET_OK;
}
const char *err_msg)
{
struct RequestHandle *handle = cls;
- int has_addr;
+ struct PrintContext *pc;
+ int friend_only;
if (NULL == handle->response)
{
handle->response = json_object();
}
- if (NULL != err_msg)
- {
- GNUNET_assert (NULL == peer);
- handle->list_it = NULL;
- handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
if (NULL == peer)
{
handle->list_it = NULL;
- GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
+ handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
+ if (NULL != err_msg)
+ {
+ GNUNET_free(handle->emsg);
+ handle->emsg = GNUNET_strdup (err_msg);
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ if (NULL == pc_head)
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
if (NULL == hello)
return;
- has_addr = GNUNET_NO;
+
+ friend_only = GNUNET_NO;
+ if (NULL != hello)
+ friend_only = GNUNET_HELLO_is_friend_only (hello);
+
+ pc = GNUNET_new(struct PrintContext);
+ GNUNET_CONTAINER_DLL_insert (pc_head,
+ pc_tail,
+ pc);
+ pc->peer = *peer;
+ pc->friend_only = friend_only;
+ pc->handle = handle;
GNUNET_HELLO_iterate_addresses (hello,
- GNUNET_NO,
- &check_has_addr,
- &has_addr);
- if (GNUNET_NO == has_addr)
+ GNUNET_NO,
+ &count_address,
+ pc);
+ if (0 == pc->off)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "HELLO for peer `%4s' has no address, not suitable for hostlist!\n",
- GNUNET_i2s (peer));
+ dump_pc (pc);
return;
}
-
- if (NULL != handle->pubkey)
- GNUNET_free (handle->pubkey);
- handle->pubkey = GNUNET_CRYPTO_eddsa_public_key_to_string(&peer->public_key);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "1\n");
+ pc->address_list_size = pc->off;
+ pc->address_list = GNUNET_malloc(
+ sizeof(struct AddressRecord) * pc->off);
GNUNET_HELLO_iterate_addresses (hello,
- GNUNET_NO,
- &address_iteration,
- handle);
- GNUNET_SCHEDULER_add_now(&create_array,handle);
+ GNUNET_NO,
+ &print_address,
+ pc);
}
/**
const struct GNUNET_PeerIdentity *specific_peer;
GNUNET_PEER_Id peer_id;
int include_friend_only;
+ char* include_friend_only_str;
include_friend_only = GNUNET_NO;
GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_FRIEND,
== GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
&key))
{
- include_friend_only = *(int*)GNUNET_CONTAINER_multihashmap_get (
+ include_friend_only_str = GNUNET_CONTAINER_multihashmap_get (
con_handle->url_param_map, &key);
- }
- if(GNUNET_YES != include_friend_only)
- {
- include_friend_only = GNUNET_NO;
+ if (0 == strcmp(include_friend_only_str, "yes"))
+ {
+ include_friend_only = GNUNET_YES;
+ }
}
specific_peer = NULL;
specific_peer = GNUNET_PEER_resolve2(peer_id);
}
-
- //TODO friend_only and special peer
-
- //TODO add behaviour and response
- //TODO maybe notify better than iteration
-
handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle,
include_friend_only,
specific_peer,
struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
handle->response_code = 0;
- handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
handle->proc_cls = proc_cls;
handle->proc = proc;
handle->rest_handle = rest_handle;