/*
This file is part of GNUnet.
- Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2010-2015 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
};
+/**
+ * Closure for #handle_send_transmit_continuation()
+ */
+struct SendTransmitContinuationContext
+{
+ /**
+ * Client that made the request.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Peer that was the target.
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * At what time did we receive the message?
+ */
+ struct GNUNET_TIME_Absolute send_time;
+
+ /**
+ * Unique ID, for logging.
+ */
+ unsigned long long uuid;
+
+ /**
+ * Set to #GNUNET_YES if the connection for @e target goes
+ * down and we thus must no longer send the
+ * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
+ */
+ int down;
+};
+
+
/**
* Head of linked list of all clients to this service.
*/
*/
static struct TransportClient *clients_tail;
+/**
+ * Map of peer identities to active send transmit continuation
+ * contexts. Used to flag contexts as 'dead' when a connection goes
+ * down. Values are of type `struct SendTransmitContinuationContext
+ * *`.
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
+
/**
* Head of linked list of all pending address iterations
*/
}
-/**
- * Closure for #handle_send_transmit_continuation()
- */
-struct SendTransmitContinuationContext
-{
- /**
- * Client that made the request.
- */
- struct GNUNET_SERVER_Client *client;
-
- /**
- * Peer that was the target.
- */
- struct GNUNET_PeerIdentity target;
-
- /**
- * At what time did we receive the message?
- */
- struct GNUNET_TIME_Absolute send_time;
-};
-
-
/**
* Function called after the transmission is done. Notify the client that it is
* OK to send the next message.
success,
(NULL != addr) ? addr->transport_name : "%");
- if (GST_neighbours_test_connected (&stcc->target))
+ if (GNUNET_NO == stcc->down)
{
/* Only send confirmation if we are still connected */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending SEND_OK for transmission request %llu\n",
+ stcc->uuid);
send_ok_msg.header.size = htons (sizeof (send_ok_msg));
send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
send_ok_msg.bytes_msg = htonl (bytes_payload);
GNUNET_NO);
}
GNUNET_SERVER_client_drop (stcc->client);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multipeermap_remove (active_stccs,
+ &stcc->target,
+ stcc));
GNUNET_free (stcc);
}
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
+ static unsigned long long uuid_gen;
const struct OutboundMessage *obm;
const struct GNUNET_MessageHeader *obmm;
struct SendTransmitContinuationContext *stcc;
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received SEND request for `%s' and first message of type %u and total size %u\n",
+ "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
+ uuid_gen,
GNUNET_i2s (&obm->peer),
ntohs (obmm->type),
msize);
stcc->target = obm->peer;
stcc->client = client;
stcc->send_time = GNUNET_TIME_absolute_get ();
+ stcc->uuid = uuid_gen++;
+ (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
+ &stcc->target,
+ stcc,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
GNUNET_SERVER_client_keep (client);
GST_manipulation_send (&obm->peer,
obmm,
}
-/**
- * Handle request connect message
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-clients_handle_request_connect (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct TransportRequestConnectMessage *trcm;
-
- trcm = (const struct TransportRequestConnectMessage *) message;
- GNUNET_break (0 == ntohl (trcm->reserved));
- GNUNET_STATISTICS_update (GST_stats,
- gettext_noop
- ("# REQUEST CONNECT messages received"), 1,
- GNUNET_NO);
- if (0 == memcmp (&trcm->peer,
- &GST_my_identity,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client,
- GNUNET_OK);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received a request connect message for peer `%s'\n",
- GNUNET_i2s (&trcm->peer));
- GST_neighbours_try_connect (&trcm->peer);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handle request disconnect message
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-clients_handle_request_disconnect (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct TransportRequestDisconnectMessage *trdm;
-
- trdm = (const struct TransportRequestDisconnectMessage *) message;
- GNUNET_break (0 == ntohl (trdm->reserved));
- GNUNET_STATISTICS_update (GST_stats,
- gettext_noop
- ("# REQUEST DISCONNECT messages received"), 1,
- GNUNET_NO);
- if (0 == memcmp (&trdm->peer,
- &GST_my_identity,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received a request disconnect message for peer `%s'\n",
- GNUNET_i2s (&trdm->peer));
- (void) GST_neighbours_force_disconnect (&trdm->peer);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
/**
* Take the given address and append it to the set of results sent back to
* the client. This function may be called serveral times for a single
GNUNET_MESSAGE_TYPE_HELLO, 0},
{&clients_handle_send, NULL,
GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
- {&clients_handle_request_connect, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
- sizeof (struct TransportRequestConnectMessage)},
- {&clients_handle_request_disconnect, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_DISCONNECT,
- sizeof (struct TransportRequestDisconnectMessage)},
{&clients_handle_address_to_string, NULL,
GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
{&clients_handle_monitor_peers, NULL,
sizeof (struct GNUNET_MessageHeader) },
{NULL, NULL, 0, 0}
};
+ active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
+ GNUNET_YES);
peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
val_nc = GNUNET_SERVER_notification_context_create (server, 0);
plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
GNUNET_SERVER_notification_context_destroy (plugin_nc);
plugin_nc = NULL;
}
+ GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
+ active_stccs = NULL;
}
}
+/**
+ * Mark the peer as down so we don't call the continuation
+ * context in the future.
+ *
+ * @param cls NULL
+ * @param peer peer that got disconnected
+ * @param value a `struct SendTransmitContinuationContext` to mark
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+mark_peer_down (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct SendTransmitContinuationContext *stcc = value;
+
+ stcc->down = GNUNET_YES;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Notify all clients about a disconnect, and cancel
+ * pending SEND_OK messages for this peer.
+ *
+ * @param peer peer that disconnected
+ */
+void
+GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
+{
+ struct DisconnectInfoMessage disconnect_msg;
+
+ GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
+ peer,
+ &mark_peer_down,
+ NULL);
+ disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
+ disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
+ disconnect_msg.reserved = htonl (0);
+ disconnect_msg.peer = *peer;
+ GST_clients_broadcast (&disconnect_msg.header,
+ GNUNET_NO);
+
+}
+
+
/* end of file gnunet-service-transport_clients.c */