#define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
+#define DEBUG_ACK GNUNET_YES
/******************************************************************************/
/************************ DATA STRUCTURES ****************************/
* Task for trying to reconnect.
*/
GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+#if DEBUG_ACK
+ unsigned int acks_sent;
+ unsigned int acks_recv;
+#endif
};
* Last pid received from the service.
*/
uint32_t last_recv_pid;
+
+ /**
+ * Which ACK value have we last sent to the service?
+ */
+ uint32_t max_recv_pid;
};
}
t->max_send_pid = INITIAL_WINDOW_SIZE - 1;
t->last_recv_pid = (uint32_t) -1;
+ t->buffering = GNUNET_YES;
return t;
}
/**
- * Add a transmit handle to the transmission queue by priority and set the
+ * Add a transmit handle to the transmission queue and set the
* timeout if needed.
*
* @param h mesh handle with the queue head and tail
add_to_queue (struct GNUNET_MESH_Handle *h,
struct GNUNET_MESH_TransmitHandle *th)
{
- struct GNUNET_MESH_TransmitHandle *p;
-
- p = h->th_head;
- while ((NULL != p))
- p = p->next;
- if (NULL == p)
- p = h->th_tail;
- else
- p = p->prev;
- GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th);
+ GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th);
if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value)
return;
th->timeout_task =
send_ack (struct GNUNET_MESH_Handle *h, struct GNUNET_MESH_Tunnel *t)
{
struct GNUNET_MESH_LocalAck msg;
+ uint32_t delta;
+ delta = t->max_recv_pid - t->last_recv_pid;
+ if (delta > ACK_THRESHOLD)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Not sending ACK on tunnel %X: ACK: %u, PID: %u, buffer %u\n",
+ t->tid, t->max_recv_pid, t->last_recv_pid, delta);
+ return;
+ }
+ if (GNUNET_YES == t->buffering)
+ t->max_recv_pid = t->last_recv_pid + INITIAL_WINDOW_SIZE;
+ else
+ t->max_recv_pid = t->last_recv_pid + 1;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Sending ACK on tunnel %X: %u\n",
- t->tid, t->last_recv_pid + INITIAL_WINDOW_SIZE);
+ t->tid, t->max_recv_pid);
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
msg.header.size = htons (sizeof (msg));
msg.tunnel_id = htonl (t->tid);
- msg.max_pid = htonl (t->last_recv_pid + INITIAL_WINDOW_SIZE);
+ msg.max_pid = htonl (t->max_recv_pid);
+
+#if DEBUG_ACK
+ t->mesh->acks_sent++;
+#endif
send_packet (h, &msg.header, t);
return;
GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
GNUNET_TIME_relative_multiply
(h->reconnect_time, 2));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Next retry in %sms\n",
- GNUNET_TIME_relative_to_string (h->reconnect_time));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Next retry in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (h->reconnect_time,
+ GNUNET_NO));
GNUNET_break (0);
return GNUNET_NO;
}
GNUNET_PEER_change_rc (t->owner, 1);
t->mesh = h;
t->tid = tid;
+ if ((msg->opt & MESH_TUNNEL_OPT_NOBUFFER) != 0)
+ t->buffering = GNUNET_NO;
+ else
+ t->buffering = GNUNET_YES;
+ if ((msg->opt & MESH_TUNNEL_OPT_SPEED_MIN) != 0)
+ t->speed_min = GNUNET_YES;
atsi.type = 0;
atsi.value = 0;
LOG (GNUNET_ERROR_TYPE_DEBUG, " created tunnel %p\n", t);
LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n");
return GNUNET_YES;
}
- if (GNUNET_YES ==
- GMC_is_pid_bigger(pid, t->last_recv_pid + INITIAL_WINDOW_SIZE))
+ if (GNUNET_YES ==
+ GMC_is_pid_bigger(pid, t->max_recv_pid))
{
GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, " unauthorized message!\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ " unauthorized message! (%u, max %u)\n",
+ pid, t->max_recv_pid);
// FIXME fc what now? accept? reject?
return GNUNET_YES;
}
t->last_recv_pid = pid;
type = ntohs (payload->type);
+ send_ack (h, t);
for (i = 0; i < h->n_handlers; i++)
{
handler = &h->message_handlers[i];
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"callback completed successfully\n");
- send_ack (h, t);
}
}
}
uint32_t ack;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
+ h->acks_recv++;
msg = (struct GNUNET_MESH_LocalAck *) message;
t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
to.tid = htonl (t->tid);
to.pid = htonl (t->next_send_pid);
+ to.ttl = 0;
memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
memcpy (cbuf, &to, sizeof (to));
uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
uc.tid = htonl (t->tid);
uc.pid = htonl (t->next_send_pid);
+ uc.ttl = 0;
memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
GNUNET_PEER_resolve (th->target, &uc.destination);
memcpy (cbuf, &uc, sizeof (uc));
LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH DISCONNECT\n");
+#if DEBUG_ACK
+ LOG (GNUNET_ERROR_TYPE_INFO, "Sent %d ACKs\n", handle->acks_sent);
+ LOG (GNUNET_ERROR_TYPE_INFO, "Recv %d ACKs\n\n", handle->acks_recv);
+#endif
+
t = handle->tunnels_head;
while (NULL != t)
{
* (for instance 'gnunet://'). If you put a variable part in there (*, +. ()),
* all matching strings will be stored in the DHT.
*
- * @param h handle to mesh.
- * @param regex string with the regular expression describing local services.
+ * @param h Handle to mesh.
+ * @param regex String with the regular expression describing local services.
+ * @param compression_characters How many characters can be assigned to one
+ * edge of the graph. The bigger the variability
+ * of the data, the smaller this parameter should
+ * be (down to 1).
+ * For maximum compression, use strlen (regex)
+ * or 0 (special value). Use with care!
*/
void
GNUNET_MESH_announce_regex (struct GNUNET_MESH_Handle *h,
- const char *regex)
+ const char *regex,
+ unsigned int compression_characters)
{
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_MESH_RegexAnnounce *msg;
size_t len;
size_t msgsize;
len = strlen (regex);
- msgsize = sizeof(struct GNUNET_MessageHeader) + len;
+ msgsize = sizeof(struct GNUNET_MESH_RegexAnnounce) + len;
GNUNET_assert (UINT16_MAX > msgsize);
{
char buffer[msgsize];
- msg = (struct GNUNET_MessageHeader *) buffer;
- msg->size = htons (msgsize);
- msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ANNOUNCE_REGEX);
+ msg = (struct GNUNET_MESH_RegexAnnounce *) buffer;
+ msg->header.size = htons (msgsize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ANNOUNCE_REGEX);
+ msg->compression_characters = htons (compression_characters);
memcpy (&msg[1], regex, len);
send_packet(h, msg, NULL);
h = tunnel->mesh;
tunnel->buffering = buffer;
+ tunnel->max_send_pid = tunnel->next_send_pid;
if (GNUNET_YES == buffer)
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_BUFFER);