* Total messages pending for this tunnels, payload or not.
*/
unsigned int pending_messages;
+
+ /**
+ * If the tunnel is empty, destoy it.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier delayed_destroy;
};
*/
GNUNET_SCHEDULER_TaskIdentifier regex_announce_task;
+ /**
+ * Tmp store for partially retrieved regex.
+ */
+ char *partial_regex;
+
};
{
struct GNUNET_MESH_PeerControl pc;
+ if (NULL == t->owner || GNUNET_YES == t->destroy)
+ return;
+
pc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
pc.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
pc.tunnel_id = htonl (t->local_tid);
* valid.
*
* @param t The tunnel whose peers to notify.
+ * @param send_back Do we need to notify our parent node?
*/
static void
-tunnel_send_destroy (struct MeshTunnel *t)
+tunnel_send_destroy (struct MeshTunnel *t, int send_back)
{
struct GNUNET_MESH_TunnelDestroy msg;
+ struct GNUNET_PeerIdentity id;
+ GNUNET_PEER_Id parent;
+
+ if (tree_count_children(t->tree) > 0)
+ {
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);
+ GNUNET_PEER_resolve (t->id.oid, &msg.oid);
+ msg.tid = htonl (t->id.tid);
+ tunnel_send_multicast (t, &msg.header);
+ }
+ parent = tree_get_predecessor(t->tree);
+ if (GNUNET_NO == send_back || 0 == parent)
+ return;
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);
- GNUNET_PEER_resolve (t->id.oid, &msg.oid);
- msg.tid = htonl (t->id.tid);
- tunnel_send_multicast (t, &msg.header);
+ send_prebuilt_message(&msg.header, &id, t);
}
}
}
- if (t->nclients > 0)
- {
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t))
- {
- GNUNET_break (0);
- r = GNUNET_SYSERR;
- }
- GNUNET_free (t->clients);
- GNUNET_free (t->clients_fc);
- }
+ (void) GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t);
+ GNUNET_free_non_null (t->clients);
+ GNUNET_free_non_null (t->clients_fc);
if (NULL != t->peers)
{
return r;
}
+#define TUNNEL_DESTROY_EMPTY_TIME GNUNET_TIME_UNIT_MILLISECONDS
+
+/**
+ * Tunnel is empty: destroy it.
+ *
+ * @param cls Closure (Tunnel).
+ * @param tc TaskContext.
+ */
+static void
+tunnel_destroy_empty_delayed (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct MeshTunnel *t = cls;
+
+ t->delayed_destroy = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ if (0 != t->nclients ||
+ 0 != tree_count_children (t->tree))
+ return;
+
+ #if MESH_DEBUG
+ {
+ struct GNUNET_PeerIdentity id;
+
+ GNUNET_PEER_resolve (t->id.oid, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "executing destruction of empty tunnel %s [%X]\n",
+ GNUNET_i2s (&id), t->id.tid);
+ }
+ #endif
+
+ tunnel_destroy (t);
+}
+
+
+/**
+ * Schedule tunnel destruction if is empty and no new traffic comes in a time.
+ *
+ * @param t Tunnel to destroy if empty.
+ */
+static void
+tunnel_destroy_empty (struct MeshTunnel *t)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != t->delayed_destroy ||
+ 0 != t->nclients ||
+ 0 != tree_count_children (t->tree))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%u %u %u\n",
+ t->delayed_destroy, t->nclients, tree_count_children(t->tree));
+ return;
+ }
+
+ #if MESH_DEBUG
+ {
+ struct GNUNET_PeerIdentity id;
+
+ GNUNET_PEER_resolve (t->id.oid, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "scheduling destruction of empty tunnel %s [%X]\n",
+ GNUNET_i2s (&id), t->id.tid);
+ }
+ #endif
+
+ t->delayed_destroy =
+ GNUNET_SCHEDULER_add_delayed (TUNNEL_DESTROY_EMPTY_TIME,
+ &tunnel_destroy_empty_delayed,
+ t);
+}
+
/**
* Create a new tunnel
* @return GNUNET_OK, keep iterating.
*/
static int
-tunnel_destroy_iterator (void *cls, const struct GNUNET_HashCode * key, void *value)
+tunnel_destroy_iterator (void *cls,
+ const struct GNUNET_HashCode * key,
+ void *value)
{
struct MeshTunnel *t = value;
struct MeshClient *c = cls;
- send_client_tunnel_disconnect(t, c);
+ send_client_tunnel_disconnect (t, c);
if (c != t->owner)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client %u is destination, keeping the tunnel alive.\n", c->id);
- tunnel_delete_client(t, c);
- client_delete_tunnel(c, t);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %u is destination.\n", c->id);
+ tunnel_delete_client (t, c);
+ client_delete_tunnel (c, t);
+ tunnel_destroy_empty (t);
return GNUNET_OK;
}
- tunnel_send_destroy(t);
+ tunnel_send_destroy (t, GNUNET_YES);
t->owner = NULL;
t->destroy = GNUNET_YES;
struct GNUNET_MESH_TunnelDestroy *msg;
struct MeshTunnel *t;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got a TUNNEL DESTROY packet from %s\n", GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_TunnelDestroy *) message;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for tunnel %s [%u]\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got a TUNNEL DESTROY packet from %s\n",
+ GNUNET_i2s (peer));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " for tunnel %s [%u]\n",
GNUNET_i2s (&msg->oid), ntohl (msg->tid));
t = tunnel_get (&msg->oid, ntohl (msg->tid));
if (NULL == t)
* destroyed the tunnel and retransmitted to children.
* Safe to ignore.
*/
- GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# control on unknown tunnel",
+ 1, GNUNET_NO);
return GNUNET_OK;
}
if (t->id.oid == myid)
t->local_tid, t->local_tid_dest);
send_clients_tunnel_destroy (t);
}
- tunnel_send_destroy (t);
+ tunnel_send_destroy (t, GNUNET_YES);
t->destroy = GNUNET_YES;
// TODO: add timeout to destroy the tunnel anyway
return GNUNET_OK;
{
/* TODO notify that we dont know this tunnel (whom)? */
GNUNET_STATISTICS_update (stats, "# data on unknown tunnel", 1, GNUNET_NO);
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received to_origin with PID %u on unknown tunnel %s [%u]\n",
pid, GNUNET_i2s (&msg->oid), ntohl (msg->tid));
return GNUNET_OK;
predecessor = tree_get_predecessor (t->tree);
if (0 == predecessor)
{
+ if (GNUNET_YES == t->destroy)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "to orig received on a dying tunnel %s [%X]\n",
+ GNUNET_i2s (&msg->oid), ntohl(msg->tid));
+ return GNUNET_OK;
+ }
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"unknown to origin at %s\n",
GNUNET_i2s (&my_full_id));
return;
}
-// return; uncomment for regex_profiler
c = clients;
while (NULL != c)
{
struct MeshClient *c;
char *regex;
size_t len;
+ size_t offset;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "announce regex started\n");
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
msg = (const struct GNUNET_MESH_RegexAnnounce *) message;
+
len = ntohs (message->size) - sizeof(struct GNUNET_MESH_RegexAnnounce);
- regex = GNUNET_malloc (len + 1);
- memcpy (regex, &msg[1], len);
- regex[len] = '\0';
+ if (NULL != c->partial_regex)
+ {
+ regex = c->partial_regex;
+ offset = strlen (c->partial_regex);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " continuation, already have %u bytes\n",
+ offset);
+ }
+ else
+ {
+ regex = NULL;
+ offset = 0;
+ }
+
+ regex = GNUNET_realloc (regex, offset + len + 1);
+ memcpy (®ex[offset], &msg[1], len);
+ regex[offset + len] = '\0';
+ if (0 == ntohs (msg->last))
+ {
+ c->partial_regex = regex;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " not ended, stored %u bytes for later\n",
+ len);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
rd.regex = regex;
rd.compression = ntohs (msg->compression_characters);
rd.dfa = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regex %s\n", regex);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " cm %u\n", ntohs(rd.compression));
GNUNET_array_append (c->regexes, c->n_regex, rd);
+ c->partial_regex = NULL;
if (GNUNET_SCHEDULER_NO_TASK == c->regex_announce_task)
{
c->regex_announce_task = GNUNET_SCHEDULER_add_now(&announce_regex, c);
if (c != t->owner || tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
{
client_ignore_tunnel (c, t);
-#if 0
- // TODO: when to destroy incoming tunnel?
- if (t->nclients == 0)
- {
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels,
- &hash, t));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (t->peers,
- &my_full_id.hashPubKey,
- t));
- }
-#endif
+ tunnel_destroy_empty (t);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
/* Don't try to ACK the client about the tunnel_destroy multicast packet */
t->owner = NULL;
- tunnel_send_destroy (t);
+ tunnel_send_destroy (t, GNUNET_YES);
t->destroy = GNUNET_YES;
// The tunnel will be destroyed when the last message is transmitted.
GNUNET_SERVER_receive_done (client, GNUNET_OK);