aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-06-25 14:14:16 +0000
committerChristian Grothoff <christian@grothoff.org>2014-06-25 14:14:16 +0000
commitb9b0323eefcc0a595f56635be5b66de687650ae0 (patch)
tree63017efb9b00c59d174d025242c77b425ce6f402 /src/transport
parentca7daa5556bce347ce55933a831a8a402231ae48 (diff)
downloadgnunet-b9b0323eefcc0a595f56635be5b66de687650ae0.tar.gz
gnunet-b9b0323eefcc0a595f56635be5b66de687650ae0.zip
-add monitor support to http server, more code clean up, add http server MHD suspend feature, support quota reset API from transport in HTTP server
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/plugin_transport_http_client.c308
-rw-r--r--src/transport/plugin_transport_http_server.c370
2 files changed, 407 insertions, 271 deletions
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
index 68b25afe5..593b063ab 100644
--- a/src/transport/plugin_transport_http_client.c
+++ b/src/transport/plugin_transport_http_client.c
@@ -156,9 +156,10 @@ struct Session
156 struct HTTP_Client_Plugin *plugin; 156 struct HTTP_Client_Plugin *plugin;
157 157
158 /** 158 /**
159 * Client send handle 159 * Curl client PUT handle.
160 * FIXME: delta to put.easyhandle?
160 */ 161 */
161 void *client_put; 162 CURL *client_put;
162 163
163 /** 164 /**
164 * Handle for the HTTP PUT request. 165 * Handle for the HTTP PUT request.
@@ -166,14 +167,15 @@ struct Session
166 struct ConnectionHandle put; 167 struct ConnectionHandle put;
167 168
168 /** 169 /**
169 * Handle for the HTTP GET request. 170 * Curl client GET handle
171 * FIXME: delta to get.easyhandle?
170 */ 172 */
171 struct ConnectionHandle get; 173 CURL *client_get;
172 174
173 /** 175 /**
174 * Client receive handle 176 * Handle for the HTTP GET request.
175 */ 177 */
176 void *client_get; 178 struct ConnectionHandle get;
177 179
178 /** 180 /**
179 * next pointer for double linked list 181 * next pointer for double linked list
@@ -415,6 +417,7 @@ client_delete_session (struct Session *s)
415 struct HTTP_Client_Plugin *plugin = s->plugin; 417 struct HTTP_Client_Plugin *plugin = s->plugin;
416 struct HTTP_Message *pos; 418 struct HTTP_Message *pos;
417 struct HTTP_Message *next; 419 struct HTTP_Message *next;
420 CURLMcode mret;
418 421
419 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) 422 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
420 { 423 {
@@ -427,11 +430,49 @@ client_delete_session (struct Session *s)
427 GNUNET_SCHEDULER_cancel (s->put_disconnect_task); 430 GNUNET_SCHEDULER_cancel (s->put_disconnect_task);
428 s->put_disconnect_task = GNUNET_SCHEDULER_NO_TASK; 431 s->put_disconnect_task = GNUNET_SCHEDULER_NO_TASK;
429 } 432 }
433 if (GNUNET_SCHEDULER_NO_TASK != s->recv_wakeup_task)
434 {
435 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
436 s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
437 }
430 GNUNET_assert (GNUNET_OK == 438 GNUNET_assert (GNUNET_OK ==
431 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, 439 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
432 &s->target, 440 &s->target,
433 s)); 441 s));
442 if (NULL != s->client_put)
443 {
444 LOG (GNUNET_ERROR_TYPE_DEBUG,
445 "Session %p/connection %p: disconnecting PUT connection to peer `%s'\n",
446 s,
447 s->client_put,
448 GNUNET_i2s (&s->target));
434 449
450 /* remove curl handle from multi handle */
451 mret = curl_multi_remove_handle (plugin->curl_multi_handle,
452 s->client_put);
453 GNUNET_break (CURLM_OK == mret);
454 curl_easy_cleanup (s->client_put);
455 s->client_put = NULL;
456 }
457 if (NULL != s->client_get)
458 {
459 LOG (GNUNET_ERROR_TYPE_DEBUG,
460 "Session %p/connection %p: disconnecting GET connection to peer `%s'\n",
461 s, s->client_get,
462 GNUNET_i2s (&s->target));
463 /* remove curl handle from multi handle */
464 mret = curl_multi_remove_handle (plugin->curl_multi_handle,
465 s->client_get);
466 GNUNET_break (CURLM_OK == mret);
467 curl_easy_cleanup (s->client_get);
468 GNUNET_assert (plugin->cur_connections > 0);
469 plugin->cur_connections--;
470 s->client_get = NULL;
471 }
472 GNUNET_STATISTICS_set (plugin->env->stats,
473 HTTP_STAT_STR_CONNECTIONS,
474 plugin->cur_connections,
475 GNUNET_NO);
435 next = s->msg_head; 476 next = s->msg_head;
436 while (NULL != (pos = next)) 477 while (NULL != (pos = next))
437 { 478 {
@@ -757,86 +798,12 @@ http_client_plugin_session_disconnect (void *cls,
757 struct Session *s) 798 struct Session *s)
758{ 799{
759 struct HTTP_Client_Plugin *plugin = cls; 800 struct HTTP_Client_Plugin *plugin = cls;
760 struct HTTP_Message *msg;
761 struct HTTP_Message *t;
762 int res = GNUNET_OK;
763 CURLMcode mret;
764
765 if (NULL != s->client_put)
766 {
767 LOG (GNUNET_ERROR_TYPE_DEBUG,
768 "Session %p/connection %p: disconnecting PUT connection to peer `%s'\n",
769 s,
770 s->client_put,
771 GNUNET_i2s (&s->target));
772 801
773 /* remove curl handle from multi handle */
774 mret = curl_multi_remove_handle (plugin->curl_multi_handle,
775 s->client_put);
776 if (mret != CURLM_OK)
777 {
778 /* clean up easy handle, handle is now invalid and free'd */
779 res = GNUNET_SYSERR;
780 GNUNET_break (0);
781 }
782 curl_easy_cleanup (s->client_put);
783 s->client_put = NULL;
784 }
785
786
787 if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK)
788 {
789 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
790 s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
791 }
792
793 if (NULL != s->client_get)
794 {
795 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "Session %p/connection %p: disconnecting GET connection to peer `%s'\n",
797 s, s->client_get,
798 GNUNET_i2s (&s->target));
799 /* remove curl handle from multi handle */
800 mret = curl_multi_remove_handle (plugin->curl_multi_handle, s->client_get);
801 if (mret != CURLM_OK)
802 {
803 /* clean up easy handle, handle is now invalid and free'd */
804 res = GNUNET_SYSERR;
805 GNUNET_break (0);
806 }
807 curl_easy_cleanup (s->client_get);
808 s->client_get = NULL;
809 }
810
811 msg = s->msg_head;
812 while (NULL != msg)
813 {
814 t = msg->next;
815 if (NULL != msg->transmit_cont)
816 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR,
817 msg->size, msg->pos + s->overhead);
818 s->overhead = 0;
819 GNUNET_CONTAINER_DLL_remove (s->msg_head,
820 s->msg_tail,
821 msg);
822 GNUNET_assert (0 < s->msgs_in_queue);
823 s->msgs_in_queue--;
824 GNUNET_assert (msg->size <= s->bytes_in_queue);
825 s->bytes_in_queue -= msg->size;
826 GNUNET_free (msg);
827 msg = t;
828 }
829
830 GNUNET_assert (plugin->cur_connections >= 2);
831 plugin->cur_connections -= 2;
832 GNUNET_STATISTICS_set (plugin->env->stats,
833 HTTP_STAT_STR_CONNECTIONS,
834 plugin->cur_connections,
835 GNUNET_NO);
836 LOG (GNUNET_ERROR_TYPE_DEBUG, 802 LOG (GNUNET_ERROR_TYPE_DEBUG,
837 "Session %p: notifying transport about ending session\n",s); 803 "Session %p: notifying transport about ending session\n",s);
838 804 plugin->env->session_end (plugin->env->cls,
839 plugin->env->session_end (plugin->env->cls, s->address, s); 805 s->address,
806 s);
840 client_delete_session (s); 807 client_delete_session (s);
841 808
842 /* Re-schedule since handles have changed */ 809 /* Re-schedule since handles have changed */
@@ -847,7 +814,7 @@ http_client_plugin_session_disconnect (void *cls,
847 } 814 }
848 client_schedule (plugin, GNUNET_YES); 815 client_schedule (plugin, GNUNET_YES);
849 816
850 return res; 817 return GNUNET_OK;
851} 818}
852 819
853 820
@@ -993,11 +960,13 @@ client_put_disconnect (void *cls,
993 s->put_disconnect_task = GNUNET_SCHEDULER_NO_TASK; 960 s->put_disconnect_task = GNUNET_SCHEDULER_NO_TASK;
994 LOG (GNUNET_ERROR_TYPE_DEBUG, 961 LOG (GNUNET_ERROR_TYPE_DEBUG,
995 "Session %p/connection %p: will be disconnected due to no activity\n", 962 "Session %p/connection %p: will be disconnected due to no activity\n",
996 s, s->client_put); 963 s,
964 s->client_put);
997 s->put_paused = GNUNET_NO; 965 s->put_paused = GNUNET_NO;
998 s->put_tmp_disconnecting = GNUNET_YES; 966 s->put_tmp_disconnecting = GNUNET_YES;
999 if (NULL != s->client_put) 967 if (NULL != s->client_put)
1000 curl_easy_pause (s->client_put, CURLPAUSE_CONT); 968 curl_easy_pause (s->client_put,
969 CURLPAUSE_CONT);
1001 client_schedule (s->plugin, GNUNET_YES); 970 client_schedule (s->plugin, GNUNET_YES);
1002} 971}
1003 972
@@ -1284,24 +1253,23 @@ client_run (void *cls,
1284 int running; 1253 int running;
1285 long http_statuscode; 1254 long http_statuscode;
1286 CURLMcode mret; 1255 CURLMcode mret;
1256 CURLMsg *msg;
1257 int msgs_left;
1287 1258
1288 plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; 1259 plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
1289 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 1260 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1290 return; 1261 return;
1291
1292 do 1262 do
1293 { 1263 {
1294 running = 0; 1264 running = 0;
1295 mret = curl_multi_perform (plugin->curl_multi_handle, &running); 1265 mret = curl_multi_perform (plugin->curl_multi_handle, &running);
1296 1266
1297 CURLMsg *msg;
1298 int msgs_left;
1299 1267
1300 while ((msg = curl_multi_info_read (plugin->curl_multi_handle, &msgs_left))) 1268 while ((msg = curl_multi_info_read (plugin->curl_multi_handle, &msgs_left)))
1301 { 1269 {
1302 CURL *easy_h = msg->easy_handle; 1270 CURL *easy_h = msg->easy_handle;
1303 struct Session *s = NULL; 1271 struct Session *s = NULL;
1304 char *d = (char *) s; 1272 char *d = NULL; /* curl requires 'd' to be a 'char *' */
1305 1273
1306 if (NULL == easy_h) 1274 if (NULL == easy_h)
1307 { 1275 {
@@ -1316,80 +1284,88 @@ client_run (void *cls,
1316 GNUNET_assert (CURLE_OK == 1284 GNUNET_assert (CURLE_OK ==
1317 curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); 1285 curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d));
1318 s = (struct Session *) d; 1286 s = (struct Session *) d;
1319 GNUNET_assert (s != NULL); 1287 GNUNET_assert (NULL != s);
1320 if (msg->msg == CURLMSG_DONE) 1288 if (msg->msg == CURLMSG_DONE)
1321 { 1289 {
1322 GNUNET_break (CURLE_OK == curl_easy_getinfo (easy_h, 1290 GNUNET_break (CURLE_OK ==
1323 CURLINFO_RESPONSE_CODE, &http_statuscode)); 1291curl_easy_getinfo (easy_h,
1292 CURLINFO_RESPONSE_CODE,
1293 &http_statuscode));
1324 if (easy_h == s->client_put) 1294 if (easy_h == s->client_put)
1325 { 1295 {
1326 if ((0 != msg->data.result) || (http_statuscode != 200)) 1296 if ((0 != msg->data.result) || (http_statuscode != 200))
1327 { 1297 {
1328 LOG (GNUNET_ERROR_TYPE_DEBUG, 1298 LOG (GNUNET_ERROR_TYPE_DEBUG,
1329 "Session %p/connection %p: PUT connection to `%s' ended with status %i reason %i: `%s'\n", 1299 "Session %p/connection %p: PUT connection to `%s' ended with status %i reason %i: `%s'\n",
1330 s, msg->easy_handle, 1300 s, msg->easy_handle,
1331 GNUNET_i2s (&s->target), 1301 GNUNET_i2s (&s->target),
1332 http_statuscode, 1302 http_statuscode,
1333 msg->data.result, 1303 msg->data.result,
1334 curl_easy_strerror (msg->data.result)); 1304 curl_easy_strerror (msg->data.result));
1335 } 1305 }
1336 else 1306 else
1337 LOG (GNUNET_ERROR_TYPE_DEBUG, 1307 LOG (GNUNET_ERROR_TYPE_DEBUG,
1338 "Session %p/connection %p: PUT connection to `%s' ended normal\n", 1308 "Session %p/connection %p: PUT connection to `%s' ended normal\n",
1339 s, msg->easy_handle, 1309 s, msg->easy_handle,
1340 GNUNET_i2s (&s->target)); 1310 GNUNET_i2s (&s->target));
1341 if (NULL == s->client_get) 1311 if (NULL == s->client_get)
1342 { 1312 {
1343 /* Disconnect other transmission direction and tell transport */ 1313 /* Disconnect other transmission direction and tell transport */
1344 /* FIXME? */ 1314 /* FIXME? */
1345 } 1315 }
1346 curl_multi_remove_handle (plugin->curl_multi_handle, easy_h); 1316 curl_multi_remove_handle (plugin->curl_multi_handle,
1347 curl_easy_cleanup (easy_h); 1317 easy_h);
1348 s->put_tmp_disconnecting = GNUNET_NO; 1318 curl_easy_cleanup (easy_h);
1349 s->put_tmp_disconnected = GNUNET_YES; 1319 GNUNET_assert (plugin->cur_connections > 0);
1350 s->client_put = NULL; 1320 plugin->cur_connections--;
1351 s->put.easyhandle = NULL; 1321 s->put_tmp_disconnecting = GNUNET_NO;
1352 s->put.s = NULL; 1322 s->put_tmp_disconnected = GNUNET_YES;
1353 1323 s->client_put = NULL;
1354 /* 1324 s->put.easyhandle = NULL;
1355 * Handling a rare case: 1325 s->put.s = NULL;
1356 * plugin_send was called during temporary put disconnect, 1326
1357 * reconnect required after connection was disconnected 1327 /*
1358 */ 1328 * Handling a rare case:
1359 if (GNUNET_YES == s->put_reconnect_required) 1329 * plugin_send was called during temporary put disconnect,
1330 * reconnect required after connection was disconnected
1331 */
1332 if (GNUNET_YES == s->put_reconnect_required)
1333 {
1334 s->put_reconnect_required = GNUNET_NO;
1335 if (GNUNET_SYSERR == client_connect_put (s))
1360 { 1336 {
1361 s->put_reconnect_required = GNUNET_NO; 1337 GNUNET_break (s->client_put == NULL);
1362 if (GNUNET_SYSERR == client_connect_put (s)) 1338 GNUNET_break (s->put_tmp_disconnected == GNUNET_NO);
1363 {
1364 GNUNET_break (s->client_put == NULL);
1365 GNUNET_break (s->put_tmp_disconnected == GNUNET_NO);
1366 }
1367 } 1339 }
1340 }
1368 } 1341 }
1369 if (easy_h == s->client_get) 1342 if (easy_h == s->client_get)
1370 { 1343 {
1371 if ((0 != msg->data.result) || (http_statuscode != 200)) 1344 if ((0 != msg->data.result) || (http_statuscode != 200))
1372 { 1345 {
1373 LOG (GNUNET_ERROR_TYPE_DEBUG, 1346 LOG (GNUNET_ERROR_TYPE_DEBUG,
1374 "Session %p/connection %p: GET connection to `%s' ended with status %i reason %i: `%s'\n", 1347 "Session %p/connection %p: GET connection to `%s' ended with status %i reason %i: `%s'\n",
1375 s, 1348 s,
1376 msg->easy_handle, 1349 msg->easy_handle,
1377 GNUNET_i2s (&s->target), 1350 GNUNET_i2s (&s->target),
1378 http_statuscode, 1351 http_statuscode,
1379 msg->data.result, 1352 msg->data.result,
1380 curl_easy_strerror (msg->data.result)); 1353 curl_easy_strerror (msg->data.result));
1381 1354
1382 } 1355 }
1383 else 1356 else
1384 LOG (GNUNET_ERROR_TYPE_DEBUG, 1357 LOG (GNUNET_ERROR_TYPE_DEBUG,
1385 "Session %p/connection %p: GET connection to `%s' ended normal\n", 1358 "Session %p/connection %p: GET connection to `%s' ended normal\n",
1386 s, 1359 s,
1387 msg->easy_handle, 1360 msg->easy_handle,
1388 GNUNET_i2s (&s->target)); 1361 GNUNET_i2s (&s->target));
1389 /* Disconnect other transmission direction and tell transport */ 1362 /* Disconnect other transmission direction and tell transport */
1390 s->get.easyhandle = NULL; 1363 s->get.easyhandle = NULL;
1391 s->get.s = NULL; 1364 s->get.s = NULL;
1392 http_client_plugin_session_disconnect (plugin, s); 1365 /* FIXME: who calls curl_multi_remove on 'easy_h' now!? */
1366 GNUNET_assert (plugin->cur_connections > 0);
1367 plugin->cur_connections--;
1368 http_client_plugin_session_disconnect (plugin, s);
1393 } 1369 }
1394 } 1370 }
1395 } 1371 }
@@ -1423,6 +1399,7 @@ client_connect_get (struct Session *s)
1423 curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); 1399 curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
1424 { 1400 {
1425 struct HttpAddress *ha; 1401 struct HttpAddress *ha;
1402
1426 ha = (struct HttpAddress *) s->address->address; 1403 ha = (struct HttpAddress *) s->address->address;
1427 1404
1428 if (HTTP_OPTIONS_VERIFY_CERTIFICATE == 1405 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
@@ -1444,7 +1421,7 @@ client_connect_get (struct Session *s)
1444 curl_easy_setopt (s->client_get, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP); 1421 curl_easy_setopt (s->client_get, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP);
1445#endif 1422#endif
1446 1423
1447 if (s->plugin->proxy_hostname != NULL) 1424 if (NULL != s->plugin->proxy_hostname)
1448 { 1425 {
1449 curl_easy_setopt (s->client_get, CURLOPT_PROXY, s->plugin->proxy_hostname); 1426 curl_easy_setopt (s->client_get, CURLOPT_PROXY, s->plugin->proxy_hostname);
1450 curl_easy_setopt (s->client_get, CURLOPT_PROXYTYPE, s->plugin->proxytype); 1427 curl_easy_setopt (s->client_get, CURLOPT_PROXYTYPE, s->plugin->proxytype);
@@ -1478,8 +1455,9 @@ client_connect_get (struct Session *s)
1478#endif 1455#endif
1479 curl_easy_setopt (s->client_get, CURLOPT_FOLLOWLOCATION, 0); 1456 curl_easy_setopt (s->client_get, CURLOPT_FOLLOWLOCATION, 0);
1480 1457
1481 mret = curl_multi_add_handle (s->plugin->curl_multi_handle, s->client_get); 1458 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1482 if (mret != CURLM_OK) 1459 s->client_get);
1460 if (CURLM_OK != mret)
1483 { 1461 {
1484 LOG (GNUNET_ERROR_TYPE_ERROR, 1462 LOG (GNUNET_ERROR_TYPE_ERROR,
1485 "Session %p : Failed to add GET handle to multihandle: `%s'\n", 1463 "Session %p : Failed to add GET handle to multihandle: `%s'\n",
@@ -1492,7 +1470,7 @@ client_connect_get (struct Session *s)
1492 GNUNET_break (0); 1470 GNUNET_break (0);
1493 return GNUNET_SYSERR; 1471 return GNUNET_SYSERR;
1494 } 1472 }
1495 1473 s->plugin->cur_connections++;
1496 return GNUNET_OK; 1474 return GNUNET_OK;
1497} 1475}
1498 1476
@@ -1576,8 +1554,9 @@ client_connect_put (struct Session *s)
1576#if CURL_TCP_NODELAY 1554#if CURL_TCP_NODELAY
1577 curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); 1555 curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1);
1578#endif 1556#endif
1579 mret = curl_multi_add_handle (s->plugin->curl_multi_handle, s->client_put); 1557 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1580 if (mret != CURLM_OK) 1558 s->client_put);
1559 if (CURLM_OK != mret)
1581 { 1560 {
1582 LOG (GNUNET_ERROR_TYPE_ERROR, 1561 LOG (GNUNET_ERROR_TYPE_ERROR,
1583 "Session %p : Failed to add PUT handle to multihandle: `%s'\n", 1562 "Session %p : Failed to add PUT handle to multihandle: `%s'\n",
@@ -1591,6 +1570,8 @@ client_connect_put (struct Session *s)
1591 return GNUNET_SYSERR; 1570 return GNUNET_SYSERR;
1592 } 1571 }
1593 s->put_tmp_disconnected = GNUNET_NO; 1572 s->put_tmp_disconnected = GNUNET_NO;
1573 s->plugin->cur_connections++;
1574
1594 return GNUNET_OK; 1575 return GNUNET_OK;
1595} 1576}
1596 1577
@@ -1632,11 +1613,7 @@ client_connect (struct Session *s)
1632 1613
1633 if ((GNUNET_SYSERR == client_connect_get (s)) || 1614 if ((GNUNET_SYSERR == client_connect_get (s)) ||
1634 (GNUNET_SYSERR == client_connect_put (s))) 1615 (GNUNET_SYSERR == client_connect_put (s)))
1635 {
1636 plugin->env->session_end (plugin->env->cls, s->address, s);
1637 client_delete_session (s);
1638 return GNUNET_SYSERR; 1616 return GNUNET_SYSERR;
1639 }
1640 1617
1641 LOG (GNUNET_ERROR_TYPE_DEBUG, 1618 LOG (GNUNET_ERROR_TYPE_DEBUG,
1642 "Session %p: connected with connections GET %p and PUT %p\n", 1619 "Session %p: connected with connections GET %p and PUT %p\n",
@@ -1644,7 +1621,6 @@ client_connect (struct Session *s)
1644 s->client_get, 1621 s->client_get,
1645 s->client_put); 1622 s->client_put);
1646 /* Perform connect */ 1623 /* Perform connect */
1647 plugin->cur_connections += 2;
1648 GNUNET_STATISTICS_set (plugin->env->stats, 1624 GNUNET_STATISTICS_set (plugin->env->stats,
1649 HTTP_STAT_STR_CONNECTIONS, 1625 HTTP_STAT_STR_CONNECTIONS,
1650 plugin->cur_connections, 1626 plugin->cur_connections,
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"));