aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_http_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/plugin_transport_http_client.c')
-rw-r--r--src/transport/plugin_transport_http_client.c267
1 files changed, 214 insertions, 53 deletions
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
index fad7d2325..d66d8c940 100644
--- a/src/transport/plugin_transport_http_client.c
+++ b/src/transport/plugin_transport_http_client.c
@@ -205,12 +205,17 @@ struct Session
205 GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task; 205 GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task;
206 206
207 /** 207 /**
208 * Absolute time when to receive data again 208 * Absolute time when to receive data again.
209 * Used for receive throttling 209 * Used for receive throttling.
210 */ 210 */
211 struct GNUNET_TIME_Absolute next_receive; 211 struct GNUNET_TIME_Absolute next_receive;
212 212
213 /** 213 /**
214 * When does this session time out.
215 */
216 struct GNUNET_TIME_Absolute timeout;
217
218 /**
214 * Number of bytes waiting for transmission to this peer. 219 * Number of bytes waiting for transmission to this peer.
215 */ 220 */
216 unsigned long long bytes_in_queue; 221 unsigned long long bytes_in_queue;
@@ -269,6 +274,16 @@ struct HTTP_Client_Plugin
269 struct GNUNET_CONTAINER_MultiPeerMap *sessions; 274 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
270 275
271 /** 276 /**
277 * Function to call about session status changes.
278 */
279 GNUNET_TRANSPORT_SessionInfoCallback sic;
280
281 /**
282 * Closure for @e sic.
283 */
284 void *sic_cls;
285
286 /**
272 * Plugin name 287 * Plugin name
273 */ 288 */
274 char *name; 289 char *name;
@@ -317,7 +332,7 @@ struct HTTP_Client_Plugin
317 * Tunnel all operations through a given HTTP instead of have the proxy 332 * Tunnel all operations through a given HTTP instead of have the proxy
318 * evaluate the HTTP request 333 * evaluate the HTTP request
319 * 334 *
320 * Default: GNUNET_NO, GNUNET_yes experimental 335 * Default: #GNUNET_NO, #GNUNET_YES experimental
321 */ 336 */
322 int proxy_use_httpproxytunnel; 337 int proxy_use_httpproxytunnel;
323 338
@@ -356,6 +371,40 @@ struct HTTP_Client_Plugin
356}; 371};
357 372
358 373
374
375/**
376 * If a session monitor is attached, notify it about the new
377 * session state.
378 *
379 * @param plugin our plugin
380 * @param session session that changed state
381 * @param state new state of the session
382 */
383static void
384notify_session_monitor (struct HTTP_Client_Plugin *plugin,
385 struct Session *session,
386 enum GNUNET_TRANSPORT_SessionState state)
387{
388 struct GNUNET_TRANSPORT_SessionInfo info;
389
390 if (NULL == plugin->sic)
391 return;
392 memset (&info, 0, sizeof (info));
393 info.state = state;
394 info.is_inbound = GNUNET_SYSERR; /* hard to say */
395 info.num_msg_pending = session->msgs_in_queue;
396 info.num_bytes_pending = session->bytes_in_queue;
397 /* info.receive_delay remains zero as this is not supported by UDP
398 (cannot selectively not receive from 'some' peer while continuing
399 to receive from others) */
400 info.session_timeout = session->timeout;
401 info.address = session->address;
402 plugin->sic (plugin->sic_cls,
403 session,
404 &info);
405}
406
407
359/** 408/**
360 * Increment session timeout due to activity for a session 409 * Increment session timeout due to activity for a session
361 * @param s the session 410 * @param s the session
@@ -503,7 +552,11 @@ http_client_plugin_send (void *cls,
503 msg->transmit_cont = cont; 552 msg->transmit_cont = cont;
504 msg->transmit_cont_cls = cont_cls; 553 msg->transmit_cont_cls = cont_cls;
505 memcpy (msg->buf, msgbuf, msgbuf_size); 554 memcpy (msg->buf, msgbuf, msgbuf_size);
506 GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); 555 GNUNET_CONTAINER_DLL_insert_tail (s->msg_head,
556 s->msg_tail,
557 msg);
558 s->msgs_in_queue++;
559 s->bytes_in_queue += msg->size;
507 560
508 GNUNET_asprintf (&stat_txt, 561 GNUNET_asprintf (&stat_txt,
509 "# bytes currently in %s_client buffers", 562 "# bytes currently in %s_client buffers",
@@ -555,7 +608,7 @@ http_client_plugin_send (void *cls,
555 608
556 609
557/** 610/**
558 * Delete session s 611 * Delete session @a s.
559 * 612 *
560 * @param s the session to delete 613 * @param s the session to delete
561 */ 614 */
@@ -570,6 +623,7 @@ client_delete_session (struct Session *s)
570 { 623 {
571 GNUNET_SCHEDULER_cancel (s->timeout_task); 624 GNUNET_SCHEDULER_cancel (s->timeout_task);
572 s->timeout_task = GNUNET_SCHEDULER_NO_TASK; 625 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
626 s->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
573 } 627 }
574 if (GNUNET_SCHEDULER_NO_TASK != s->put_disconnect_task) 628 if (GNUNET_SCHEDULER_NO_TASK != s->put_disconnect_task)
575 { 629 {
@@ -588,6 +642,10 @@ client_delete_session (struct Session *s)
588 GNUNET_CONTAINER_DLL_remove (s->msg_head, 642 GNUNET_CONTAINER_DLL_remove (s->msg_head,
589 s->msg_tail, 643 s->msg_tail,
590 pos); 644 pos);
645 GNUNET_assert (0 < s->msgs_in_queue);
646 s->msgs_in_queue--;
647 GNUNET_assert (pos->size <= s->bytes_in_queue);
648 s->bytes_in_queue -= pos->size;
591 if (NULL != pos->transmit_cont) 649 if (NULL != pos->transmit_cont)
592 pos->transmit_cont (pos->transmit_cont_cls, 650 pos->transmit_cont (pos->transmit_cont_cls,
593 &s->target, 651 &s->target,
@@ -677,7 +735,13 @@ http_client_session_disconnect (void *cls,
677 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR, 735 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR,
678 msg->size, msg->pos + s->overhead); 736 msg->size, msg->pos + s->overhead);
679 s->overhead = 0; 737 s->overhead = 0;
680 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); 738 GNUNET_CONTAINER_DLL_remove (s->msg_head,
739 s->msg_tail,
740 msg);
741 GNUNET_assert (0 < s->msgs_in_queue);
742 s->msgs_in_queue--;
743 GNUNET_assert (msg->size <= s->bytes_in_queue);
744 s->bytes_in_queue -= msg->size;
681 GNUNET_free (msg); 745 GNUNET_free (msg);
682 msg = t; 746 msg = t;
683 } 747 }
@@ -905,22 +969,37 @@ client_send_cb (void *stream,
905 "Session %p/connection %p: sent message with %u bytes sent, removing message from queue\n", 969 "Session %p/connection %p: sent message with %u bytes sent, removing message from queue\n",
906 s, s->client_put, msg->size, msg->pos); 970 s, s->client_put, msg->size, msg->pos);
907 /* Calling transmit continuation */ 971 /* Calling transmit continuation */
908 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); 972 GNUNET_CONTAINER_DLL_remove (s->msg_head,
973 s->msg_tail,
974 msg);
975 GNUNET_assert (0 < s->msgs_in_queue);
976 s->msgs_in_queue--;
977 GNUNET_assert (msg->size <= s->bytes_in_queue);
978 s->bytes_in_queue -= msg->size;
909 if (NULL != msg->transmit_cont) 979 if (NULL != msg->transmit_cont)
910 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, 980 msg->transmit_cont (msg->transmit_cont_cls,
911 msg->size, msg->size + s->overhead); 981 &s->target,
982 GNUNET_OK,
983 msg->size,
984 msg->size + s->overhead);
912 s->overhead = 0; 985 s->overhead = 0;
913 GNUNET_free (msg); 986 GNUNET_free (msg);
914 } 987 }
915 988 GNUNET_asprintf (&stat_txt,
916 GNUNET_asprintf (&stat_txt, "# bytes currently in %s_client buffers", plugin->protocol); 989 "# bytes currently in %s_client buffers",
990 plugin->protocol);
917 GNUNET_STATISTICS_update (plugin->env->stats, 991 GNUNET_STATISTICS_update (plugin->env->stats,
918 stat_txt, -len, GNUNET_NO); 992 stat_txt,
993 - len,
994 GNUNET_NO);
919 GNUNET_free (stat_txt); 995 GNUNET_free (stat_txt);
920 996 GNUNET_asprintf (&stat_txt,
921 GNUNET_asprintf (&stat_txt, "# bytes transmitted via %s_client", plugin->protocol); 997 "# bytes transmitted via %s_client",
998 plugin->protocol);
922 GNUNET_STATISTICS_update (plugin->env->stats, 999 GNUNET_STATISTICS_update (plugin->env->stats,
923 stat_txt, len, GNUNET_NO); 1000 stat_txt,
1001 len,
1002 GNUNET_NO);
924 GNUNET_free (stat_txt); 1003 GNUNET_free (stat_txt);
925 return len; 1004 return len;
926} 1005}
@@ -996,8 +1075,8 @@ client_receive_mst_cb (void *cls,
996 LOG (GNUNET_ERROR_TYPE_DEBUG, 1075 LOG (GNUNET_ERROR_TYPE_DEBUG,
997 "Client: peer `%s' address `%s' next read delayed for %s\n", 1076 "Client: peer `%s' address `%s' next read delayed for %s\n",
998 GNUNET_i2s (&s->target), 1077 GNUNET_i2s (&s->target),
999 http_common_plugin_address_to_string (NULL, 1078 http_common_plugin_address_to_string (s->plugin->protocol,
1000 s->plugin->protocol, s->address->address, 1079 s->address->address,
1001 s->address->address_length), 1080 s->address->address_length),
1002 GNUNET_STRINGS_relative_time_to_string (delay, 1081 GNUNET_STRINGS_relative_time_to_string (delay,
1003 GNUNET_YES)); 1082 GNUNET_YES));
@@ -1494,8 +1573,9 @@ client_connect (struct Session *s)
1494 int res = GNUNET_OK; 1573 int res = GNUNET_OK;
1495 1574
1496 /* create url */ 1575 /* create url */
1497 if (NULL == http_common_plugin_address_to_string (NULL, 1576 if (NULL == http_common_plugin_address_to_string (plugin->protocol,
1498 plugin->protocol, s->address->address, s->address->address_length)) 1577 s->address->address,
1578 s->address->address_length))
1499 { 1579 {
1500 LOG (GNUNET_ERROR_TYPE_DEBUG, 1580 LOG (GNUNET_ERROR_TYPE_DEBUG,
1501 "Invalid address peer `%s'\n", 1581 "Invalid address peer `%s'\n",
@@ -1571,17 +1651,30 @@ client_session_timeout (void *cls,
1571 const struct GNUNET_SCHEDULER_TaskContext *tc) 1651 const struct GNUNET_SCHEDULER_TaskContext *tc)
1572{ 1652{
1573 struct Session *s = cls; 1653 struct Session *s = cls;
1654 struct GNUNET_TIME_Relative left;
1574 1655
1575 s->timeout_task = GNUNET_SCHEDULER_NO_TASK; 1656 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1657 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1658 if (0 != left.rel_value_us)
1659 {
1660 /* not actually our turn yet, but let's at least update
1661 the monitor, it may think we're about to die ... */
1662 notify_session_monitor (s->plugin,
1663 s,
1664 GNUNET_TRANSPORT_SS_UP);
1665 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1666 &client_session_timeout,
1667 s);
1668 return;
1669 }
1576 LOG (TIMEOUT_LOG, 1670 LOG (TIMEOUT_LOG,
1577 "Session %p was idle for %s, disconnecting\n", 1671 "Session %p was idle for %s, disconnecting\n",
1578 s, 1672 s,
1579 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT, 1673 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT,
1580 GNUNET_YES)); 1674 GNUNET_YES));
1581 1675 GNUNET_assert (GNUNET_OK ==
1582 /* call session destroy function */ 1676 http_client_session_disconnect (s->plugin,
1583 GNUNET_assert (GNUNET_OK == http_client_session_disconnect (s->plugin, 1677 s));
1584 s));
1585} 1678}
1586 1679
1587 1680
@@ -1661,14 +1754,16 @@ http_client_plugin_get_session (void *cls,
1661 s->put_paused = GNUNET_NO; 1754 s->put_paused = GNUNET_NO;
1662 s->put_tmp_disconnecting = GNUNET_NO; 1755 s->put_tmp_disconnecting = GNUNET_NO;
1663 s->put_tmp_disconnected = GNUNET_NO; 1756 s->put_tmp_disconnected = GNUNET_NO;
1757 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_CLIENT_SESSION_TIMEOUT);
1664 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT, 1758 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT,
1665 &client_session_timeout, 1759 &client_session_timeout,
1666 s); 1760 s);
1667 LOG (GNUNET_ERROR_TYPE_DEBUG, 1761 LOG (GNUNET_ERROR_TYPE_DEBUG,
1668 "Created new session %p for `%s' address `%s''\n", 1762 "Created new session %p for `%s' address `%s''\n",
1669 s, http_common_plugin_address_to_string (NULL, 1763 s,
1670 plugin->protocol, s->address->address, 1764 http_common_plugin_address_to_string (plugin->protocol,
1671 s->address->address_length), 1765 s->address->address,
1766 s->address->address_length),
1672 GNUNET_i2s (&s->target)); 1767 GNUNET_i2s (&s->target));
1673 1768
1674 /* add new session */ 1769 /* add new session */
@@ -1681,8 +1776,8 @@ http_client_plugin_get_session (void *cls,
1681 { 1776 {
1682 LOG (GNUNET_ERROR_TYPE_ERROR, 1777 LOG (GNUNET_ERROR_TYPE_ERROR,
1683 "Cannot connect to peer `%s' address `%s''\n", 1778 "Cannot connect to peer `%s' address `%s''\n",
1684 http_common_plugin_address_to_string (NULL, 1779 http_common_plugin_address_to_string (plugin->protocol,
1685 plugin->protocol, s->address->address, 1780 s->address->address,
1686 s->address->address_length), 1781 s->address->address_length),
1687 GNUNET_i2s (&s->target)); 1782 GNUNET_i2s (&s->target));
1688 client_delete_session (s); 1783 client_delete_session (s);
@@ -1716,23 +1811,15 @@ client_start (struct HTTP_Client_Plugin *plugin)
1716 1811
1717 1812
1718/** 1813/**
1719 * Increment session timeout due to activity for session s 1814 * Increment session timeout due to activity for session @a s.
1720 * 1815 *
1721 * param s the session 1816 * @param s the session
1722 */ 1817 */
1723static void 1818static void
1724client_reschedule_session_timeout (struct Session *s) 1819client_reschedule_session_timeout (struct Session *s)
1725{ 1820{
1726 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); 1821 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
1727 GNUNET_SCHEDULER_cancel (s->timeout_task); 1822 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1728 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT,
1729 &client_session_timeout,
1730 s);
1731 LOG (TIMEOUT_LOG,
1732 "Timeout rescheduled for session %p set to %s\n",
1733 s,
1734 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT,
1735 GNUNET_YES));
1736} 1823}
1737 1824
1738 1825
@@ -1753,8 +1840,6 @@ http_client_plugin_address_suggested (void *cls,
1753 const void *addr, 1840 const void *addr,
1754 size_t addrlen) 1841 size_t addrlen)
1755{ 1842{
1756 /* struct Plugin *plugin = cls; */
1757
1758 /* A HTTP/S client does not have any valid address so:*/ 1843 /* A HTTP/S client does not have any valid address so:*/
1759 return GNUNET_NO; 1844 return GNUNET_NO;
1760} 1845}
@@ -1917,31 +2002,107 @@ client_configure_plugin (struct HTTP_Client_Plugin *plugin)
1917} 2002}
1918 2003
1919 2004
2005/**
2006 * Function called by the pretty printer for the resolved address for
2007 * each human-readable address obtained. The callback can be called
2008 * several times. The last invocation must be with a @a address of
2009 * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion
2010 * errors, the callback might be called first with @a address NULL and
2011 * @a res being #GNUNET_SYSERR. In that case, there must still be a
2012 * subsequent call later with @a address NULL and @a res #GNUNET_OK.
2013 *
2014 * @param cls closure
2015 * @param address one of the names for the host, NULL on last callback
2016 * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on failure,
2017 * #GNUNET_OK on last callback
2018 */
1920static const char * 2019static const char *
1921http_plugin_address_to_string (void *cls, 2020http_client_plugin_address_to_string (void *cls,
1922 const void *addr, 2021 const void *addr,
1923 size_t addrlen) 2022 size_t addrlen)
1924{ 2023{
1925 return http_common_plugin_address_to_string (cls, 2024 return http_common_plugin_address_to_string (PLUGIN_NAME,
1926 PLUGIN_NAME,
1927 addr, 2025 addr,
1928 addrlen); 2026 addrlen);
1929} 2027}
1930 2028
1931 2029
2030/**
2031 * Function that will be called whenever the transport service wants to
2032 * notify the plugin that a session is still active and in use and
2033 * therefore the session timeout for this session has to be updated
2034 *
2035 * @param cls closure
2036 * @param peer which peer was the session for
2037 * @param session which session is being updated
2038 */
1932static void 2039static void
1933http_client_plugin_update_session_timeout (void *cls, 2040http_client_plugin_update_session_timeout (void *cls,
1934 const struct GNUNET_PeerIdentity *peer, 2041 const struct GNUNET_PeerIdentity *peer,
1935 struct Session *session) 2042 struct Session *session)
1936{ 2043{
1937 // struct HTTP_Client_Plugin *plugin = cls;
1938
1939 /* lookup if session is really existing */
1940 client_reschedule_session_timeout (session); 2044 client_reschedule_session_timeout (session);
1941} 2045}
1942 2046
1943 2047
1944/** 2048/**
2049 * Return information about the given session to the
2050 * monitor callback.
2051 *
2052 * @param cls the `struct Plugin` with the monitor callback (`sic`)
2053 * @param peer peer we send information about
2054 * @param value our `struct Session` to send information about
2055 * @return #GNUNET_OK (continue to iterate)
2056 */
2057static int
2058send_session_info_iter (void *cls,
2059 const struct GNUNET_PeerIdentity *peer,
2060 void *value)
2061{
2062 struct HTTP_Client_Plugin *plugin = cls;
2063 struct Session *session = value;
2064
2065 notify_session_monitor (plugin,
2066 session,
2067 GNUNET_TRANSPORT_SS_UP);
2068 return GNUNET_OK;
2069}
2070
2071
2072/**
2073 * Begin monitoring sessions of a plugin. There can only
2074 * be one active monitor per plugin (i.e. if there are
2075 * multiple monitors, the transport service needs to
2076 * multiplex the generated events over all of them).
2077 *
2078 * @param cls closure of the plugin
2079 * @param sic callback to invoke, NULL to disable monitor;
2080 * plugin will being by iterating over all active
2081 * sessions immediately and then enter monitor mode
2082 * @param sic_cls closure for @a sic
2083 */
2084static void
2085http_client_plugin_setup_monitor (void *cls,
2086 GNUNET_TRANSPORT_SessionInfoCallback sic,
2087 void *sic_cls)
2088{
2089 struct HTTP_Client_Plugin *plugin = cls;
2090
2091 plugin->sic = sic;
2092 plugin->sic_cls = sic_cls;
2093 if (NULL != sic)
2094 {
2095 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2096 &send_session_info_iter,
2097 plugin);
2098 /* signal end of first iteration */
2099 sic (sic_cls, NULL, NULL);
2100 }
2101}
2102
2103
2104
2105/**
1945 * Entry point for the plugin. 2106 * Entry point for the plugin.
1946 */ 2107 */
1947void * 2108void *
@@ -1957,7 +2118,7 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1957 initialze the plugin or the API */ 2118 initialze the plugin or the API */
1958 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); 2119 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
1959 api->cls = NULL; 2120 api->cls = NULL;
1960 api->address_to_string = &http_plugin_address_to_string; 2121 api->address_to_string = &http_client_plugin_address_to_string;
1961 api->string_to_address = &http_common_plugin_string_to_address; 2122 api->string_to_address = &http_common_plugin_string_to_address;
1962 api->address_pretty_printer = &http_common_plugin_address_pretty_printer; 2123 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
1963 return api; 2124 return api;
@@ -1975,12 +2136,12 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1975 api->disconnect_peer = &http_client_peer_disconnect; 2136 api->disconnect_peer = &http_client_peer_disconnect;
1976 api->check_address = &http_client_plugin_address_suggested; 2137 api->check_address = &http_client_plugin_address_suggested;
1977 api->get_session = &http_client_plugin_get_session; 2138 api->get_session = &http_client_plugin_get_session;
1978 api->address_to_string = &http_plugin_address_to_string; 2139 api->address_to_string = &http_client_plugin_address_to_string;
1979 api->string_to_address = &http_common_plugin_string_to_address; 2140 api->string_to_address = &http_common_plugin_string_to_address;
1980 api->address_pretty_printer = &http_common_plugin_address_pretty_printer; 2141 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
1981 api->get_network = &http_client_get_network; 2142 api->get_network = &http_client_get_network;
1982 api->update_session_timeout = &http_client_plugin_update_session_timeout; 2143 api->update_session_timeout = &http_client_plugin_update_session_timeout;
1983 2144 api->setup_monitor = &http_client_plugin_setup_monitor;
1984#if BUILD_HTTPS 2145#if BUILD_HTTPS
1985 plugin->name = "transport-https_client"; 2146 plugin->name = "transport-https_client";
1986 plugin->protocol = "https"; 2147 plugin->protocol = "https";