aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_http_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/plugin_transport_http_server.c')
-rw-r--r--src/transport/plugin_transport_http_server.c370
1 files changed, 265 insertions, 105 deletions
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index 0db5e31c5..ab6b0d1da 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -23,6 +23,7 @@
23 * @brief HTTP/S server transport plugin 23 * @brief HTTP/S server transport plugin
24 * @author Matthias Wachs 24 * @author Matthias Wachs
25 * @author David Barksdale 25 * @author David Barksdale
26 * @author Christian Grothoff
26 */ 27 */
27#include "platform.h" 28#include "platform.h"
28#include "gnunet_util_lib.h" 29#include "gnunet_util_lib.h"
@@ -223,11 +224,31 @@ struct Session
223 struct GNUNET_TIME_Absolute next_receive; 224 struct GNUNET_TIME_Absolute next_receive;
224 225
225 /** 226 /**
227 * Absolute time when this connection will time out.
228 */
229 struct GNUNET_TIME_Absolute timeout;
230
231 /**
226 * Session timeout task 232 * Session timeout task
227 */ 233 */
228 GNUNET_SCHEDULER_TaskIdentifier timeout_task; 234 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
229 235
230 /** 236 /**
237 * Task to resume MHD handling when receiving is allowed again
238 */
239 GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task;
240
241 /**
242 * Number of bytes waiting for transmission to this peer.
243 */
244 unsigned long long bytes_in_queue;
245
246 /**
247 * Number of messages waiting for transmission to this peer.
248 */
249 unsigned int msgs_in_queue;
250
251 /**
231 * Unique HTTP/S connection tag for this connection 252 * Unique HTTP/S connection tag for this connection
232 */ 253 */
233 uint32_t tag; 254 uint32_t tag;
@@ -295,6 +316,7 @@ struct HTTP_Server_Plugin
295 * NAT handle & address management 316 * NAT handle & address management
296 */ 317 */
297 struct GNUNET_NAT_Handle *nat; 318 struct GNUNET_NAT_Handle *nat;
319
298 /** 320 /**
299 * IPv4 addresses DLL head 321 * IPv4 addresses DLL head
300 */ 322 */
@@ -453,10 +475,10 @@ notify_session_monitor (struct HTTP_Server_Plugin *plugin,
453 memset (&info, 0, sizeof (info)); 475 memset (&info, 0, sizeof (info));
454 info.state = state; 476 info.state = state;
455 info.is_inbound = GNUNET_YES; 477 info.is_inbound = GNUNET_YES;
456 // info.num_msg_pending = session->msgs_in_queue; // FIXME 478 info.num_msg_pending = session->msgs_in_queue;
457 // info.num_bytes_pending = session->bytes_in_queue; // FIXME 479 info.num_bytes_pending = session->bytes_in_queue;
458 // info.receive_delay = session->next_receive; // FIXME 480 info.receive_delay = session->next_receive;
459 // info.session_timeout = session->timeout; // FIXME 481 info.session_timeout = session->timeout;
460 info.address = session->address; 482 info.address = session->address;
461 plugin->sic (plugin->sic_cls, 483 plugin->sic (plugin->sic_cls,
462 session, 484 session,
@@ -465,6 +487,28 @@ notify_session_monitor (struct HTTP_Server_Plugin *plugin,
465 487
466 488
467/** 489/**
490 * Wake up an MHD connection which was suspended
491 *
492 * @param cls the session
493 * @param tc task context
494 */
495static void
496server_wake_up (void *cls,
497 const struct GNUNET_SCHEDULER_TaskContext *tc)
498{
499 struct Session *s = cls;
500
501 s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
502 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
503 return;
504 LOG (GNUNET_ERROR_TYPE_DEBUG,
505 "Session %p: Waking up PUT handle\n",
506 s);
507 MHD_resume_connection (s->server_recv->mhd_conn);
508}
509
510
511/**
468 * Reschedule the execution of both IPv4 and IPv6 server. 512 * Reschedule the execution of both IPv4 and IPv6 server.
469 * 513 *
470 * @param plugin the plugin 514 * @param plugin the plugin
@@ -488,7 +532,6 @@ server_delete_session (struct Session *s)
488{ 532{
489 struct HTTP_Server_Plugin *plugin = s->plugin; 533 struct HTTP_Server_Plugin *plugin = s->plugin;
490 struct HTTP_Message *msg; 534 struct HTTP_Message *msg;
491 struct HTTP_Message *tmp;
492 struct ServerConnection *send; 535 struct ServerConnection *send;
493 struct ServerConnection *recv; 536 struct ServerConnection *recv;
494 537
@@ -496,15 +539,21 @@ server_delete_session (struct Session *s)
496 { 539 {
497 GNUNET_SCHEDULER_cancel (s->timeout_task); 540 GNUNET_SCHEDULER_cancel (s->timeout_task);
498 s->timeout_task = GNUNET_SCHEDULER_NO_TASK; 541 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
542 s->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
543 }
544 if (GNUNET_SCHEDULER_NO_TASK != s->recv_wakeup_task)
545 {
546 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
547 s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
548 if (NULL != s->server_recv)
549 MHD_resume_connection (s->server_recv->mhd_conn);
499 } 550 }
500 GNUNET_assert (GNUNET_OK == 551 GNUNET_assert (GNUNET_OK ==
501 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, 552 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
502 &s->target, 553 &s->target,
503 s)); 554 s));
504 msg = s->msg_head; 555 while (NULL != (msg = s->msg_head))
505 while (NULL != msg)
506 { 556 {
507 tmp = msg->next;
508 GNUNET_CONTAINER_DLL_remove (s->msg_head, 557 GNUNET_CONTAINER_DLL_remove (s->msg_head,
509 s->msg_tail, 558 s->msg_tail,
510 msg); 559 msg);
@@ -514,9 +563,14 @@ server_delete_session (struct Session *s)
514 GNUNET_SYSERR, 563 GNUNET_SYSERR,
515 msg->size, 564 msg->size,
516 msg->pos + msg->overhead); 565 msg->pos + msg->overhead);
566 GNUNET_assert (s->msgs_in_queue > 0);
567 s->msgs_in_queue--;
568 GNUNET_assert (s->bytes_in_queue >= msg->size);
569 s->bytes_in_queue -= msg->size;
517 GNUNET_free (msg); 570 GNUNET_free (msg);
518 msg = tmp;
519 } 571 }
572 GNUNET_assert (0 == s->msgs_in_queue);
573 GNUNET_assert (0 == s->bytes_in_queue);
520 send = s->server_send; 574 send = s->server_send;
521 if (NULL != send) 575 if (NULL != send)
522 { 576 {
@@ -546,6 +600,9 @@ server_delete_session (struct Session *s)
546 recv->mhd_daemon, 600 recv->mhd_daemon,
547 GNUNET_YES); 601 GNUNET_YES);
548 } 602 }
603 notify_session_monitor (plugin,
604 s,
605 GNUNET_TRANSPORT_SS_DOWN);
549 if (GNUNET_YES == s->known_to_service) 606 if (GNUNET_YES == s->known_to_service)
550 plugin->env->session_end (plugin->env->cls, 607 plugin->env->session_end (plugin->env->cls,
551 s->address, 608 s->address,
@@ -591,8 +648,22 @@ server_session_timeout (void *cls,
591 const struct GNUNET_SCHEDULER_TaskContext *tc) 648 const struct GNUNET_SCHEDULER_TaskContext *tc)
592{ 649{
593 struct Session *s = cls; 650 struct Session *s = cls;
651 struct GNUNET_TIME_Relative left;
594 652
595 s->timeout_task = GNUNET_SCHEDULER_NO_TASK; 653 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
654 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
655 if (0 != left.rel_value_us)
656 {
657 /* not actually our turn yet, but let's at least update
658 the monitor, it may think we're about to die ... */
659 notify_session_monitor (s->plugin,
660 s,
661 GNUNET_TRANSPORT_SS_UP);
662 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
663 &server_session_timeout,
664 s);
665 return;
666 }
596 GNUNET_log (TIMEOUT_LOG, 667 GNUNET_log (TIMEOUT_LOG,
597 "Session %p was idle for %s, disconnecting\n", 668 "Session %p was idle for %s, disconnecting\n",
598 s, 669 s,
@@ -611,15 +682,7 @@ static void
611server_reschedule_session_timeout (struct Session *s) 682server_reschedule_session_timeout (struct Session *s)
612{ 683{
613 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); 684 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
614 GNUNET_SCHEDULER_cancel (s->timeout_task); 685 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
615 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
616 &server_session_timeout,
617 s);
618 GNUNET_log (TIMEOUT_LOG,
619 "Timeout rescheduled for session %p set to %s\n",
620 s,
621 GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT,
622 GNUNET_YES));
623} 686}
624 687
625 688
@@ -681,10 +744,17 @@ http_server_plugin_send (void *cls,
681 msg->buf = (char *) &msg[1]; 744 msg->buf = (char *) &msg[1];
682 msg->transmit_cont = cont; 745 msg->transmit_cont = cont;
683 msg->transmit_cont_cls = cont_cls; 746 msg->transmit_cont_cls = cont_cls;
684 memcpy (msg->buf, msgbuf, msgbuf_size); 747 memcpy (msg->buf,
748 msgbuf,
749 msgbuf_size);
685 GNUNET_CONTAINER_DLL_insert_tail (session->msg_head, 750 GNUNET_CONTAINER_DLL_insert_tail (session->msg_head,
686 session->msg_tail, 751 session->msg_tail,
687 msg); 752 msg);
753 session->msgs_in_queue++;
754 session->bytes_in_queue += msg->size;
755 notify_session_monitor (plugin,
756 session,
757 GNUNET_TRANSPORT_SS_UP);
688 GNUNET_asprintf (&stat_txt, 758 GNUNET_asprintf (&stat_txt,
689 "# bytes currently in %s_server buffers", 759 "# bytes currently in %s_server buffers",
690 plugin->protocol); 760 plugin->protocol);
@@ -1018,6 +1088,15 @@ http_server_query_keepalive_factor (void *cls)
1018} 1088}
1019 1089
1020 1090
1091/**
1092 * Function that will be called whenever the transport service wants to
1093 * notify the plugin that a session is still active and in use and
1094 * therefore the session timeout for this session has to be updated
1095 *
1096 * @param cls closure
1097 * @param peer which peer was the session for
1098 * @param session which session is being updated
1099 */
1021static void 1100static void
1022http_server_plugin_update_session_timeout (void *cls, 1101http_server_plugin_update_session_timeout (void *cls,
1023 const struct GNUNET_PeerIdentity *peer, 1102 const struct GNUNET_PeerIdentity *peer,
@@ -1094,8 +1173,8 @@ server_parse_url (struct HTTP_Server_Plugin *plugin,
1094 1173
1095 if (NULL == url) 1174 if (NULL == url)
1096 { 1175 {
1097 GNUNET_break (0); 1176 GNUNET_break (0);
1098 return GNUNET_SYSERR; 1177 return GNUNET_SYSERR;
1099 } 1178 }
1100 1179
1101 if (regexec(&plugin->url_regex, url, 4, matches, 0)) 1180 if (regexec(&plugin->url_regex, url, 4, matches, 0))
@@ -1162,9 +1241,12 @@ server_parse_url (struct HTTP_Server_Plugin *plugin,
1162 GNUNET_i2s_full (target)); 1241 GNUNET_i2s_full (target));
1163 1242
1164 /* convert options */ 1243 /* convert options */
1165 if (-1 == matches[3].rm_so) { 1244 if (-1 == matches[3].rm_so)
1166 *options = 0; 1245 {
1167 } else { 1246 *options = 0;
1247 }
1248 else
1249 {
1168 rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10); 1250 rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10);
1169 if (&url[matches[3].rm_eo] != options_end) 1251 if (&url[matches[3].rm_eo] != options_end)
1170 { 1252 {
@@ -1184,9 +1266,10 @@ server_parse_url (struct HTTP_Server_Plugin *plugin,
1184 "URL options > UINT32_MAX\n"); 1266 "URL options > UINT32_MAX\n");
1185 return GNUNET_SYSERR; 1267 return GNUNET_SYSERR;
1186 } 1268 }
1187 (*options) = (uint32_t)rc; 1269 (*options) = (uint32_t) rc;
1188 LOG (GNUNET_ERROR_TYPE_DEBUG, 1270 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 "Found options `%u' in url\n", *options); 1271 "Found options `%u' in url\n",
1272 *options);
1190 } 1273 }
1191 return GNUNET_OK; 1274 return GNUNET_OK;
1192} 1275}
@@ -1344,6 +1427,7 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1344 s->ats_address_network_type = ats.value; 1427 s->ats_address_network_type = ats.value;
1345 s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; 1428 s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS;
1346 s->tag = stc.tag; 1429 s->tag = stc.tag;
1430 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_SERVER_SESSION_TIMEOUT);
1347 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, 1431 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT,
1348 &server_session_timeout, 1432 &server_session_timeout,
1349 s); 1433 s);
@@ -1351,7 +1435,9 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1351 &s->target, 1435 &s->target,
1352 s, 1436 s,
1353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 1437 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1354 1438 notify_session_monitor (plugin,
1439 s,
1440 GNUNET_TRANSPORT_SS_HANDSHAKE);
1355 LOG (GNUNET_ERROR_TYPE_DEBUG, 1441 LOG (GNUNET_ERROR_TYPE_DEBUG,
1356 "Creating new session %p for peer `%s' connecting from `%s'\n", 1442 "Creating new session %p for peer `%s' connecting from `%s'\n",
1357 s, GNUNET_i2s (&target), 1443 s, GNUNET_i2s (&target),
@@ -1361,7 +1447,8 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1361 GNUNET_free_non_null (addr); 1447 GNUNET_free_non_null (addr);
1362 } 1448 }
1363 1449
1364 if ( (_RECEIVE == direction) && (NULL != s->server_recv) ) 1450 if ( (_RECEIVE == direction) &&
1451 (NULL != s->server_recv) )
1365 { 1452 {
1366 LOG (GNUNET_ERROR_TYPE_DEBUG, 1453 LOG (GNUNET_ERROR_TYPE_DEBUG,
1367 "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n", 1454 "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n",
@@ -1392,13 +1479,15 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1392 if (direction == _RECEIVE) 1479 if (direction == _RECEIVE)
1393 s->server_recv = sc; 1480 s->server_recv = sc;
1394 1481
1395 if ((NULL != s->server_send) && (NULL != s->server_recv)) 1482 if ( (NULL != s->server_send) &&
1483 (NULL != s->server_recv) )
1396 { 1484 {
1397 s->known_to_service = GNUNET_YES; 1485 s->known_to_service = GNUNET_YES;
1398 plugin->env->session_start (NULL, s->address ,s, NULL, 0); 1486 plugin->env->session_start (NULL, s->address ,s, NULL, 0);
1399 } 1487 }
1400 1488
1401 if ((NULL == s->server_recv) || (NULL == s->server_send)) 1489 if ( (NULL == s->server_recv) ||
1490 (NULL == s->server_send) )
1402 { 1491 {
1403 to = (HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL); 1492 to = (HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1404 MHD_set_connection_option (mhd_connection, 1493 MHD_set_connection_option (mhd_connection,
@@ -1425,8 +1514,8 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin,
1425 * @param cls current session 1514 * @param cls current session
1426 * @param pos position in buffer 1515 * @param pos position in buffer
1427 * @param buf the buffer to write data to 1516 * @param buf the buffer to write data to
1428 * @param max max number of bytes available in buffer 1517 * @param max max number of bytes available in @a buf
1429 * @return bytes written to buffer 1518 * @return bytes written to @a buf
1430 */ 1519 */
1431static ssize_t 1520static ssize_t
1432server_send_callback (void *cls, 1521server_send_callback (void *cls,
@@ -1461,7 +1550,14 @@ server_send_callback (void *cls,
1461 if (NULL != msg->transmit_cont) 1550 if (NULL != msg->transmit_cont)
1462 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, 1551 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK,
1463 msg->size, msg->size + msg->overhead); 1552 msg->size, msg->size + msg->overhead);
1553 GNUNET_assert (s->msgs_in_queue > 0);
1554 s->msgs_in_queue--;
1555 GNUNET_assert (s->bytes_in_queue >= msg->size);
1556 s->bytes_in_queue -= msg->size;
1464 GNUNET_free (msg); 1557 GNUNET_free (msg);
1558 notify_session_monitor (s->plugin,
1559 s,
1560 GNUNET_TRANSPORT_SS_UP);
1465 } 1561 }
1466 } 1562 }
1467 if (0 < bytes_read) 1563 if (0 < bytes_read)
@@ -1469,13 +1565,19 @@ server_send_callback (void *cls,
1469 sc->connected = GNUNET_YES; 1565 sc->connected = GNUNET_YES;
1470 LOG (GNUNET_ERROR_TYPE_DEBUG, 1566 LOG (GNUNET_ERROR_TYPE_DEBUG,
1471 "Sent %u bytes to peer `%s' with session %p \n", 1567 "Sent %u bytes to peer `%s' with session %p \n",
1472 bytes_read, GNUNET_i2s (&s->target), s); 1568 bytes_read,
1473 GNUNET_asprintf (&stat_txt, "# bytes currently in %s_server buffers", 1569 GNUNET_i2s (&s->target),
1570 s);
1571 GNUNET_asprintf (&stat_txt,
1572 "# bytes currently in %s_server buffers",
1474 s->plugin->protocol); 1573 s->plugin->protocol);
1475 GNUNET_STATISTICS_update (s->plugin->env->stats, 1574 GNUNET_STATISTICS_update (s->plugin->env->stats,
1476 stat_txt, -bytes_read, GNUNET_NO); 1575 stat_txt,
1576 - bytes_read,
1577 GNUNET_NO);
1477 GNUNET_free (stat_txt); 1578 GNUNET_free (stat_txt);
1478 GNUNET_asprintf (&stat_txt, "# bytes transmitted via %s_server", 1579 GNUNET_asprintf (&stat_txt,
1580 "# bytes transmitted via %s_server",
1479 s->plugin->protocol); 1581 s->plugin->protocol);
1480 GNUNET_STATISTICS_update (s->plugin->env->stats, 1582 GNUNET_STATISTICS_update (s->plugin->env->stats,
1481 stat_txt, bytes_read, GNUNET_NO); 1583 stat_txt, bytes_read, GNUNET_NO);
@@ -1484,8 +1586,9 @@ server_send_callback (void *cls,
1484 else if ((sc->options & OPTION_LONG_POLL) && sc->connected) 1586 else if ((sc->options & OPTION_LONG_POLL) && sc->connected)
1485 { 1587 {
1486 LOG (GNUNET_ERROR_TYPE_DEBUG, 1588 LOG (GNUNET_ERROR_TYPE_DEBUG,
1487 "Completing GET response to peer `%s' with session %p \n", 1589 "Completing GET response to peer `%s' with session %p\n",
1488 GNUNET_i2s (&s->target), s); 1590 GNUNET_i2s (&s->target),
1591 s);
1489 return MHD_CONTENT_READER_END_OF_STREAM; 1592 return MHD_CONTENT_READER_END_OF_STREAM;
1490 } 1593 }
1491 return bytes_read; 1594 return bytes_read;
@@ -1519,7 +1622,14 @@ server_receive_mst_cb (void *cls,
1519 if (GNUNET_NO == s->known_to_service) 1622 if (GNUNET_NO == s->known_to_service)
1520 { 1623 {
1521 s->known_to_service = GNUNET_YES; 1624 s->known_to_service = GNUNET_YES;
1522 plugin->env->session_start (NULL, s->address, s, NULL, 0); 1625 plugin->env->session_start (NULL,
1626 s->address,
1627 s,
1628 NULL,
1629 0);
1630 notify_session_monitor (plugin,
1631 s,
1632 GNUNET_TRANSPORT_SS_UP);
1523 } 1633 }
1524 delay = plugin->env->receive (plugin->env->cls, 1634 delay = plugin->env->receive (plugin->env->cls,
1525 s->address, 1635 s->address,
@@ -1554,6 +1664,8 @@ server_receive_mst_cb (void *cls,
1554/** 1664/**
1555 * Add headers to a request indicating that we allow Cross-Origin Resource 1665 * Add headers to a request indicating that we allow Cross-Origin Resource
1556 * Sharing. 1666 * Sharing.
1667 *
1668 * @param response response object to modify
1557 */ 1669 */
1558static void 1670static void
1559add_cors_headers(struct MHD_Response *response) 1671add_cors_headers(struct MHD_Response *response)
@@ -1579,7 +1691,7 @@ add_cors_headers(struct MHD_Response *response)
1579 * @param method GET or PUT 1691 * @param method GET or PUT
1580 * @param version HTTP version 1692 * @param version HTTP version
1581 * @param upload_data upload data 1693 * @param upload_data upload data
1582 * @param upload_data_size sizeof upload data 1694 * @param upload_data_size size of @a upload_data
1583 * @param httpSessionCache the session cache to remember the connection 1695 * @param httpSessionCache the session cache to remember the connection
1584 * @return MHD_YES if connection is accepted, MHD_NO on reject 1696 * @return MHD_YES if connection is accepted, MHD_NO on reject
1585 */ 1697 */
@@ -1705,6 +1817,8 @@ server_access_cb (void *cls,
1705 } 1817 }
1706 else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES)) 1818 else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES))
1707 { 1819 {
1820 struct GNUNET_TIME_Relative delay;
1821
1708 /* (*upload_data_size > 0) for every segment received */ 1822 /* (*upload_data_size > 0) for every segment received */
1709 LOG (GNUNET_ERROR_TYPE_DEBUG, 1823 LOG (GNUNET_ERROR_TYPE_DEBUG,
1710 "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %u bytes\n", 1824 "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %u bytes\n",
@@ -1714,9 +1828,8 @@ server_access_cb (void *cls,
1714 s->address->address, 1828 s->address->address,
1715 s->address->address_length), 1829 s->address->address_length),
1716 *upload_data_size); 1830 *upload_data_size);
1717 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1831 delay = GNUNET_TIME_absolute_get_remaining (s->next_receive);
1718 1832 if (0 == delay.rel_value_us)
1719 if ((s->next_receive.abs_value_us <= now.abs_value_us))
1720 { 1833 {
1721 LOG (GNUNET_ERROR_TYPE_DEBUG, 1834 LOG (GNUNET_ERROR_TYPE_DEBUG,
1722 "PUT with %u bytes forwarded to MST\n", 1835 "PUT with %u bytes forwarded to MST\n",
@@ -1725,19 +1838,26 @@ server_access_cb (void *cls,
1725 { 1838 {
1726 s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); 1839 s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s);
1727 } 1840 }
1728 GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, 1841 GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data,
1729 *upload_data_size, GNUNET_NO, GNUNET_NO); 1842 *upload_data_size, GNUNET_NO, GNUNET_NO);
1730 server_mhd_connection_timeout (plugin, s, 1843 server_mhd_connection_timeout (plugin, s,
1731 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL / 1000LL); 1844 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1732 (*upload_data_size) = 0; 1845 (*upload_data_size) = 0;
1733 } 1846 }
1734 else 1847 else
1735 { 1848 {
1849 /* delay processing */
1736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1737 "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n", 1851 "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n",
1738 s, sc, 1852 s, sc,
1739 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (s->next_receive), 1853 GNUNET_STRINGS_relative_time_to_string (delay,
1740 GNUNET_YES)); 1854 GNUNET_YES));
1855 GNUNET_assert (s->server_recv->mhd_conn == mhd_connection);
1856 MHD_suspend_connection (s->server_recv->mhd_conn);
1857 if (GNUNET_SCHEDULER_NO_TASK == s->recv_wakeup_task)
1858 s->recv_wakeup_task = GNUNET_SCHEDULER_add_delayed (delay,
1859 &server_wake_up,
1860 s);
1741 } 1861 }
1742 return MHD_YES; 1862 return MHD_YES;
1743 } 1863 }
@@ -1832,7 +1952,7 @@ server_disconnect_cb (void *cls,
1832 * 1952 *
1833 * @param cls plugin as closure 1953 * @param cls plugin as closure
1834 * @param addr address of incoming connection 1954 * @param addr address of incoming connection
1835 * @param addr_len address length of incoming connection 1955 * @param addr_len number of bytes in @a addr
1836 * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected 1956 * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
1837 */ 1957 */
1838static int 1958static int
@@ -1860,6 +1980,14 @@ server_accept_cb (void *cls,
1860} 1980}
1861 1981
1862 1982
1983/**
1984 * Log function called by MHD.
1985 *
1986 * @param arg NULL
1987 * @param fmt format string
1988 * @param ap arguments for the format string (va_start() and va_end()
1989 * will be called by MHD)
1990 */
1863static void 1991static void
1864server_log (void *arg, 1992server_log (void *arg,
1865 const char *fmt, 1993 const char *fmt,
@@ -1867,8 +1995,10 @@ server_log (void *arg,
1867{ 1995{
1868 char text[1024]; 1996 char text[1024];
1869 1997
1870 vsnprintf (text, sizeof (text), fmt, ap); 1998 vsnprintf (text,
1871 va_end (ap); 1999 sizeof (text),
2000 fmt,
2001 ap);
1872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1873 "Server: %s\n", 2003 "Server: %s\n",
1874 text); 2004 text);
@@ -1896,7 +2026,7 @@ server_load_file (const char *file)
1896 gn_file = 2026 gn_file =
1897 GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, 2027 GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
1898 GNUNET_DISK_PERM_USER_READ); 2028 GNUNET_DISK_PERM_USER_READ);
1899 if (gn_file == NULL) 2029 if (NULL == gn_file)
1900 { 2030 {
1901 GNUNET_free (text); 2031 GNUNET_free (text);
1902 return NULL; 2032 return NULL;
@@ -2114,7 +2244,9 @@ server_start (struct HTTP_Server_Plugin *plugin)
2114 plugin->name, plugin->port); 2244 plugin->name, plugin->port);
2115 } 2245 }
2116 else 2246 else
2117 server_reschedule (plugin, plugin->server_v4, GNUNET_NO); 2247 server_reschedule (plugin,
2248 plugin->server_v4,
2249 GNUNET_NO);
2118 } 2250 }
2119 2251
2120 2252
@@ -2186,44 +2318,6 @@ server_start (struct HTTP_Server_Plugin *plugin)
2186} 2318}
2187 2319
2188 2320
2189static void
2190server_stop (struct HTTP_Server_Plugin *plugin)
2191{
2192 if (plugin->server_v4 != NULL)
2193 {
2194 MHD_stop_daemon (plugin->server_v4);
2195 plugin->server_v4 = NULL;
2196 }
2197 if ( plugin->server_v6 != NULL)
2198 {
2199 MHD_stop_daemon (plugin->server_v6);
2200 plugin->server_v6 = NULL;
2201 }
2202
2203
2204 if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
2205 {
2206 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
2207 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
2208 }
2209
2210 if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
2211 {
2212 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
2213 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
2214 }
2215#if BUILD_HTTPS
2216 GNUNET_free_non_null (plugin->crypto_init);
2217 GNUNET_free_non_null (plugin->cert);
2218 GNUNET_free_non_null (plugin->key);
2219#endif
2220
2221 LOG (GNUNET_ERROR_TYPE_DEBUG,
2222 "%s server component stopped\n",
2223 plugin->name);
2224}
2225
2226
2227/** 2321/**
2228 * Add an address to the server's set of addresses and notify transport 2322 * Add an address to the server's set of addresses and notify transport
2229 * 2323 *
@@ -2456,8 +2550,7 @@ server_get_addresses (struct HTTP_Server_Plugin *plugin,
2456 if (port > 65535) 2550 if (port > 65535)
2457 { 2551 {
2458 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2552 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2459 _ 2553 _("Require valid port number for service in configuration!\n"));
2460 ("Require valid port number for service in configuration!\n"));
2461 return GNUNET_SYSERR; 2554 return GNUNET_SYSERR;
2462 } 2555 }
2463 } 2556 }
@@ -2469,7 +2562,8 @@ server_get_addresses (struct HTTP_Server_Plugin *plugin,
2469 } 2562 }
2470 2563
2471 2564
2472 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) 2565 if (GNUNET_CONFIGURATION_have_value (cfg, service_name,
2566 "BINDTO"))
2473 { 2567 {
2474 GNUNET_break (GNUNET_OK == 2568 GNUNET_break (GNUNET_OK ==
2475 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, 2569 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
@@ -2478,7 +2572,7 @@ server_get_addresses (struct HTTP_Server_Plugin *plugin,
2478 else 2572 else
2479 hostname = NULL; 2573 hostname = NULL;
2480 2574
2481 if (hostname != NULL) 2575 if (NULL != hostname)
2482 { 2576 {
2483 LOG (GNUNET_ERROR_TYPE_DEBUG, 2577 LOG (GNUNET_ERROR_TYPE_DEBUG,
2484 "Resolving `%s' since that is where `%s' will bind to.\n", 2578 "Resolving `%s' since that is where `%s' will bind to.\n",
@@ -2487,10 +2581,12 @@ server_get_addresses (struct HTTP_Server_Plugin *plugin,
2487 if (disablev6) 2581 if (disablev6)
2488 hints.ai_family = AF_INET; 2582 hints.ai_family = AF_INET;
2489 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || 2583 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
2490 (res == NULL)) 2584 (NULL == res))
2491 { 2585 {
2492 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), 2586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2493 hostname, gai_strerror (ret)); 2587 _("Failed to resolve `%s': %s\n"),
2588 hostname,
2589 gai_strerror (ret));
2494 GNUNET_free (hostname); 2590 GNUNET_free (hostname);
2495 return GNUNET_SYSERR; 2591 return GNUNET_SYSERR;
2496 } 2592 }
@@ -2522,9 +2618,9 @@ server_get_addresses (struct HTTP_Server_Plugin *plugin,
2522 next = pos->ai_next; 2618 next = pos->ai_next;
2523 if ((disablev6) && (pos->ai_family == AF_INET6)) 2619 if ((disablev6) && (pos->ai_family == AF_INET6))
2524 continue; 2620 continue;
2525 if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) 2621 if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol))
2526 continue; /* not TCP */ 2622 continue; /* not TCP */
2527 if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) 2623 if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype))
2528 continue; /* huh? */ 2624 continue; /* huh? */
2529 LOG (GNUNET_ERROR_TYPE_DEBUG, 2625 LOG (GNUNET_ERROR_TYPE_DEBUG,
2530 "Service will bind to `%s'\n", 2626 "Service will bind to `%s'\n",
@@ -2638,7 +2734,7 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2638 while (res > 0) 2734 while (res > 0)
2639 { 2735 {
2640 res--; 2736 res--;
2641 GNUNET_assert (addrs[res] != NULL); 2737 GNUNET_assert (NULL != addrs[res]);
2642 GNUNET_free (addrs[res]); 2738 GNUNET_free (addrs[res]);
2643 } 2739 }
2644 GNUNET_free_non_null (addrs); 2740 GNUNET_free_non_null (addrs);
@@ -2733,7 +2829,10 @@ server_notify_external_hostname (void *cls,
2733 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 2829 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2734 return; 2830 return;
2735 2831
2736 GNUNET_asprintf(&url, "%s://%s", plugin->protocol, plugin->external_hostname); 2832 GNUNET_asprintf(&url,
2833 "%s://%s",
2834 plugin->protocol,
2835 plugin->external_hostname);
2737 2836
2738 urlen = strlen (url) + 1; 2837 urlen = strlen (url) + 1;
2739 ext_addr = GNUNET_malloc (sizeof (struct HttpAddress) + urlen); 2838 ext_addr = GNUNET_malloc (sizeof (struct HttpAddress) + urlen);
@@ -3048,7 +3147,32 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
3048 3147
3049 /* Stop to report addresses to transport service */ 3148 /* Stop to report addresses to transport service */
3050 server_stop_report_addresses (plugin); 3149 server_stop_report_addresses (plugin);
3051 server_stop (plugin); 3150 if (NULL != plugin->server_v4)
3151 {
3152 MHD_stop_daemon (plugin->server_v4);
3153 plugin->server_v4 = NULL;
3154 }
3155 if (NULL != plugin->server_v6)
3156 {
3157 MHD_stop_daemon (plugin->server_v6);
3158 plugin->server_v6 = NULL;
3159 }
3160 if (GNUNET_SCHEDULER_NO_TASK != plugin->server_v4_task)
3161 {
3162 GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
3163 plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
3164 }
3165
3166 if (GNUNET_SCHEDULER_NO_TASK != plugin->server_v6_task)
3167 {
3168 GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
3169 plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
3170 }
3171#if BUILD_HTTPS
3172 GNUNET_free_non_null (plugin->crypto_init);
3173 GNUNET_free_non_null (plugin->cert);
3174 GNUNET_free_non_null (plugin->key);
3175#endif
3052 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, 3176 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
3053 &destroy_session_cb, 3177 &destroy_session_cb,
3054 plugin); 3178 plugin);
@@ -3090,7 +3214,9 @@ http_server_plugin_address_to_string (void *cls,
3090 const void *addr, 3214 const void *addr,
3091 size_t addrlen) 3215 size_t addrlen)
3092{ 3216{
3093 return http_common_plugin_address_to_string (PLUGIN_NAME, addr, addrlen); 3217 return http_common_plugin_address_to_string (PLUGIN_NAME,
3218 addr,
3219 addrlen);
3094} 3220}
3095 3221
3096 3222
@@ -3099,7 +3225,7 @@ http_server_plugin_address_to_string (void *cls,
3099 * 3225 *
3100 * @param cls closure ('struct HTTP_Server_Plugin*') 3226 * @param cls closure ('struct HTTP_Server_Plugin*')
3101 * @param session the session 3227 * @param session the session
3102 * @return the network type in HBO or GNUNET_SYSERR 3228 * @return the network type in HBO or #GNUNET_SYSERR
3103 */ 3229 */
3104static enum GNUNET_ATS_Network_Type 3230static enum GNUNET_ATS_Network_Type
3105http_server_get_network (void *cls, 3231http_server_get_network (void *cls,
@@ -3110,6 +3236,38 @@ http_server_get_network (void *cls,
3110 3236
3111 3237
3112/** 3238/**
3239 * Function that will be called whenever the transport service wants to
3240 * notify the plugin that the inbound quota changed and that the plugin
3241 * should update it's delay for the next receive value
3242 *
3243 * @param cls closure
3244 * @param peer which peer was the session for
3245 * @param session which session is being updated
3246 * @param delay new delay to use for receiving
3247 */
3248static void
3249http_server_plugin_update_inbound_delay (void *cls,
3250 const struct GNUNET_PeerIdentity *peer,
3251 struct Session *s,
3252 struct GNUNET_TIME_Relative delay)
3253{
3254 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
3255 LOG (GNUNET_ERROR_TYPE_DEBUG,
3256 "New inbound delay %s\n",
3257 GNUNET_STRINGS_relative_time_to_string (delay,
3258 GNUNET_NO));
3259 if (GNUNET_SCHEDULER_NO_TASK != s->recv_wakeup_task)
3260 {
3261 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
3262 s->recv_wakeup_task
3263 = GNUNET_SCHEDULER_add_delayed (delay,
3264 &server_wake_up,
3265 s);
3266 }
3267}
3268
3269
3270/**
3113 * Return information about the given session to the 3271 * Return information about the given session to the
3114 * monitor callback. 3272 * monitor callback.
3115 * 3273 *
@@ -3207,7 +3365,7 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
3207 api->address_pretty_printer = &http_common_plugin_address_pretty_printer; 3365 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
3208 api->get_network = &http_server_get_network; 3366 api->get_network = &http_server_get_network;
3209 api->update_session_timeout = &http_server_plugin_update_session_timeout; 3367 api->update_session_timeout = &http_server_plugin_update_session_timeout;
3210 // api->update_inbound_delay = &http_server_plugin_update_inbound_delay; // FIXME: implement/support! 3368 api->update_inbound_delay = &http_server_plugin_update_inbound_delay;
3211 api->setup_monitor = &http_server_plugin_setup_monitor; 3369 api->setup_monitor = &http_server_plugin_setup_monitor;
3212#if BUILD_HTTPS 3370#if BUILD_HTTPS
3213 plugin->name = "transport-https_server"; 3371 plugin->name = "transport-https_server";
@@ -3218,7 +3376,9 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
3218#endif 3376#endif
3219 3377
3220 /* Compile URL regex */ 3378 /* Compile URL regex */
3221 if (regcomp(&plugin->url_regex, URL_REGEX, REG_EXTENDED)) 3379 if (regcomp(&plugin->url_regex,
3380 URL_REGEX,
3381 REG_EXTENDED))
3222 { 3382 {
3223 LOG (GNUNET_ERROR_TYPE_ERROR, 3383 LOG (GNUNET_ERROR_TYPE_ERROR,
3224 _("Unable to compile URL regex\n")); 3384 _("Unable to compile URL regex\n"));