*/
struct IPv4HttpAddress
{
+ /**
+ * Linked list next
+ */
+ struct IPv4HttpAddress * next;
+
+ /**
+ * Linked list previous
+ */
+ struct IPv4HttpAddress * prev;
+
/**
* IPv4 address, in network byte order.
*/
*/
struct IPv6HttpAddress
{
+ /**
+ * Linked list next
+ */
+ struct IPv6HttpAddress * next;
+
+ /**
+ * Linked list previous
+ */
+ struct IPv6HttpAddress * prev;
+
/**
* IPv6 address.
*/
* Last session used to send data
*/
struct Session * last_session;
+
+ /**
+ * The task resetting inbound quota delay
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reset_task;
+
+ /**
+ * Delay from transport service inbound quota tracker when to receive data again
+ */
+ struct GNUNET_TIME_Relative delay;
};
*/
CURLM * multi_handle;
+ /**
+ * ipv4 DLL head
+ */
+ struct IPv4HttpAddress * ipv4_addr_head;
+
+ /**
+ * ipv4 DLL tail
+ */
+ struct IPv4HttpAddress * ipv4_addr_tail;
+
+ /**
+ * ipv6 DLL head
+ */
+ struct IPv6HttpAddress * ipv6_addr_head;
+
+ /**
+ * ipv6 DLL tail
+ */
+ struct IPv6HttpAddress * ipv6_addr_tail;
+
/**
* Our ASCII encoded, hashed peer identity
* This string is used to distinguish between connections and is added to the urls
*/
static int curl_schedule (struct Plugin *plugin);
+/**
+ * Task scheduled to reset the inbound quota delay for a specific peer
+ * @param cls plugin as closure
+ * @param tc task context
+ */
+static void reset_inbound_quota_delay (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct HTTP_PeerContext * pc;
+
+ GNUNET_assert(cls !=NULL);
+
+ pc = (struct HTTP_PeerContext *) cls;
+ pc->reset_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ pc->delay = GNUNET_TIME_relative_get_zero ();
+}
+
/**
* Creates a valid url from passed address and id
{
if (0 == memcmp(&plugin->bind4_address->sin_addr, &bnd_cmp, sizeof (struct in_addr)))
{
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv4_addr_head,plugin->ipv4_addr_tail,t4);
plugin->env->notify_address(plugin->env->cls,PROTOCOL_PREFIX,t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
}
}
else
{
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv4_addr_head,plugin->ipv4_addr_tail,t4);
plugin->env->notify_address(plugin->env->cls,PROTOCOL_PREFIX,t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
}
- GNUNET_free (t4);
+
}
else if ((af == AF_INET6) && (plugin->use_ipv6 == GNUNET_YES) && (plugin->bind4_address == NULL))
{
sizeof (struct in6_addr));
t6->u6_port = htons (plugin->port_inbound);
plugin->env->notify_address(plugin->env->cls,PROTOCOL_PREFIX,t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv6_addr_head,plugin->ipv6_addr_tail,t6);
}
}
else
&((struct sockaddr_in6 *) addr)->sin6_addr,
sizeof (struct in6_addr));
t6->u6_port = htons (plugin->port_inbound);
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv6_addr_head,plugin->ipv6_addr_tail,t6);
plugin->env->notify_address(plugin->env->cls,PROTOCOL_PREFIX,t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
}
- GNUNET_free (t6);
}
return GNUNET_OK;
}
void *client,
const struct GNUNET_MessageHeader *message)
{
-
+ struct GNUNET_TIME_Relative delay;
struct Session *ps = cls;
GNUNET_assert(ps != NULL);
ntohs(message->size),
GNUNET_i2s(&(ps->peercontext)->identity),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
#endif
- pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
- &pc->identity,
- message, 1, ps,
- NULL,
- 0);
+ delay = pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
+ &pc->identity,
+ message, 1, ps,
+ NULL,
+ 0);
+ pc->delay = delay;
+ if (pc->reset_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (pc->plugin->env->sched, pc->reset_task);
+
+ if (delay.value > 0)
+ {
+#if DEBUG_HTTP
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Connection %X: Inbound quota management: delay next read for %llu ms \n", ps, delay.value);
+#endif
+ pc->reset_task = GNUNET_SCHEDULER_add_delayed (pc->plugin->env->sched, delay, &reset_inbound_quota_delay, pc);
+ }
}
/**
struct IPv4HttpAddress ipv4addr;
struct IPv6HttpAddress ipv6addr;
- struct HTTP_PeerContext *pc;
+ struct HTTP_PeerContext *pc = NULL;
struct Session *ps = NULL;
struct Session *ps_tmp = NULL;
/* Recieving data */
if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
{
- res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
- (*upload_data_size) = 0;
+ if (pc->delay.value == 0)
+ {
+ res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
+ (*upload_data_size) = 0;
+ }
+ else
+ {
+#if DEBUG_HTTP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: no inbound bandwidth available! Next read was delayed for %llu ms\n", ps, ps->peercontext->delay.value);
+#endif
+ }
return MHD_YES;
}
else
const struct GNUNET_MessageHeader *message)
{
struct Session *ps = cls;
+ struct GNUNET_TIME_Relative delay;
GNUNET_assert(ps != NULL);
struct HTTP_PeerContext *pc = ps->peercontext;
ntohs(message->size),
GNUNET_i2s(&(pc->identity)),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
#endif
- pc->plugin->env->receive (pc->plugin->env->cls,
- &pc->identity,
- message, 1, ps,
- ps->addr,
- ps->addrlen);
+ delay = pc->plugin->env->receive (pc->plugin->env->cls,
+ &pc->identity,
+ message, 1, ps,
+ ps->addr,
+ ps->addrlen);
+
+ pc->delay = delay;
+ if (pc->reset_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (pc->plugin->env->sched, pc->reset_task);
+
+ if (delay.value > 0)
+ {
+#if DEBUG_HTTP
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Connection %X: Inbound quota management: delay next read for %llu ms \n", ps, delay.value);
+#endif
+ pc->reset_task = GNUNET_SCHEDULER_add_delayed (pc->plugin->env->sched, delay, &reset_inbound_quota_delay, pc);
+ }
}
static size_t curl_receive_cb( void *stream, size_t size, size_t nmemb, void *ptr)
{
struct Session * ps = ptr;
+
+ if (ps->peercontext->delay.value > 0)
+ {
+#if DEBUG_HTTP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: no inbound bandwidth available! Next read was delayed for %llu ms\n", ps, ps->peercontext->delay.value);
+#endif
+ return (0);
+ }
+
#if DEBUG_CONNECTIONS
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes received\n",ps, size*nmemb);
#endif
if (msgbuf_size >= (ps->queue_length_max - ps->queue_length_cur))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Queue %X full: (%u) bytes in queue, would discard message (%u)\n", ps, (ps->queue_length_max - ps->queue_length_cur), msgbuf_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Queue %X full: %u bytes in queue available, message with %u is too big\n", ps, (ps->queue_length_max - ps->queue_length_cur), msgbuf_size);
//return GNUNET_SYSERR;
}
struct Plugin *plugin = cls;
struct IPv4HttpAddress *v4;
struct IPv6HttpAddress *v6;
+
+ struct IPv4HttpAddress *tv4 = plugin->ipv4_addr_head;
+ struct IPv6HttpAddress *tv6 = plugin->ipv6_addr_head;
+ int res;
unsigned int port;
GNUNET_assert(cls !=NULL);
{
return GNUNET_SYSERR;
} */
+
+ if (plugin->bind4_address!=NULL)
+ {
+ res = memcmp (&plugin->bind4_address->sin_addr, &v4->ipv4_addr, sizeof(uint32_t));
+ if ((res==0) && (ntohs (v4->u_port) == plugin->port_inbound))
+ return GNUNET_OK;
+ else
+ return GNUNET_SYSERR;
+ }
+
+ while (tv4!=NULL)
+ {
+ res = memcmp (&tv4->ipv4_addr, &v4->ipv4_addr, sizeof(uint32_t));
+ if ((res==0) && (v4->u_port == tv4->u_port) && (ntohs (v4->u_port) == plugin->port_inbound))
+ return GNUNET_OK;
+ tv4 = tv4->next;
+ }
port = ntohs (v4->u_port);
if (port != plugin->port_inbound)
{
if (addrlen == sizeof (struct IPv6HttpAddress))
{
v6 = (struct IPv6HttpAddress *) addr;
- if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
- {
- return GNUNET_SYSERR;
- }
- port = ntohs (v6->u6_port);
- if (port != plugin->port_inbound)
+
+ if (plugin->bind6_address!=NULL)
{
- return GNUNET_SYSERR;
+ res = memcmp (&plugin->bind6_address->sin6_addr, &v6->ipv6_addr, sizeof(struct in6_addr));
+ if ((res==0) && (ntohs (v6->u6_port) == plugin->port_inbound))
+ return GNUNET_OK;
+ else
+ return GNUNET_SYSERR;
+ }
+
+ while (tv6!=NULL)
+ {
+ res = memcmp (&tv6->ipv6_addr, &v6->ipv6_addr, sizeof(struct in6_addr));
+ if ((res==0) && (v6->u6_port == tv6->u6_port) && (ntohs (v6->u6_port) == plugin->port_inbound))
+ return GNUNET_OK;
+ tv6 = tv6->next;
}
}
- return GNUNET_OK;
+ return GNUNET_SYSERR;
}
struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
struct Plugin *plugin = api->cls;
CURLMcode mret;
+ struct IPv4HttpAddress * ipv4addr;
+ struct IPv6HttpAddress * ipv6addr;
GNUNET_assert(cls !=NULL);
if (plugin->http_server_daemon_v4 != NULL)
plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
}
+ while (plugin->ipv4_addr_head!=NULL)
+ {
+ ipv4addr = plugin->ipv4_addr_head;
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_addr_head,plugin->ipv4_addr_tail,ipv4addr);
+ GNUNET_free(ipv4addr);
+ }
+
+ while (plugin->ipv6_addr_head!=NULL)
+ {
+ ipv6addr = plugin->ipv6_addr_head;
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_addr_head,plugin->ipv6_addr_tail,ipv6addr);
+ GNUNET_free(ipv6addr);
+ }
+
/* free all peer information */
if (plugin->peers!=NULL)
{