* @author Julius Bünger
*/
#include "platform.h"
+#include "gnunet_applications.h"
#include "gnunet_util_lib.h"
#include "gnunet_cadet_service.h"
#include <inttypes.h>
*
* To be canceled on shutdown.
*/
- struct GNUNET_CADET_TransmitHandle *transmit_handle;
+ struct PendingMessage *liveliness_check_pending;
/**
* Number of pending operations.
* Identity of the peer
*/
struct GNUNET_PeerIdentity peer_id;
-
+
/**
* Flags indicating status of peer
*/
return ctx;
}
+
/**
* @brief Create a new #PeerContext and insert it into the peer map
*
return ctx;
}
+
/**
* @brief Create or get a #PeerContext
*
return get_peer_ctx (peer);
}
+
/**
* @brief Check whether we have a connection to this @a peer
*
return GNUNET_YES;
}
+
/**
* @brief The closure to #get_rand_peer_iterator.
*/
const struct GNUNET_PeerIdentity *peer;
};
+
/**
* @brief Iterator function for #get_random_peer_from_peermap.
*
return GNUNET_YES;
}
+
/**
* @brief Get a random peer from @a peer_map
*
return ret;
}
+
/**
* @brief Add a given @a peer to valid peers.
*
return ret;
}
+
/**
* @brief Set the peer flag to living and
* call the pending operations on this peer.
struct GNUNET_PeerIdentity *peer;
unsigned int i;
- /* Cancle cadet transmit_handle if still scheduled */
- if (NULL != peer_ctx->transmit_handle)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
- peer_ctx->transmit_handle = NULL;
- }
-
peer = &peer_ctx->peer_id;
- (void) add_valid_peer (peer);
- set_peer_flag (peer_ctx, Peers_ONLINE);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Peer %s is live and valid, calling %i pending operations on it\n",
GNUNET_i2s (peer),
peer_ctx->num_pending_ops);
+ if (NULL != peer_ctx->liveliness_check_pending)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing pending liveliness check for peer %s\n",
+ GNUNET_i2s (&peer_ctx->peer_id));
+ // TODO wait until cadet sets mq->cancel_impl
+ //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
+ GNUNET_free (peer_ctx->liveliness_check_pending);
+ peer_ctx->liveliness_check_pending = NULL;
+ }
+
+ (void) add_valid_peer (peer);
+ set_peer_flag (peer_ctx, Peers_ONLINE);
+
/* Call pending operations */
for (i = 0; i < peer_ctx->num_pending_ops; i++)
{
GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
}
+
/**
* @brief Get the channel of a peer. If not existing, create.
*
get_channel (const struct GNUNET_PeerIdentity *peer)
{
struct PeerContext *peer_ctx;
+ struct GNUNET_HashCode port;
peer_ctx = get_peer_ctx (peer);
if (NULL == peer_ctx->send_channel)
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Trying to establish channel to peer %s\n",
GNUNET_i2s (peer));
+ GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
+ strlen (GNUNET_APPLICATION_PORT_RPS),
+ &port);
peer_ctx->send_channel =
GNUNET_CADET_channel_create (cadet_handle,
peer_ctx->send_channel_flags, /* context */
peer,
- GNUNET_RPS_CADET_PORT,
+ &port,
GNUNET_CADET_OPTION_RELIABLE);
}
GNUNET_assert (NULL != peer_ctx->send_channel);
return peer_ctx->send_channel;
}
+
/**
* Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
*
* If we already have a message queue open to this client,
* simply return it, otherways create one.
- *
+ *
* @param peer the peer to get the mq to
* @return the #GNUNET_MQ_Handle
*/
struct PeerContext *peer_ctx;
peer_ctx = get_peer_ctx (peer);
- GNUNET_assert (NULL == peer_ctx->transmit_handle);
if (NULL == peer_ctx->mq)
{
return peer_ctx->mq;
}
+
/**
- * @brief Callback that is called when a channel was effectively established.
- *
- * This is an implementation of #GNUNET_CONNECTION_TransmitReadyNotify and
- * given to #GNUNET_CADET_notify_transmit_ready_cancel and called when the
- * channel was successfully established.
- *
- * This function type was originally ment to be called to provide the data to
- * be sent. This is called when the connection is ready to queue more data.
- * However we use it to get notified about the successful establishement of a
- * cadet channel.
- *
- * @a buf will be NULL and @a size zero if the
- * connection was closed for writing in the meantime.
+ * @brief This is called in response to the first message we sent as a
+ * liveliness check.
*
- * @param cls closure
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to @a buf
+ * @param cls #PeerContext of peer with pending liveliness check
*/
-//TODO
-static size_t
-cadet_notify_transmit_ready_cb (void *cls, size_t size, void *buf)
+static void
+mq_liveliness_check_successful (void *cls)
{
- struct PeerContext *peer_ctx = (struct PeerContext *) cls;
- // TODO make sure the context is not deleted or the establishing of the
- // channel is cancelled
+ struct PeerContext *peer_ctx = cls;
- peer_ctx->transmit_handle = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Set ->transmit_handle = NULL for peer %s\n",
- GNUNET_i2s (&peer_ctx->peer_id));
-
- if ( (NULL != buf) &&
- (0 != size) )
+ if (NULL != peer_ctx->liveliness_check_pending)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Liveliness check for peer %s was successfull\n",
+ GNUNET_i2s (&peer_ctx->peer_id));
+ GNUNET_free (peer_ctx->liveliness_check_pending);
+ peer_ctx->liveliness_check_pending = NULL;
set_peer_live (peer_ctx);
}
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Problems establishing a connection to peer %s in order to check liveliness\n",
- GNUNET_i2s (&peer_ctx->peer_id));
- // TODO reschedule? cleanup?
- }
- return 0;
}
/**
"Get informed about peer %s getting live\n",
GNUNET_i2s (&peer_ctx->peer_id));
- if (NULL != peer_ctx->transmit_handle)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Already waiting for notification\n");
- return;
- }
- if (NULL != peer_ctx->send_channel)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Already have established channel to peer\n");
- return;
- }
- (void) get_channel (&peer_ctx->peer_id);
- peer_ctx->transmit_handle =
- GNUNET_CADET_notify_transmit_ready (peer_ctx->send_channel,
- GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct GNUNET_MessageHeader),
- cadet_notify_transmit_ready_cb,
- peer_ctx);
- if (NULL == peer_ctx->transmit_handle)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Cadet was not able to queue the request (insufficient memory)\n");
- GNUNET_break (0);
- }
+ struct GNUNET_MQ_Handle *mq;
+ struct GNUNET_MQ_Envelope *ev;
+
+ ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE);
+ peer_ctx->liveliness_check_pending = GNUNET_new (struct PendingMessage);
+ peer_ctx->liveliness_check_pending->ev = ev;
+ peer_ctx->liveliness_check_pending->peer_ctx = peer_ctx;
+ peer_ctx->liveliness_check_pending->type = "Check liveliness";
+ mq = get_mq (&peer_ctx->peer_id);
+ GNUNET_MQ_notify_sent (ev,
+ mq_liveliness_check_successful,
+ peer_ctx);
+ GNUNET_MQ_send (mq, ev);
}
/**
return pending_msg;
}
+
/**
* @brief Remove a pending message from the respective DLL
*
GNUNET_free (pending_msg);
}
+
/**
* @brief Check whether function of type #PeerOp was already scheduled
*
return GNUNET_NO;
}
+
/**
* Iterator over hash map entries. Deletes all contexts of peers.
*
return GNUNET_YES;
}
+
/**
* @brief This is called once a message is sent.
*
remove_pending_message (pending_msg);
}
+
/**
* @brief Iterator function for #store_valid_peers.
*
return GNUNET_YES;
}
+
/**
* @brief Store the peers currently in #valid_peers to disk.
*/
GNUNET_CONTAINER_multipeermap_size (valid_peers));
}
+
/**
* @brief Convert string representation of peer id to peer id.
*
return peer;
}
+
/**
* @brief Restore the peers on disk to #valid_peers.
*/
char *buf;
ssize_t size_read;
char *iter_buf;
- const char *str_repr;
+ char *str_repr;
const struct GNUNET_PeerIdentity *peer;
if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
buf = GNUNET_malloc (file_size);
size_read = GNUNET_DISK_file_read (fh, buf, file_size);
GNUNET_assert (size_read == file_size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Restoring %" PRIu32 " peers from file `%s'\n",
+ num_peers,
+ filename_valid_peers);
for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
{
str_repr = GNUNET_strndup (iter_buf, 53);
peer = s2i_full (str_repr);
+ GNUNET_free (str_repr);
add_valid_peer (peer);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Restored valid peer %s from disk\n",
GNUNET_i2s_full (peer));
}
+ iter_buf = NULL;
+ GNUNET_free (buf);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
num_peers,
GNUNET_CONTAINER_multipeermap_size (valid_peers));
- GNUNET_assert (num_peers == GNUNET_CONTAINER_multipeermap_size (valid_peers));
+ if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Number of restored peers does not match file size. Have probably duplicates.\n");
+ }
GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Restored %u valid peers from disk\n",
- num_peers);
+ GNUNET_CONTAINER_multipeermap_size (valid_peers));
}
+
/**
* @brief Initialise storage of peers
*
restore_valid_peers ();
}
+
/**
* @brief Delete storage of peers that was created with #Peers_initialise ()
*/
return ret;
}
+
/**
* @brief Add peer to known peers.
*
return ret;
}
+
/**
- * @brief Remove unecessary data
+ * @brief Check if peer is removable.
*
- * If the other peer is not intending to send messages, we have messages pending
- * to be sent to this peer and we are not waiting for a reply, remove the
- * information about it (its #PeerContext).
+ * Check if
+ * - a recv channel exists
+ * - there are pending messages
+ * - there is no pending pull reply
*
- * @param peer the peer to clean
- * @return #GNUNET_YES if peer was removed
- * #GNUNET_NO otherwise
+ * @param peer the peer in question
+ * @return #GNUNET_YES if peer is removable
+ * #GNUNET_NO if peer is NOT removable
+ * #GNUNET_SYSERR if peer is not known
*/
int
-Peers_clean_peer (const struct GNUNET_PeerIdentity *peer)
+Peers_check_removable (const struct GNUNET_PeerIdentity *peer)
{
struct PeerContext *peer_ctx;
- // TODO actually remove unnecessary data
-
- if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
+ if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
{
- return GNUNET_NO;
+ return GNUNET_SYSERR;
}
peer_ctx = get_peer_ctx (peer);
{
return GNUNET_NO;
}
- Peers_remove_peer (peer);
return GNUNET_YES;
}
+
/**
* @brief Remove peer
- *
+ *
* @param peer the peer to clean
* @return #GNUNET_YES if peer was removed
* #GNUNET_NO otherwise
{
struct PeerContext *peer_ctx;
- if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
+ if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
{
return GNUNET_NO;
}
Peers_unset_peer_flag (peer, Peers_ONLINE);
GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
- // TODO delete struct GNUNET_TRANSPORT_TransmitHandle *transmit_handle
- /* Cancle messages that have not been sent yet */
while (NULL != peer_ctx->pending_messages_head)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
}
/* If we are still waiting for notification whether this peer is live
* cancel the according task */
- if (NULL != peer_ctx->transmit_handle)
+ if (NULL != peer_ctx->liveliness_check_pending)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to cancle transmit_handle for peer %s\n",
+ "Removing pending liveliness check for peer %s\n",
GNUNET_i2s (&peer_ctx->peer_id));
- GNUNET_CADET_notify_transmit_ready_cancel (peer_ctx->transmit_handle);
- peer_ctx->transmit_handle = NULL;
+ // TODO wait until cadet sets mq->cancel_impl
+ //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
+ GNUNET_free (peer_ctx->liveliness_check_pending);
+ peer_ctx->liveliness_check_pending = NULL;
}
if (NULL != peer_ctx->send_channel)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying send channel\n");
GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
peer_ctx->send_channel = NULL;
}
if (NULL != peer_ctx->recv_channel)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying recv channel\n");
GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
peer_ctx->recv_channel = NULL;
}
return GNUNET_YES;
}
+
/**
* @brief set flags on a given peer.
*
set_peer_flag (peer_ctx, flags);
}
+
/**
* @brief unset flags on a given peer.
*
unset_peer_flag (peer_ctx, flags);
}
+
/**
* @brief Check whether flags on a peer are set.
*
set_channel_flag (channel_flags, flags);
}
+
/**
* @brief unset flags on a given channel.
*
unset_channel_flag (channel_flags, flags);
}
+
/**
* @brief Check whether flags on a channel are set.
*
return check_channel_flag_set (channel_flags, flags);
}
+
/**
* @brief Check whether we have information about the given peer.
*
return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
}
+
/**
* @brief Check whether @a peer is actually a peer.
*
return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
}
+
/**
* @brief Indicate that we want to send to the other peer
*
(void) get_channel (peer);
}
+
/**
* @brief Check whether other peer has the intention to send/opened channel
* towars us
return GNUNET_NO;
}
+
/**
* Handle the channel a peer opens to us.
*
Peers_handle_inbound_channel (void *cls,
struct GNUNET_CADET_Channel *channel,
const struct GNUNET_PeerIdentity *initiator,
- uint32_t port,
+ const struct GNUNET_HashCode *port,
enum GNUNET_CADET_ChannelOption options)
{
struct PeerContext *peer_ctx;
return peer_ctx->recv_channel_flags;
}
+
/**
* @brief Check whether a sending channel towards the given peer exists
*
return GNUNET_YES;
}
+
/**
* @brief check whether the given channel is the sending channel of the given
* peer
return GNUNET_NO;
}
+
/**
* @brief Destroy the send channel of a peer e.g. stop indicating a sending
* intention to another peer