/*
This file is part of GNUnet.
- (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2009, 2010, 2011 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
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
#include "gnunet_transport_service.h"
#include "gnunet-service-core.h"
#include "gnunet-service-core_clients.h"
+#include "gnunet-service-core_neighbours.h"
#include "gnunet-service-core_sessions.h"
#include "gnunet-service-core_typemap.h"
#include "core.h"
*/
static void
send_to_client (struct GSC_Client *client,
- const struct GNUNET_MessageHeader *msg, int can_drop)
+ const struct GNUNET_MessageHeader *msg,
+ int can_drop)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Preparing to send %u bytes of message of type %u to client.\n",
{
unsigned int i;
- if (c->tcnt == 0)
- return GNUNET_YES; /* peer without handlers matches ALL */
+ if (c->tcnt == 0 && c->options != 0)
+ return GNUNET_YES; /* peer without handlers and inbound/outbond
+ callbacks matches ALL */
for (i = 0; i < c->tcnt; i++)
if (type == c->types[i])
return GNUNET_YES;
*/
static void
send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
- const struct GNUNET_MessageHeader *msg, int can_drop,
- uint32_t options, uint16_t type)
+ const struct GNUNET_MessageHeader *msg,
+ int can_drop,
+ uint32_t options,
+ uint16_t type)
{
struct GSC_Client *c;
int tm;
/**
- * Handle CORE_INIT request.
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
*
* @param cls unused
- * @param client new client that sent INIT
+ * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
* @param message the `struct InitMessage` (presumably)
*/
static void
/**
- * Handle CORE_SEND_REQUEST message.
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
*
* @param cls unused
- * @param client new client that sent CORE_SEND_REQUEST
+ * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
* @param message the `struct SendMessageRequest` (presumably)
*/
static void
req = (const struct SendMessageRequest *) message;
c = find_client (client);
- if (c == NULL)
+ if (NULL == c)
{
/* client did not send INIT first! */
GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ GNUNET_SERVER_receive_done (client,
+ GNUNET_SYSERR);
return;
}
- if (c->requests == NULL)
- c->requests = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
+ if (NULL == c->requests)
+ c->requests = GNUNET_CONTAINER_multipeermap_create (16,
+ GNUNET_NO);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Client asked for transmission to `%s'\n",
GNUNET_i2s (&req->peer));
is_loopback =
(0 ==
- memcmp (&req->peer, &GSC_my_identity,
+ memcmp (&req->peer,
+ &GSC_my_identity,
sizeof (struct GNUNET_PeerIdentity)));
- if ((!is_loopback) &&
+ if ((! is_loopback) &&
(GNUNET_YES !=
GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
&req->peer)))
gettext_noop
("# send requests dropped (disconnected)"), 1,
GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ GNUNET_SERVER_receive_done (client,
+ GNUNET_OK);
return;
}
- car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
+ car = GNUNET_CONTAINER_multipeermap_get (c->requests,
+ &req->peer);
if (NULL == car)
{
/* create new entry */
}
else
{
+ /* dequeue and recycle memory from pending request, there can only
+ be at most one per client and peer */
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop
+ ("# dequeuing CAR (duplicate request)"), 1,
+ GNUNET_NO);
GSC_SESSIONS_dequeue_request (car);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission request to `%s' was a duplicate!\n",
+ GNUNET_i2s (&req->peer));
}
car->target = req->peer;
+ car->received_time = GNUNET_TIME_absolute_get ();
car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
car->msize = ntohs (req->size);
/**
- * Handle CORE_SEND request.
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
*
* @param cls unused
* @param client the client issuing the request
struct GSC_Client *c;
struct TokenizerContext tc;
uint16_t msize;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_TIME_Relative overdue;
msize = ntohs (message->size);
- if (msize <
- sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
+ if (msize < sizeof (struct SendMessage))
{
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
- tc.car =
- GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
+ tc.car
+ = GNUNET_CONTAINER_multipeermap_get (c->requests,
+ &sm->peer);
if (NULL == tc.car)
{
/* Must have been that we first approved the request, then got disconnected
gettext_noop
("# messages discarded (session disconnected)"),
1, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ GNUNET_SERVER_receive_done (client,
+ GNUNET_OK);
return;
}
+ delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
+ overdue = GNUNET_TIME_absolute_get_duration (tc.car->deadline);
+ tc.cork = ntohl (sm->cork);
+ tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
+ if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client waited %s for transmission of %u bytes to `%s'%s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ msize,
+ GNUNET_i2s (&sm->peer),
+ tc.cork ? "" : " (corked)");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client waited %s for transmission of %u bytes to `%s'%s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ msize,
+ GNUNET_i2s (&sm->peer),
+ tc.cork ? "" : " (corked)");
+
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multipeermap_remove (c->requests,
&sm->peer,
tc.car));
- tc.cork = ntohl (sm->cork);
- tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client asked for transmission of %u bytes to `%s' %s\n",
- msize,
- GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
GNUNET_SERVER_mst_receive (client_mst, &tc,
- (const char *) &sm[1], msize,
- GNUNET_YES, GNUNET_NO);
- if (0 !=
- memcmp (&tc.car->target, &GSC_my_identity,
- sizeof (struct GNUNET_PeerIdentity)))
- GSC_SESSIONS_dequeue_request (tc.car);
+ (const char *) &sm[1],
+ msize,
+ GNUNET_YES,
+ GNUNET_NO);
+ GSC_SESSIONS_dequeue_request (tc.car);
GNUNET_free (tc.car);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ GNUNET_SERVER_receive_done (client,
+ GNUNET_OK);
}
* @param message the actual message
*/
static int
-client_tokenizer_callback (void *cls, void *client,
+client_tokenizer_callback (void *cls,
+ void *client,
const struct GNUNET_MessageHeader *message)
{
struct TokenizerContext *tc = client;
GNUNET_snprintf (buf, sizeof (buf),
gettext_noop ("# bytes of messages of type %u received"),
(unsigned int) ntohs (message->type));
- GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
+ GNUNET_STATISTICS_update (GSC_stats,
+ buf,
+ ntohs (message->size),
+ GNUNET_NO);
if (0 ==
- memcmp (&car->target, &GSC_my_identity,
+ memcmp (&car->target,
+ &GSC_my_identity,
sizeof (struct GNUNET_PeerIdentity)))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
else
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Delivering message of type %u to %s\n",
- ntohs (message->type),
+ "Delivering message of type %u and size %u to %s\n",
+ ntohs (message->type), ntohs (message->size),
GNUNET_i2s (&car->target));
GSC_CLIENTS_deliver_message (&car->target, message,
ntohs (message->size),
if (NULL == client)
return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client %p has disconnected from core service.\n", client);
+ "Client %p has disconnected from core service.\n",
+ client);
c = find_client (client);
if (c == NULL)
return; /* client never sent INIT */
{
struct GSC_Client *c;
struct SendMessageReady smr;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_TIME_Relative left;
c = car->client_handle;
if (GNUNET_YES !=
{
/* connection has gone down since, drop request */
GNUNET_assert (0 !=
- memcmp (&car->target, &GSC_my_identity,
+ memcmp (&car->target,
+ &GSC_my_identity,
sizeof (struct GNUNET_PeerIdentity)));
GSC_SESSIONS_dequeue_request (car);
- GSC_CLIENTS_reject_request (car);
+ GSC_CLIENTS_reject_request (car,
+ GNUNET_NO);
return;
}
+ delay = GNUNET_TIME_absolute_get_duration (car->received_time);
+ left = GNUNET_TIME_absolute_get_duration (car->deadline);
+ if (left.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ GNUNET_i2s (&car->target),
+ (0 == left.rel_value_us)
+ ? " (past deadline)"
+ : "",
+ car->priority);
smr.header.size = htons (sizeof (struct SendMessageReady));
smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
smr.size = htons (car->msize);
/**
- * Tell a client that we will never be ready to receive the
- * given message in time (disconnect or timeout).
+ * We will never be ready to transmit the given message in (disconnect
+ * or invalid request). Frees resources associated with @a car. We
+ * don't explicitly tell the client, he'll learn with the disconnect
+ * (or violated the protocol).
*
* @param car request that now permanently failed; the
* responsibility for the handle is now returned
* to CLIENTS (SESSIONS is done with it).
+ * @param drop_client #GNUNET_YES if the client violated the protocol
+ * and we should thus drop the connection
*/
void
-GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
+GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
+ int drop_client)
{
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multipeermap_remove (car->
client_handle->requests,
&car->target,
car));
+ if (GNUNET_YES == drop_client)
+ GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
GNUNET_free (car);
}
(0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
return; /* no client cares about this message notification */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service passes message from `%4s' of type %u to client.\n",
- GNUNET_i2s (sender), (unsigned int) ntohs (msg->type));
+ "Core service passes message from `%s' of type %u to client.\n",
+ GNUNET_i2s (sender),
+ (unsigned int) ntohs (msg->type));
GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
ntm = (struct NotifyTrafficMessage *) buf;
ntm->header.size = htons (size);
else
ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
ntm->peer = *sender;
- memcpy (&ntm[1], msg, msize);
- send_to_all_clients (sender, &ntm->header, GNUNET_YES, options,
+ memcpy (&ntm[1],
+ msg,
+ msize);
+ send_to_all_clients (sender,
+ &ntm->header,
+ GNUNET_YES,
+ options,
ntohs (msg->type));
}