aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/gnunet-service-core_kx.c197
-rw-r--r--src/datacache/datacache.c3
-rw-r--r--src/datacache/plugin_datacache_heap.c143
-rw-r--r--src/datacache/plugin_datacache_postgres.c2
-rw-r--r--src/datacache/plugin_datacache_sqlite.c94
-rw-r--r--src/datacache/plugin_datacache_template.c2
-rw-r--r--src/datacache/test_datacache.c10
-rw-r--r--src/datacache/test_datacache_quota.c10
-rw-r--r--src/dht/gnunet-dht-get.c22
-rw-r--r--src/dht/gnunet-dht-monitor.c27
-rw-r--r--src/dht/gnunet-service-dht_datacache.c6
-rw-r--r--src/dht/gnunet-service-dht_neighbours.c14
-rw-r--r--src/dht/gnunet-service-dht_neighbours.h22
-rw-r--r--src/gns/gnunet-bcd.c22
-rw-r--r--src/gns/gnunet-gns-proxy.c16
-rw-r--r--src/gns/gnunet-service-gns_resolver.c2
-rw-r--r--src/hostlist/gnunet-daemon-hostlist_client.c65
-rw-r--r--src/include/gnunet_core_service.h2
-rw-r--r--src/include/gnunet_datacache_lib.h2
-rw-r--r--src/include/gnunet_datacache_plugin.h2
-rw-r--r--src/include/gnunet_getopt_lib.h17
-rw-r--r--src/include/gnunet_protocols.h6
-rw-r--r--src/peerinfo/peerinfo_api.c3
-rw-r--r--src/topology/gnunet-daemon-topology.c31
-rw-r--r--src/transport/Makefile.am31
-rw-r--r--src/transport/gnunet-service-transport_validation.c13
-rw-r--r--src/transport/plugin_transport_xt.c4107
-rw-r--r--src/transport/plugin_transport_xu.c2492
-rw-r--r--src/transport/plugin_transport_xu.h273
-rw-r--r--src/transport/transport.conf.in37
-rw-r--r--src/util/getopt_helpers.c76
31 files changed, 7543 insertions, 206 deletions
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
index 944d1e692..c29e46997 100644
--- a/src/core/gnunet-service-core_kx.c
+++ b/src/core/gnunet-service-core_kx.c
@@ -448,7 +448,14 @@ derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
448{ 448{
449 static const char ctx[] = "authentication key"; 449 static const char ctx[] = "authentication key";
450 450
451 GNUNET_CRYPTO_hmac_derive_key (akey, skey, 451 struct GNUNET_HashCode sh;
452 GNUNET_CRYPTO_hash (skey, sizeof (*skey), &sh);
453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454 "Deriving Auth key from SKEY %s and seed %u\n",
455 GNUNET_h2s (&sh),
456 (unsigned int) seed);
457 GNUNET_CRYPTO_hmac_derive_key (akey,
458 skey,
452 &seed, sizeof (seed), 459 &seed, sizeof (seed),
453 skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), 460 skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
454 ctx, sizeof (ctx), 461 ctx, sizeof (ctx),
@@ -472,7 +479,15 @@ derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
472{ 479{
473 static const char ctx[] = "initialization vector"; 480 static const char ctx[] = "initialization vector";
474 481
475 GNUNET_CRYPTO_symmetric_derive_iv (iv, skey, 482 struct GNUNET_HashCode sh;
483 GNUNET_CRYPTO_hash (skey, sizeof (*skey), &sh);
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 "Deriving IV from SKEY %s and seed %u for peer %s\n",
486 GNUNET_h2s (&sh),
487 (unsigned int) seed,
488 GNUNET_i2s (identity));
489 GNUNET_CRYPTO_symmetric_derive_iv (iv,
490 skey,
476 &seed, sizeof (seed), 491 &seed, sizeof (seed),
477 identity, 492 identity,
478 sizeof (struct GNUNET_PeerIdentity), ctx, 493 sizeof (struct GNUNET_PeerIdentity), ctx,
@@ -498,7 +513,16 @@ derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
498{ 513{
499 static const char ctx[] = "pong initialization vector"; 514 static const char ctx[] = "pong initialization vector";
500 515
501 GNUNET_CRYPTO_symmetric_derive_iv (iv, skey, 516 struct GNUNET_HashCode sh;
517 GNUNET_CRYPTO_hash (skey, sizeof (*skey), &sh);
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519 "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n",
520 GNUNET_h2s (&sh),
521 (unsigned int) seed,
522 (unsigned int) challenge,
523 GNUNET_i2s (identity));
524 GNUNET_CRYPTO_symmetric_derive_iv (iv,
525 skey,
502 &seed, sizeof (seed), 526 &seed, sizeof (seed),
503 identity, 527 identity,
504 sizeof (struct GNUNET_PeerIdentity), 528 sizeof (struct GNUNET_PeerIdentity),
@@ -524,6 +548,13 @@ derive_aes_key (const struct GNUNET_PeerIdentity *sender,
524{ 548{
525 static const char ctx[] = "aes key generation vector"; 549 static const char ctx[] = "aes key generation vector";
526 550
551 struct GNUNET_HashCode sh;
552 GNUNET_CRYPTO_hash (skey, sizeof (*skey), &sh);
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Deriving AES Keys for %s to %s from %s\n",
555 GNUNET_i2s (sender),
556 GNUNET_i2s2 (receiver),
557 GNUNET_h2s (key_material));
527 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), 558 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
528 ctx, sizeof (ctx), 559 ctx, sizeof (ctx),
529 key_material, sizeof (struct GNUNET_HashCode), 560 key_material, sizeof (struct GNUNET_HashCode),
@@ -939,15 +970,26 @@ handle_ephemeral_key (void *cls,
939 { 970 {
940 GNUNET_STATISTICS_update (GSC_stats, 971 GNUNET_STATISTICS_update (GSC_stats,
941 gettext_noop ("# old ephemeral keys ignored"), 972 gettext_noop ("# old ephemeral keys ignored"),
942 1, GNUNET_NO); 973 1,
974 GNUNET_NO);
975 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
976 "Received expired EPHEMERAL_KEY from %s\n",
977 GNUNET_i2s (&m->origin_identity));
978 return;
979 }
980 if (0 == memcmp (&m->ephemeral_key,
981 &kx->other_ephemeral_key,
982 sizeof (m->ephemeral_key)))
983 {
984 GNUNET_STATISTICS_update (GSC_stats,
985 gettext_noop ("# duplicate ephemeral keys ignored"),
986 1,
987 GNUNET_NO);
988 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
989 "Ignoring duplicate EPHEMERAL_KEY from %s\n",
990 GNUNET_i2s (&m->origin_identity));
943 return; 991 return;
944 } 992 }
945 start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
946
947 GNUNET_STATISTICS_update (GSC_stats,
948 gettext_noop ("# ephemeral keys received"),
949 1, GNUNET_NO);
950
951 if (0 != 993 if (0 !=
952 memcmp (&m->origin_identity, 994 memcmp (&m->origin_identity,
953 kx->peer, 995 kx->peer,
@@ -960,9 +1002,6 @@ handle_ephemeral_key (void *cls,
960 GNUNET_break_op (0); 1002 GNUNET_break_op (0);
961 return; 1003 return;
962 } 1004 }
963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964 "Core service receives EPHEMERAL_KEY request from `%s'.\n",
965 GNUNET_i2s (kx->peer));
966 if ((ntohl (m->purpose.size) != 1005 if ((ntohl (m->purpose.size) !=
967 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + 1006 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
968 sizeof (struct GNUNET_TIME_AbsoluteNBO) + 1007 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
@@ -977,26 +1016,51 @@ handle_ephemeral_key (void *cls,
977 { 1016 {
978 /* invalid signature */ 1017 /* invalid signature */
979 GNUNET_break_op (0); 1018 GNUNET_break_op (0);
1019 GNUNET_STATISTICS_update (GSC_stats,
1020 gettext_noop ("# EPHEMERAL_KEYs rejected (bad signature)"),
1021 1,
1022 GNUNET_NO);
1023 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1024 "Received EPHEMERAL_KEY from %s with bad signature\n",
1025 GNUNET_i2s (&m->origin_identity));
980 return; 1026 return;
981 } 1027 }
982 now = GNUNET_TIME_absolute_get (); 1028 now = GNUNET_TIME_absolute_get ();
1029 start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
983 if ( (end_t.abs_value_us < GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) || 1030 if ( (end_t.abs_value_us < GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
984 (start_t.abs_value_us > GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us) ) 1031 (start_t.abs_value_us > GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us) )
985 { 1032 {
986 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1033 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
987 _("Ephemeral key message from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"), 1034 _("EPHERMAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
988 GNUNET_i2s (kx->peer), 1035 GNUNET_i2s (kx->peer),
989 (unsigned long long) now.abs_value_us, 1036 (unsigned long long) now.abs_value_us,
990 (unsigned long long) start_t.abs_value_us, 1037 (unsigned long long) start_t.abs_value_us,
991 (unsigned long long) end_t.abs_value_us); 1038 (unsigned long long) end_t.abs_value_us);
1039 GNUNET_STATISTICS_update (GSC_stats,
1040 gettext_noop ("# EPHEMERAL_KEY messages rejected due to time"),
1041 1,
1042 GNUNET_NO);
992 return; 1043 return;
993 } 1044 }
1045 {
1046 struct GNUNET_HashCode eh;
1047
1048 GNUNET_CRYPTO_hash (&m->ephemeral_key,
1049 sizeof (m->ephemeral_key),
1050 &eh);
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n",
1053 GNUNET_h2s (&eh),
1054 GNUNET_i2s (kx->peer),
1055 kx->status);
1056 }
1057 GNUNET_STATISTICS_update (GSC_stats,
1058 gettext_noop ("# valid ephemeral keys received"),
1059 1,
1060 GNUNET_NO);
994 kx->other_ephemeral_key = m->ephemeral_key; 1061 kx->other_ephemeral_key = m->ephemeral_key;
995 kx->foreign_key_expires = end_t; 1062 kx->foreign_key_expires = end_t;
996 derive_session_keys (kx); 1063 derive_session_keys (kx);
997 GNUNET_STATISTICS_update (GSC_stats,
998 gettext_noop ("# EPHEMERAL_KEY messages received"), 1,
999 GNUNET_NO);
1000 1064
1001 /* check if we still need to send the sender our key */ 1065 /* check if we still need to send the sender our key */
1002 sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status); 1066 sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status);
@@ -1130,8 +1194,9 @@ handle_ping (void *cls,
1130 { 1194 {
1131 if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status) 1195 if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status)
1132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1196 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1133 "Decryption of PING from peer `%s' failed\n", 1197 "Decryption of PING from peer `%s' failed, PING for `%s'?\n",
1134 GNUNET_i2s (kx->peer)); 1198 GNUNET_i2s (kx->peer),
1199 GNUNET_i2s2 (&t.target));
1135 else 1200 else
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137 "Decryption of PING from peer `%s' failed after rekey (harmless)\n", 1202 "Decryption of PING from peer `%s' failed after rekey (harmless)\n",
@@ -1328,7 +1393,7 @@ handle_pong (void *cls,
1328 return; 1393 return;
1329 } 1394 }
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 "Received PONG from `%s'\n", 1396 "Received valid PONG from `%s'\n",
1332 GNUNET_i2s (kx->peer)); 1397 GNUNET_i2s (kx->peer));
1333 /* no need to resend key any longer */ 1398 /* no need to resend key any longer */
1334 if (NULL != kx->retry_set_key_task) 1399 if (NULL != kx->retry_set_key_task)
@@ -1395,10 +1460,18 @@ send_key (struct GSC_KeyExchangeInfo *kx)
1395 kx->retry_set_key_task = NULL; 1460 kx->retry_set_key_task = NULL;
1396 } 1461 }
1397 /* always update sender status in SET KEY message */ 1462 /* always update sender status in SET KEY message */
1398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1463 {
1399 "Sending key to `%s' (my status: %d)\n", 1464 struct GNUNET_HashCode hc;
1400 GNUNET_i2s (kx->peer), 1465
1401 kx->status); 1466 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1467 sizeof (current_ekm.ephemeral_key),
1468 &hc);
1469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1470 "Sending EPHERMERAL_KEY %s to `%s' (my status: %d)\n",
1471 GNUNET_h2s (&hc),
1472 GNUNET_i2s (kx->peer),
1473 kx->status);
1474 }
1402 current_ekm.sender_status = htonl ((int32_t) (kx->status)); 1475 current_ekm.sender_status = htonl ((int32_t) (kx->status));
1403 env = GNUNET_MQ_msg_copy (&current_ekm.header); 1476 env = GNUNET_MQ_msg_copy (&current_ekm.header);
1404 GNUNET_MQ_send (kx->mq, 1477 GNUNET_MQ_send (kx->mq,
@@ -1454,10 +1527,18 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1454 &ph->sequence_number, 1527 &ph->sequence_number,
1455 &em->sequence_number, 1528 &em->sequence_number,
1456 used - ENCRYPTED_HEADER_SIZE)); 1529 used - ENCRYPTED_HEADER_SIZE));
1457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1530 {
1458 "Encrypted %u bytes for %s\n", 1531 struct GNUNET_HashCode hc;
1459 (unsigned int) (used - ENCRYPTED_HEADER_SIZE), 1532
1460 GNUNET_i2s (kx->peer)); 1533 GNUNET_CRYPTO_hash (&ph->sequence_number,
1534 used - ENCRYPTED_HEADER_SIZE,
1535 &hc);
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1537 "Encrypted payload `%s' of %u bytes for %s\n",
1538 GNUNET_h2s (&hc),
1539 (unsigned int) (used - ENCRYPTED_HEADER_SIZE),
1540 GNUNET_i2s (kx->peer));
1541 }
1461 derive_auth_key (&auth_key, 1542 derive_auth_key (&auth_key,
1462 &kx->encrypt_key, 1543 &kx->encrypt_key,
1463 ph->iv_seed); 1544 ph->iv_seed);
@@ -1465,6 +1546,18 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1465 &em->sequence_number, 1546 &em->sequence_number,
1466 used - ENCRYPTED_HEADER_SIZE, 1547 used - ENCRYPTED_HEADER_SIZE,
1467 &em->hmac); 1548 &em->hmac);
1549 {
1550 struct GNUNET_HashCode hc;
1551
1552 GNUNET_CRYPTO_hash (&auth_key,
1553 sizeof (auth_key),
1554 &hc);
1555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1556 "For peer %s, used AC %s to create hmac %s\n",
1557 GNUNET_i2s (kx->peer),
1558 GNUNET_h2s (&hc),
1559 GNUNET_h2s2 (&em->hmac));
1560 }
1468 kx->has_excess_bandwidth = GNUNET_NO; 1561 kx->has_excess_bandwidth = GNUNET_NO;
1469 GNUNET_MQ_send (kx->mq, 1562 GNUNET_MQ_send (kx->mq,
1470 env); 1563 env);
@@ -1544,6 +1637,19 @@ handle_encrypted (void *cls,
1544 } 1637 }
1545 1638
1546 /* validate hash */ 1639 /* validate hash */
1640 {
1641 struct GNUNET_HashCode hc;
1642
1643 GNUNET_CRYPTO_hash (&m->sequence_number,
1644 size - ENCRYPTED_HEADER_SIZE,
1645 &hc);
1646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1647 "Received encrypted payload `%s' of %u bytes from %s\n",
1648 GNUNET_h2s (&hc),
1649 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1650 GNUNET_i2s (kx->peer));
1651 }
1652
1547 derive_auth_key (&auth_key, 1653 derive_auth_key (&auth_key,
1548 &kx->decrypt_key, 1654 &kx->decrypt_key,
1549 m->iv_seed); 1655 m->iv_seed);
@@ -1551,6 +1657,18 @@ handle_encrypted (void *cls,
1551 &m->sequence_number, 1657 &m->sequence_number,
1552 size - ENCRYPTED_HEADER_SIZE, 1658 size - ENCRYPTED_HEADER_SIZE,
1553 &ph); 1659 &ph);
1660 {
1661 struct GNUNET_HashCode hc;
1662
1663 GNUNET_CRYPTO_hash (&auth_key,
1664 sizeof (auth_key),
1665 &hc);
1666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1667 "For peer %s, used AC %s to verify hmac %s\n",
1668 GNUNET_i2s (kx->peer),
1669 GNUNET_h2s (&hc),
1670 GNUNET_h2s2 (&m->hmac));
1671 }
1554 if (0 != memcmp (&ph, 1672 if (0 != memcmp (&ph,
1555 &m->hmac, 1673 &m->hmac,
1556 sizeof (struct GNUNET_HashCode))) 1674 sizeof (struct GNUNET_HashCode)))
@@ -1742,11 +1860,19 @@ do_rekey (void *cls)
1742 NULL); 1860 NULL);
1743 if (NULL != my_ephemeral_key) 1861 if (NULL != my_ephemeral_key)
1744 GNUNET_free (my_ephemeral_key); 1862 GNUNET_free (my_ephemeral_key);
1745 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1746 "Rekeying\n");
1747 my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create (); 1863 my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
1748 GNUNET_assert (NULL != my_ephemeral_key); 1864 GNUNET_assert (NULL != my_ephemeral_key);
1749 sign_ephemeral_key (); 1865 sign_ephemeral_key ();
1866 {
1867 struct GNUNET_HashCode eh;
1868
1869 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1870 sizeof (current_ekm.ephemeral_key),
1871 &eh);
1872 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1873 "Rekeying to %s\n",
1874 GNUNET_h2s (&eh));
1875 }
1750 for (pos = kx_head; NULL != pos; pos = pos->next) 1876 for (pos = kx_head; NULL != pos; pos = pos->next)
1751 { 1877 {
1752 if (GNUNET_CORE_KX_STATE_UP == pos->status) 1878 if (GNUNET_CORE_KX_STATE_UP == pos->status)
@@ -1807,6 +1933,17 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1807 return GNUNET_SYSERR; 1933 return GNUNET_SYSERR;
1808 } 1934 }
1809 sign_ephemeral_key (); 1935 sign_ephemeral_key ();
1936 {
1937 struct GNUNET_HashCode eh;
1938
1939 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1940 sizeof (current_ekm.ephemeral_key),
1941 &eh);
1942 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1943 "Starting with ephemeral key %s\n",
1944 GNUNET_h2s (&eh));
1945 }
1946
1810 nc = GNUNET_notification_context_create (1); 1947 nc = GNUNET_notification_context_create (1);
1811 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, 1948 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
1812 &do_rekey, 1949 &do_rekey,
diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c
index 0646019bd..7c0a975da 100644
--- a/src/datacache/datacache.c
+++ b/src/datacache/datacache.c
@@ -260,6 +260,7 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
260 * 260 *
261 * @param h handle to the datacache 261 * @param h handle to the datacache
262 * @param key key to store data under 262 * @param key key to store data under
263 * @param xor_distance distance of @a key to our PID
263 * @param data_size number of bytes in @a data 264 * @param data_size number of bytes in @a data
264 * @param data data to store 265 * @param data data to store
265 * @param type type of the value 266 * @param type type of the value
@@ -271,6 +272,7 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
271int 272int
272GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, 273GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
273 const struct GNUNET_HashCode *key, 274 const struct GNUNET_HashCode *key,
275 uint32_t xor_distance,
274 size_t data_size, 276 size_t data_size,
275 const char *data, 277 const char *data,
276 enum GNUNET_BLOCK_Type type, 278 enum GNUNET_BLOCK_Type type,
@@ -282,6 +284,7 @@ GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
282 284
283 used = h->api->put (h->api->cls, 285 used = h->api->put (h->api->cls,
284 key, 286 key,
287 xor_distance,
285 data_size, 288 data_size,
286 data, 289 data,
287 type, 290 type,
diff --git a/src/datacache/plugin_datacache_heap.c b/src/datacache/plugin_datacache_heap.c
index 49e60bca1..ad5e7834d 100644
--- a/src/datacache/plugin_datacache_heap.c
+++ b/src/datacache/plugin_datacache_heap.c
@@ -31,7 +31,7 @@
31 31
32#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn) 32#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-heap", op, fn)
33 33
34 34#define NUM_HEAPS 24
35 35
36/** 36/**
37 * Context for all functions in this plugin. 37 * Context for all functions in this plugin.
@@ -49,9 +49,9 @@ struct Plugin
49 struct GNUNET_CONTAINER_MultiHashMap *map; 49 struct GNUNET_CONTAINER_MultiHashMap *map;
50 50
51 /** 51 /**
52 * Heap for expirations. 52 * Heaps sorted by distance.
53 */ 53 */
54 struct GNUNET_CONTAINER_Heap *heap; 54 struct GNUNET_CONTAINER_Heap *heaps[NUM_HEAPS];
55 55
56}; 56};
57 57
@@ -92,6 +92,11 @@ struct Value
92 unsigned int path_info_len; 92 unsigned int path_info_len;
93 93
94 /** 94 /**
95 * How close is the hash to us? Determines which heap we are in!
96 */
97 uint32_t distance;
98
99 /**
95 * Type of the block. 100 * Type of the block.
96 */ 101 */
97 enum GNUNET_BLOCK_Type type; 102 enum GNUNET_BLOCK_Type type;
@@ -118,11 +123,6 @@ struct PutContext
118 const char *data; 123 const char *data;
119 124
120 /** 125 /**
121 * Heap from the plugin.
122 */
123 struct GNUNET_CONTAINER_Heap *heap;
124
125 /**
126 * Path information. 126 * Path information.
127 */ 127 */
128 const struct GNUNET_PeerIdentity *path_info; 128 const struct GNUNET_PeerIdentity *path_info;
@@ -168,7 +168,9 @@ put_cb (void *cls,
168 168
169 if ( (val->size == put_ctx->size) && 169 if ( (val->size == put_ctx->size) &&
170 (val->type == put_ctx->type) && 170 (val->type == put_ctx->type) &&
171 (0 == memcmp (&val[1], put_ctx->data, put_ctx->size)) ) 171 (0 == memcmp (&val[1],
172 put_ctx->data,
173 put_ctx->size)) )
172 { 174 {
173 put_ctx->found = GNUNET_YES; 175 put_ctx->found = GNUNET_YES;
174 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time, 176 val->discard_time = GNUNET_TIME_absolute_max (val->discard_time,
@@ -178,8 +180,8 @@ put_cb (void *cls,
178 val->path_info_len, 180 val->path_info_len,
179 put_ctx->path_info_len); 181 put_ctx->path_info_len);
180 GNUNET_memcpy (val->path_info, 182 GNUNET_memcpy (val->path_info,
181 put_ctx->path_info, 183 put_ctx->path_info,
182 put_ctx->path_info_len * sizeof (struct GNUNET_PeerIdentity)); 184 put_ctx->path_info_len * sizeof (struct GNUNET_PeerIdentity));
183 GNUNET_CONTAINER_heap_update_cost (val->hn, 185 GNUNET_CONTAINER_heap_update_cost (val->hn,
184 val->discard_time.abs_value_us); 186 val->discard_time.abs_value_us);
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -199,6 +201,7 @@ put_cb (void *cls,
199 * 201 *
200 * @param cls closure (our `struct Plugin`) 202 * @param cls closure (our `struct Plugin`)
201 * @param key key to store data under 203 * @param key key to store data under
204 * @param xor_distance how close is @a key to our PID?
202 * @param size number of bytes in @a data 205 * @param size number of bytes in @a data
203 * @param data data to store 206 * @param data data to store
204 * @param type type of the value 207 * @param type type of the value
@@ -210,6 +213,7 @@ put_cb (void *cls,
210static ssize_t 213static ssize_t
211heap_plugin_put (void *cls, 214heap_plugin_put (void *cls,
212 const struct GNUNET_HashCode *key, 215 const struct GNUNET_HashCode *key,
216 uint32_t xor_distance,
213 size_t size, 217 size_t size,
214 const char *data, 218 const char *data,
215 enum GNUNET_BLOCK_Type type, 219 enum GNUNET_BLOCK_Type type,
@@ -222,7 +226,6 @@ heap_plugin_put (void *cls,
222 struct PutContext put_ctx; 226 struct PutContext put_ctx;
223 227
224 put_ctx.found = GNUNET_NO; 228 put_ctx.found = GNUNET_NO;
225 put_ctx.heap = plugin->heap;
226 put_ctx.data = data; 229 put_ctx.data = data;
227 put_ctx.size = size; 230 put_ctx.size = size;
228 put_ctx.path_info = path_info; 231 put_ctx.path_info = path_info;
@@ -236,22 +239,28 @@ heap_plugin_put (void *cls,
236 if (GNUNET_YES == put_ctx.found) 239 if (GNUNET_YES == put_ctx.found)
237 return 0; 240 return 0;
238 val = GNUNET_malloc (sizeof (struct Value) + size); 241 val = GNUNET_malloc (sizeof (struct Value) + size);
239 GNUNET_memcpy (&val[1], data, size); 242 GNUNET_memcpy (&val[1],
243 data,
244 size);
240 val->key = *key; 245 val->key = *key;
241 val->type = type; 246 val->type = type;
242 val->discard_time = discard_time; 247 val->discard_time = discard_time;
243 val->size = size; 248 val->size = size;
249 if (xor_distance >= NUM_HEAPS)
250 val->distance = NUM_HEAPS - 1;
251 else
252 val->distance = xor_distance;
244 GNUNET_array_grow (val->path_info, 253 GNUNET_array_grow (val->path_info,
245 val->path_info_len, 254 val->path_info_len,
246 path_info_len); 255 path_info_len);
247 GNUNET_memcpy (val->path_info, 256 GNUNET_memcpy (val->path_info,
248 path_info, 257 path_info,
249 path_info_len * sizeof (struct GNUNET_PeerIdentity)); 258 path_info_len * sizeof (struct GNUNET_PeerIdentity));
250 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map, 259 (void) GNUNET_CONTAINER_multihashmap_put (plugin->map,
251 &val->key, 260 &val->key,
252 val, 261 val,
253 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 262 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
254 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heap, 263 val->hn = GNUNET_CONTAINER_heap_insert (plugin->heaps[val->distance],
255 val, 264 val,
256 val->discard_time.abs_value_us); 265 val->discard_time.abs_value_us);
257 return size + OVERHEAD; 266 return size + OVERHEAD;
@@ -369,7 +378,12 @@ heap_plugin_del (void *cls)
369 struct Plugin *plugin = cls; 378 struct Plugin *plugin = cls;
370 struct Value *val; 379 struct Value *val;
371 380
372 val = GNUNET_CONTAINER_heap_remove_root (plugin->heap); 381 for (unsigned int i=0;i<NUM_HEAPS;i++)
382 {
383 val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i]);
384 if (NULL != val)
385 break;
386 }
373 if (NULL == val) 387 if (NULL == val)
374 return GNUNET_SYSERR; 388 return GNUNET_SYSERR;
375 GNUNET_assert (GNUNET_YES == 389 GNUNET_assert (GNUNET_YES ==
@@ -413,6 +427,53 @@ heap_plugin_get_random (void *cls,
413 427
414 428
415/** 429/**
430 * Closure for #find_closest().
431 */
432struct GetClosestContext
433{
434 struct Value **values;
435
436 unsigned int num_results;
437
438 const struct GNUNET_HashCode *key;
439};
440
441
442static int
443find_closest (void *cls,
444 const struct GNUNET_HashCode *key,
445 void *value)
446{
447 struct GetClosestContext *gcc = cls;
448 struct Value *val = value;
449 unsigned int j;
450
451 if (1 != GNUNET_CRYPTO_hash_cmp (key,
452 gcc->key))
453 return GNUNET_OK; /* useless */
454 j = gcc->num_results;
455 for (unsigned int i=0;i<gcc->num_results;i++)
456 {
457 if (NULL == gcc->values[i])
458 {
459 j = i;
460 break;
461 }
462 if (1 == GNUNET_CRYPTO_hash_cmp (&gcc->values[i]->key,
463 key))
464 {
465 j = i;
466 break;
467 }
468 }
469 if (j == gcc->num_results)
470 return GNUNET_OK;
471 gcc->values[j] = val;
472 return GNUNET_OK;
473}
474
475
476/**
416 * Iterate over the results that are "close" to a particular key in 477 * Iterate over the results that are "close" to a particular key in
417 * the datacache. "close" is defined as numerically larger than @a 478 * the datacache. "close" is defined as numerically larger than @a
418 * key (when interpreted as a circular address space), with small 479 * key (when interpreted as a circular address space), with small
@@ -432,8 +493,30 @@ heap_plugin_get_closest (void *cls,
432 GNUNET_DATACACHE_Iterator iter, 493 GNUNET_DATACACHE_Iterator iter,
433 void *iter_cls) 494 void *iter_cls)
434{ 495{
435 GNUNET_break (0); // not implemented! 496 struct Plugin *plugin = cls;
436 return 0; 497 struct Value *values[num_results];
498 struct GetClosestContext gcc = {
499 .values = values,
500 .num_results = num_results,
501 .key = key
502 };
503 GNUNET_CONTAINER_multihashmap_iterate (plugin->map,
504 &find_closest,
505 &gcc);
506 for (unsigned int i=0;i<num_results;i++)
507 {
508 if (NULL == values[i])
509 return i;
510 iter (iter_cls,
511 &values[i]->key,
512 values[i]->size,
513 (void *) &values[i][1],
514 values[i]->type,
515 values[i]->discard_time,
516 values[i]->path_info_len,
517 values[i]->path_info);
518 }
519 return num_results;
437} 520}
438 521
439 522
@@ -453,7 +536,8 @@ libgnunet_plugin_datacache_heap_init (void *cls)
453 plugin = GNUNET_new (struct Plugin); 536 plugin = GNUNET_new (struct Plugin);
454 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */ 537 plugin->map = GNUNET_CONTAINER_multihashmap_create (1024, /* FIXME: base on quota! */
455 GNUNET_YES); 538 GNUNET_YES);
456 plugin->heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); 539 for (unsigned int i=0;i<NUM_HEAPS;i++)
540 plugin->heaps[i] = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
457 plugin->env = env; 541 plugin->env = env;
458 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions); 542 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
459 api->cls = plugin; 543 api->cls = plugin;
@@ -481,16 +565,19 @@ libgnunet_plugin_datacache_heap_done (void *cls)
481 struct Plugin *plugin = api->cls; 565 struct Plugin *plugin = api->cls;
482 struct Value *val; 566 struct Value *val;
483 567
484 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heap))) 568 for (unsigned int i=0;i<NUM_HEAPS;i++)
485 { 569 {
486 GNUNET_assert (GNUNET_YES == 570 while (NULL != (val = GNUNET_CONTAINER_heap_remove_root (plugin->heaps[i])))
487 GNUNET_CONTAINER_multihashmap_remove (plugin->map, 571 {
488 &val->key, 572 GNUNET_assert (GNUNET_YES ==
489 val)); 573 GNUNET_CONTAINER_multihashmap_remove (plugin->map,
490 GNUNET_free_non_null (val->path_info); 574 &val->key,
491 GNUNET_free (val); 575 val));
576 GNUNET_free_non_null (val->path_info);
577 GNUNET_free (val);
578 }
579 GNUNET_CONTAINER_heap_destroy (plugin->heaps[i]);
492 } 580 }
493 GNUNET_CONTAINER_heap_destroy (plugin->heap);
494 GNUNET_CONTAINER_multihashmap_destroy (plugin->map); 581 GNUNET_CONTAINER_multihashmap_destroy (plugin->map);
495 GNUNET_free (plugin); 582 GNUNET_free (plugin);
496 GNUNET_free (api); 583 GNUNET_free (api);
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c
index 2c233c4c2..c6ccfb210 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -141,6 +141,7 @@ init_connection (struct Plugin *plugin)
141 * 141 *
142 * @param cls closure (our `struct Plugin`) 142 * @param cls closure (our `struct Plugin`)
143 * @param key key to store @a data under 143 * @param key key to store @a data under
144 * @param am_closest are we the closest peer?
144 * @param data_size number of bytes in @a data 145 * @param data_size number of bytes in @a data
145 * @param data data to store 146 * @param data data to store
146 * @param type type of the value 147 * @param type type of the value
@@ -152,6 +153,7 @@ init_connection (struct Plugin *plugin)
152static ssize_t 153static ssize_t
153postgres_plugin_put (void *cls, 154postgres_plugin_put (void *cls,
154 const struct GNUNET_HashCode *key, 155 const struct GNUNET_HashCode *key,
156 int am_closest,
155 size_t data_size, 157 size_t data_size,
156 const char *data, 158 const char *data,
157 enum GNUNET_BLOCK_Type type, 159 enum GNUNET_BLOCK_Type type,
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
index 15438b29b..ef24199ca 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -38,7 +38,7 @@
38 * How much overhead do we assume per entry in the 38 * How much overhead do we assume per entry in the
39 * datacache? 39 * datacache?
40 */ 40 */
41#define OVERHEAD (sizeof(struct GNUNET_HashCode) + 32) 41#define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
42 42
43/** 43/**
44 * Context for all functions in this plugin. 44 * Context for all functions in this plugin.
@@ -83,6 +83,11 @@ struct Plugin
83 /** 83 /**
84 * Prepared statement for #sqlite_plugin_del. 84 * Prepared statement for #sqlite_plugin_del.
85 */ 85 */
86 sqlite3_stmt *del_expired_stmt;
87
88 /**
89 * Prepared statement for #sqlite_plugin_del.
90 */
86 sqlite3_stmt *del_stmt; 91 sqlite3_stmt *del_stmt;
87 92
88 /** 93 /**
@@ -150,6 +155,7 @@ sq_prepare (sqlite3 *dbh,
150 * 155 *
151 * @param cls closure (our `struct Plugin`) 156 * @param cls closure (our `struct Plugin`)
152 * @param key key to store @a data under 157 * @param key key to store @a data under
158 * @param xor_distance how close is @a key to our PID?
153 * @param size number of bytes in @a data 159 * @param size number of bytes in @a data
154 * @param data data to store 160 * @param data data to store
155 * @param type type of the value 161 * @param type type of the value
@@ -161,6 +167,7 @@ sq_prepare (sqlite3 *dbh,
161static ssize_t 167static ssize_t
162sqlite_plugin_put (void *cls, 168sqlite_plugin_put (void *cls,
163 const struct GNUNET_HashCode *key, 169 const struct GNUNET_HashCode *key,
170 uint32_t xor_distance,
164 size_t size, 171 size_t size,
165 const char *data, 172 const char *data,
166 enum GNUNET_BLOCK_Type type, 173 enum GNUNET_BLOCK_Type type,
@@ -174,6 +181,7 @@ sqlite_plugin_put (void *cls,
174 GNUNET_SQ_query_param_uint32 (&type32), 181 GNUNET_SQ_query_param_uint32 (&type32),
175 GNUNET_SQ_query_param_absolute_time (&discard_time), 182 GNUNET_SQ_query_param_absolute_time (&discard_time),
176 GNUNET_SQ_query_param_auto_from_type (key), 183 GNUNET_SQ_query_param_auto_from_type (key),
184 GNUNET_SQ_query_param_uint32 (&xor_distance),
177 GNUNET_SQ_query_param_fixed_size (data, size), 185 GNUNET_SQ_query_param_fixed_size (data, size),
178 GNUNET_SQ_query_param_fixed_size (path_info, 186 GNUNET_SQ_query_param_fixed_size (path_info,
179 path_info_len * sizeof (struct GNUNET_PeerIdentity)), 187 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
@@ -387,6 +395,7 @@ sqlite_plugin_del (void *cls)
387 void *data; 395 void *data;
388 size_t dsize; 396 size_t dsize;
389 struct GNUNET_HashCode hc; 397 struct GNUNET_HashCode hc;
398 struct GNUNET_TIME_Absolute now;
390 struct GNUNET_SQ_ResultSpec rs[] = { 399 struct GNUNET_SQ_ResultSpec rs[] = {
391 GNUNET_SQ_result_spec_uint64 (&rowid), 400 GNUNET_SQ_result_spec_uint64 (&rowid),
392 GNUNET_SQ_result_spec_auto_from_type (&hc), 401 GNUNET_SQ_result_spec_auto_from_type (&hc),
@@ -398,27 +407,52 @@ sqlite_plugin_del (void *cls)
398 GNUNET_SQ_query_param_uint64 (&rowid), 407 GNUNET_SQ_query_param_uint64 (&rowid),
399 GNUNET_SQ_query_param_end 408 GNUNET_SQ_query_param_end
400 }; 409 };
410 struct GNUNET_SQ_QueryParam time_params[] = {
411 GNUNET_SQ_query_param_absolute_time (&now),
412 GNUNET_SQ_query_param_end
413 };
401 414
402 LOG (GNUNET_ERROR_TYPE_DEBUG, 415 LOG (GNUNET_ERROR_TYPE_DEBUG,
403 "Processing DEL\n"); 416 "Processing DEL\n");
404 if (SQLITE_ROW != 417 now = GNUNET_TIME_absolute_get ();
405 sqlite3_step (plugin->del_select_stmt)) 418 if (GNUNET_OK !=
419 GNUNET_SQ_bind (plugin->del_expired_stmt,
420 time_params))
406 { 421 {
407 LOG_SQLITE (plugin->dbh, 422 LOG_SQLITE (plugin->dbh,
408 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 423 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
409 "sqlite3_step"); 424 "sqlite3_bind");
410 GNUNET_SQ_reset (plugin->dbh, 425 GNUNET_SQ_reset (plugin->dbh,
411 plugin->del_select_stmt); 426 plugin->del_expired_stmt);
412 return GNUNET_SYSERR; 427 return GNUNET_SYSERR;
413 } 428 }
414 if (GNUNET_OK != 429 if ( (SQLITE_ROW !=
415 GNUNET_SQ_extract_result (plugin->del_select_stmt, 430 sqlite3_step (plugin->del_expired_stmt)) ||
416 rs)) 431 (GNUNET_OK !=
432 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
433 rs)) )
417 { 434 {
418 GNUNET_break (0);
419 GNUNET_SQ_reset (plugin->dbh, 435 GNUNET_SQ_reset (plugin->dbh,
420 plugin->del_select_stmt); 436 plugin->del_expired_stmt);
421 return GNUNET_SYSERR; 437 if (SQLITE_ROW !=
438 sqlite3_step (plugin->del_select_stmt))
439 {
440 LOG_SQLITE (plugin->dbh,
441 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
442 "sqlite3_step");
443 GNUNET_SQ_reset (plugin->dbh,
444 plugin->del_select_stmt);
445 return GNUNET_SYSERR;
446 }
447 if (GNUNET_OK !=
448 GNUNET_SQ_extract_result (plugin->del_select_stmt,
449 rs))
450 {
451 GNUNET_SQ_reset (plugin->dbh,
452 plugin->del_select_stmt);
453 GNUNET_break (0);
454 return GNUNET_SYSERR;
455 }
422 } 456 }
423 GNUNET_SQ_cleanup_result (rs); 457 GNUNET_SQ_cleanup_result (rs);
424 GNUNET_SQ_reset (plugin->dbh, 458 GNUNET_SQ_reset (plugin->dbh,
@@ -709,13 +743,15 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
709 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3"); 743 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
710 744
711 SQLITE3_EXEC (dbh, 745 SQLITE3_EXEC (dbh,
712 "CREATE TABLE ds090 (" " type INTEGER NOT NULL DEFAULT 0," 746 "CREATE TABLE ds091 ("
713 " expire INTEGER NOT NULL DEFAULT 0," 747 " type INTEGER NOT NULL DEFAULT 0,"
748 " expire INTEGER NOT NULL,"
714 " key BLOB NOT NULL DEFAULT ''," 749 " key BLOB NOT NULL DEFAULT '',"
715 " value BLOB NOT NULL DEFAULT ''," 750 " prox INTEGER NOT NULL,"
751 " value BLOB NOT NULL,"
716 " path BLOB DEFAULT '')"); 752 " path BLOB DEFAULT '')");
717 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)"); 753 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
718 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)"); 754 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds091 (prox,expire)");
719 plugin = GNUNET_new (struct Plugin); 755 plugin = GNUNET_new (struct Plugin);
720 plugin->env = env; 756 plugin->env = env;
721 plugin->dbh = dbh; 757 plugin->dbh = dbh;
@@ -723,35 +759,42 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
723 759
724 if ( (SQLITE_OK != 760 if ( (SQLITE_OK !=
725 sq_prepare (plugin->dbh, 761 sq_prepare (plugin->dbh,
726 "INSERT INTO ds090 (type, expire, key, value, path) " 762 "INSERT INTO ds091 (type, expire, key, prox, value, path) "
727 "VALUES (?, ?, ?, ?, ?)", 763 "VALUES (?, ?, ?, ?, ?, ?)",
728 &plugin->insert_stmt)) || 764 &plugin->insert_stmt)) ||
729 (SQLITE_OK != 765 (SQLITE_OK !=
730 sq_prepare (plugin->dbh, 766 sq_prepare (plugin->dbh,
731 "SELECT count(*) FROM ds090 " 767 "SELECT count(*) FROM ds091 "
732 "WHERE key=? AND type=? AND expire >= ?", 768 "WHERE key=? AND type=? AND expire >= ?",
733 &plugin->get_count_stmt)) || 769 &plugin->get_count_stmt)) ||
734 (SQLITE_OK != 770 (SQLITE_OK !=
735 sq_prepare (plugin->dbh, 771 sq_prepare (plugin->dbh,
736 "SELECT value,expire,path FROM ds090 " 772 "SELECT value,expire,path FROM ds091"
737 "WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?", 773 " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
738 &plugin->get_stmt)) || 774 &plugin->get_stmt)) ||
739 (SQLITE_OK != 775 (SQLITE_OK !=
740 sq_prepare (plugin->dbh, 776 sq_prepare (plugin->dbh,
741 "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1", 777 "SELECT _ROWID_,key,value FROM ds091"
778 " WHERE expire < ?"
779 " ORDER BY expire ASC LIMIT 1",
780 &plugin->del_expired_stmt)) ||
781 (SQLITE_OK !=
782 sq_prepare (plugin->dbh,
783 "SELECT _ROWID_,key,value FROM ds091"
784 " ORDER BY prox ASC, expire ASC LIMIT 1",
742 &plugin->del_select_stmt)) || 785 &plugin->del_select_stmt)) ||
743 (SQLITE_OK != 786 (SQLITE_OK !=
744 sq_prepare (plugin->dbh, 787 sq_prepare (plugin->dbh,
745 "DELETE FROM ds090 WHERE _ROWID_=?", 788 "DELETE FROM ds091 WHERE _ROWID_=?",
746 &plugin->del_stmt)) || 789 &plugin->del_stmt)) ||
747 (SQLITE_OK != 790 (SQLITE_OK !=
748 sq_prepare (plugin->dbh, 791 sq_prepare (plugin->dbh,
749 "SELECT value,expire,path,key,type FROM ds090 " 792 "SELECT value,expire,path,key,type FROM ds091 "
750 "ORDER BY key LIMIT 1 OFFSET ?", 793 "ORDER BY key LIMIT 1 OFFSET ?",
751 &plugin->get_random_stmt)) || 794 &plugin->get_random_stmt)) ||
752 (SQLITE_OK != 795 (SQLITE_OK !=
753 sq_prepare (plugin->dbh, 796 sq_prepare (plugin->dbh,
754 "SELECT value,expire,path,type,key FROM ds090 " 797 "SELECT value,expire,path,type,key FROM ds091 "
755 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?", 798 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
756 &plugin->get_closest_stmt)) 799 &plugin->get_closest_stmt))
757 ) 800 )
@@ -807,6 +850,7 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
807 sqlite3_finalize (plugin->get_count_stmt); 850 sqlite3_finalize (plugin->get_count_stmt);
808 sqlite3_finalize (plugin->get_stmt); 851 sqlite3_finalize (plugin->get_stmt);
809 sqlite3_finalize (plugin->del_select_stmt); 852 sqlite3_finalize (plugin->del_select_stmt);
853 sqlite3_finalize (plugin->del_expired_stmt);
810 sqlite3_finalize (plugin->del_stmt); 854 sqlite3_finalize (plugin->del_stmt);
811 sqlite3_finalize (plugin->get_random_stmt); 855 sqlite3_finalize (plugin->get_random_stmt);
812 sqlite3_finalize (plugin->get_closest_stmt); 856 sqlite3_finalize (plugin->get_closest_stmt);
diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c
index b9baa64d3..1064d3125 100644
--- a/src/datacache/plugin_datacache_template.c
+++ b/src/datacache/plugin_datacache_template.c
@@ -45,6 +45,7 @@ struct Plugin
45 * 45 *
46 * @param cls closure (our `struct Plugin`) 46 * @param cls closure (our `struct Plugin`)
47 * @param key key to store @a data under 47 * @param key key to store @a data under
48 * @param xor_distance distance of @a key to our PID
48 * @param size number of bytes in @a data 49 * @param size number of bytes in @a data
49 * @param data data to store 50 * @param data data to store
50 * @param type type of the value 51 * @param type type of the value
@@ -56,6 +57,7 @@ struct Plugin
56static ssize_t 57static ssize_t
57template_plugin_put (void *cls, 58template_plugin_put (void *cls,
58 const struct GNUNET_HashCode *key, 59 const struct GNUNET_HashCode *key,
60 uint32_t xor_distance,
59 size_t size, 61 size_t size,
60 const char *data, 62 const char *data,
61 enum GNUNET_BLOCK_Type type, 63 enum GNUNET_BLOCK_Type type,
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
index 79e6b6d74..c4d59c3cc 100644
--- a/src/datacache/test_datacache.c
+++ b/src/datacache/test_datacache.c
@@ -87,7 +87,10 @@ run (void *cls, char *const *args, const char *cfgfile,
87 { 87 {
88 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); 88 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
89 ASSERT (GNUNET_OK == 89 ASSERT (GNUNET_OK ==
90 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), 90 GNUNET_DATACACHE_put (h,
91 &k,
92 GNUNET_YES,
93 sizeof (struct GNUNET_HashCode),
91 (const char *) &n, 1 + i % 16, exp, 94 (const char *) &n, 1 + i % 16, exp,
92 0, NULL)); 95 0, NULL));
93 k = n; 96 k = n;
@@ -103,7 +106,10 @@ run (void *cls, char *const *args, const char *cfgfile,
103 memset (&k, 42, sizeof (struct GNUNET_HashCode)); 106 memset (&k, 42, sizeof (struct GNUNET_HashCode));
104 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n); 107 GNUNET_CRYPTO_hash (&k, sizeof (struct GNUNET_HashCode), &n);
105 ASSERT (GNUNET_OK == 108 ASSERT (GNUNET_OK ==
106 GNUNET_DATACACHE_put (h, &k, sizeof (struct GNUNET_HashCode), 109 GNUNET_DATACACHE_put (h,
110 &k,
111 GNUNET_YES,
112 sizeof (struct GNUNET_HashCode),
107 (const char *) &n, 792, 113 (const char *) &n, 792,
108 GNUNET_TIME_UNIT_FOREVER_ABS, 114 GNUNET_TIME_UNIT_FOREVER_ABS,
109 0, NULL)); 115 0, NULL));
diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c
index 78b56ce42..35357a8d2 100644
--- a/src/datacache/test_datacache_quota.c
+++ b/src/datacache/test_datacache_quota.c
@@ -73,7 +73,15 @@ run (void *cls, char *const *args, const char *cfgfile,
73 { 73 {
74 exp.abs_value_us++; 74 exp.abs_value_us++;
75 buf[j] = i; 75 buf[j] = i;
76 ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp, 0, NULL)); 76 ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h,
77 &k,
78 GNUNET_YES,
79 j,
80 buf,
81 1 + i,
82 exp,
83 0,
84 NULL));
77 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); 85 ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL));
78 } 86 }
79 k = n; 87 k = n;
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c
index 842ec6270..afcd5422c 100644
--- a/src/dht/gnunet-dht-get.c
+++ b/src/dht/gnunet-dht-get.c
@@ -154,7 +154,9 @@ get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
154 const void *data) 154 const void *data)
155{ 155{
156 FPRINTF (stdout, 156 FPRINTF (stdout,
157 _("Result %d, type %d:\n%.*s\n"), 157 (GNUNET_BLOCK_TYPE_TEST == type)
158 ? _("Result %d, type %d:\n%.*s\n")
159 : _("Result %d, type %d:\n"),
158 result_count, 160 result_count,
159 type, 161 type,
160 (unsigned int) size, 162 (unsigned int) size,
@@ -196,8 +198,6 @@ run (void *cls, char *const *args, const char *cfgfile,
196{ 198{
197 struct GNUNET_HashCode key; 199 struct GNUNET_HashCode key;
198 200
199
200
201 cfg = c; 201 cfg = c;
202 if (NULL == query_key) 202 if (NULL == query_key)
203 { 203 {
@@ -215,17 +215,22 @@ run (void *cls, char *const *args, const char *cfgfile,
215 query_type = GNUNET_BLOCK_TYPE_TEST; 215 query_type = GNUNET_BLOCK_TYPE_TEST;
216 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); 216 GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key);
217 if (verbose) 217 if (verbose)
218 FPRINTF (stderr, "%s `%s' \n", _("Issueing DHT GET with key"), GNUNET_h2s_full (&key)); 218 FPRINTF (stderr, "%s `%s' \n",
219 _("Issueing DHT GET with key"),
220 GNUNET_h2s_full (&key));
219 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL); 221 GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
220 tt = GNUNET_SCHEDULER_add_delayed (timeout_request, 222 tt = GNUNET_SCHEDULER_add_delayed (timeout_request,
221 &timeout_task, NULL); 223 &timeout_task,
224 NULL);
222 get_handle = 225 get_handle =
223 GNUNET_DHT_get_start (dht_handle, query_type, &key, replication, 226 GNUNET_DHT_get_start (dht_handle, query_type, &key, replication,
224 (demultixplex_everywhere) ? GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE : GNUNET_DHT_RO_NONE, 227 (demultixplex_everywhere) ? GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE : GNUNET_DHT_RO_NONE,
225 NULL, 0, &get_result_iterator, NULL); 228 NULL, 0,
226 229 &get_result_iterator,
230 NULL);
227} 231}
228 232
233
229/** 234/**
230 * Entry point for gnunet-dht-get 235 * Entry point for gnunet-dht-get
231 * 236 *
@@ -236,15 +241,12 @@ run (void *cls, char *const *args, const char *cfgfile,
236int 241int
237main (int argc, char *const *argv) 242main (int argc, char *const *argv)
238{ 243{
239
240 struct GNUNET_GETOPT_CommandLineOption options[] = { 244 struct GNUNET_GETOPT_CommandLineOption options[] = {
241
242 GNUNET_GETOPT_option_string ('k', 245 GNUNET_GETOPT_option_string ('k',
243 "key", 246 "key",
244 "KEY", 247 "KEY",
245 gettext_noop ("the query key"), 248 gettext_noop ("the query key"),
246 &query_key), 249 &query_key),
247
248 GNUNET_GETOPT_option_uint ('r', 250 GNUNET_GETOPT_option_uint ('r',
249 "replication", 251 "replication",
250 "LEVEL", 252 "LEVEL",
diff --git a/src/dht/gnunet-dht-monitor.c b/src/dht/gnunet-dht-monitor.c
index b7360bbab..a699b3d17 100644
--- a/src/dht/gnunet-dht-monitor.c
+++ b/src/dht/gnunet-dht-monitor.c
@@ -141,7 +141,8 @@ get_callback (void *cls,
141 const struct GNUNET_PeerIdentity *path, 141 const struct GNUNET_PeerIdentity *path,
142 const struct GNUNET_HashCode * key) 142 const struct GNUNET_HashCode * key)
143{ 143{
144 FPRINTF (stdout, "GET #%u: type %d, key `%s'\n", 144 FPRINTF (stdout,
145 "GET #%u: type %d, key `%s'\n",
145 result_count, 146 result_count,
146 (int) type, 147 (int) type,
147 GNUNET_h2s_full(key)); 148 GNUNET_h2s_full(key));
@@ -176,8 +177,11 @@ get_resp_callback (void *cls,
176 size_t size) 177 size_t size)
177{ 178{
178 FPRINTF (stdout, 179 FPRINTF (stdout,
179 "RESPONSE #%u: type %d, key `%s', data `%.*s'\n", 180 (GNUNET_BLOCK_TYPE_TEST == type)
181 ? "RESPONSE #%u (%s): type %d, key `%s', data `%.*s'\n"
182 : "RESPONSE #%u (%s): type %d, key `%s'\n",
180 result_count, 183 result_count,
184 GNUNET_STRINGS_absolute_time_to_string (exp),
181 (int) type, 185 (int) type,
182 GNUNET_h2s_full (key), 186 GNUNET_h2s_full (key),
183 (unsigned int) size, 187 (unsigned int) size,
@@ -215,8 +219,11 @@ put_callback (void *cls,
215 size_t size) 219 size_t size)
216{ 220{
217 FPRINTF (stdout, 221 FPRINTF (stdout,
218 "PUT %u: type %d, key `%s', data `%.*s'\n", 222 (GNUNET_BLOCK_TYPE_TEST == type)
223 ? "PUT %u (%s): type %d, key `%s', data `%.*s'\n"
224 : "PUT %u (%s): type %d, key `%s'\n",
219 result_count, 225 result_count,
226 GNUNET_STRINGS_absolute_time_to_string (exp),
220 (int) type, 227 (int) type,
221 GNUNET_h2s_full(key), 228 GNUNET_h2s_full(key),
222 (unsigned int) size, 229 (unsigned int) size,
@@ -234,7 +241,9 @@ put_callback (void *cls,
234 * @param c configuration 241 * @param c configuration
235 */ 242 */
236static void 243static void
237run (void *cls, char *const *args, const char *cfgfile, 244run (void *cls,
245 char *const *args,
246 const char *cfgfile,
238 const struct GNUNET_CONFIGURATION_Handle *c) 247 const struct GNUNET_CONFIGURATION_Handle *c)
239{ 248{
240 struct GNUNET_HashCode *key; 249 struct GNUNET_HashCode *key;
@@ -291,30 +300,30 @@ int
291main (int argc, char *const *argv) 300main (int argc, char *const *argv)
292{ 301{
293 struct GNUNET_GETOPT_CommandLineOption options[] = { 302 struct GNUNET_GETOPT_CommandLineOption options[] = {
294 303
295 GNUNET_GETOPT_option_string ('k', 304 GNUNET_GETOPT_option_string ('k',
296 "key", 305 "key",
297 "KEY", 306 "KEY",
298 gettext_noop ("the query key"), 307 gettext_noop ("the query key"),
299 &query_key), 308 &query_key),
300 309
301 GNUNET_GETOPT_option_uint ('t', 310 GNUNET_GETOPT_option_uint ('t',
302 "type", 311 "type",
303 "TYPE", 312 "TYPE",
304 gettext_noop ("the type of data to look for"), 313 gettext_noop ("the type of data to look for"),
305 &block_type), 314 &block_type),
306 315
307 GNUNET_GETOPT_option_relative_time ('T', 316 GNUNET_GETOPT_option_relative_time ('T',
308 "timeout", 317 "timeout",
309 "TIMEOUT", 318 "TIMEOUT",
310 gettext_noop ("how long should the monitor command run"), 319 gettext_noop ("how long should the monitor command run"),
311 &timeout_request), 320 &timeout_request),
312 321
313 GNUNET_GETOPT_option_flag ('V', 322 GNUNET_GETOPT_option_flag ('V',
314 "verbose", 323 "verbose",
315 gettext_noop ("be verbose (print progress information)"), 324 gettext_noop ("be verbose (print progress information)"),
316 &verbose), 325 &verbose),
317 326
318 GNUNET_GETOPT_OPTION_END 327 GNUNET_GETOPT_OPTION_END
319 }; 328 };
320 329
diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c
index 36047d561..07a666db6 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.c
@@ -26,6 +26,7 @@
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_datacache_lib.h" 27#include "gnunet_datacache_lib.h"
28#include "gnunet-service-dht_datacache.h" 28#include "gnunet-service-dht_datacache.h"
29#include "gnunet-service-dht_neighbours.h"
29#include "gnunet-service-dht_routing.h" 30#include "gnunet-service-dht_routing.h"
30#include "gnunet-service-dht.h" 31#include "gnunet-service-dht.h"
31 32
@@ -79,10 +80,13 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
79 } 80 }
80 /* Put size is actual data size plus struct overhead plus path length (if any) */ 81 /* Put size is actual data size plus struct overhead plus path length (if any) */
81 GNUNET_STATISTICS_update (GDS_stats, 82 GNUNET_STATISTICS_update (GDS_stats,
82 gettext_noop ("# ITEMS stored in datacache"), 1, 83 gettext_noop ("# ITEMS stored in datacache"),
84 1,
83 GNUNET_NO); 85 GNUNET_NO);
84 r = GNUNET_DATACACHE_put (datacache, 86 r = GNUNET_DATACACHE_put (datacache,
85 key, 87 key,
88 GNUNET_CRYPTO_hash_matching_bits (key,
89 &my_identity_hash),
86 data_size, 90 data_size,
87 data, 91 data,
88 type, 92 type,
diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c
index 0309bea88..94844374d 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -404,7 +404,7 @@ static struct GNUNET_PeerIdentity my_identity;
404/** 404/**
405 * Hash of the identity of this peer. 405 * Hash of the identity of this peer.
406 */ 406 */
407static struct GNUNET_HashCode my_identity_hash; 407struct GNUNET_HashCode my_identity_hash;
408 408
409/** 409/**
410 * Handle to CORE. 410 * Handle to CORE.
@@ -421,7 +421,7 @@ static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
421 * Find the optimal bucket for this key. 421 * Find the optimal bucket for this key.
422 * 422 *
423 * @param hc the hashcode to compare our identity to 423 * @param hc the hashcode to compare our identity to
424 * @return the proper bucket index, or GNUNET_SYSERR 424 * @return the proper bucket index, or #GNUNET_SYSERR
425 * on error (same hashcode) 425 * on error (same hashcode)
426 */ 426 */
427static int 427static int
@@ -941,9 +941,9 @@ get_distance (const struct GNUNET_HashCode *target,
941 * @return #GNUNET_YES if node location is closest, 941 * @return #GNUNET_YES if node location is closest,
942 * #GNUNET_NO otherwise. 942 * #GNUNET_NO otherwise.
943 */ 943 */
944static int 944int
945am_closest_peer (const struct GNUNET_HashCode *key, 945GDS_am_closest_peer (const struct GNUNET_HashCode *key,
946 const struct GNUNET_CONTAINER_BloomFilter *bloom) 946 const struct GNUNET_CONTAINER_BloomFilter *bloom)
947{ 947{
948 int bits; 948 int bits;
949 int other_bits; 949 int other_bits;
@@ -1803,7 +1803,7 @@ handle_dht_p2p_put (void *cls,
1803 payload); 1803 payload);
1804 /* store locally */ 1804 /* store locally */
1805 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || 1805 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1806 (am_closest_peer (&put->key, bf))) 1806 (GDS_am_closest_peer (&put->key, bf)))
1807 GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time), 1807 GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time),
1808 &put->key, 1808 &put->key,
1809 putlen, 1809 putlen,
@@ -2122,7 +2122,7 @@ handle_dht_p2p_get (void *cls,
2122 (unsigned int) ntohl (get->hop_count)); 2122 (unsigned int) ntohl (get->hop_count));
2123 /* local lookup (this may update the reply_bf) */ 2123 /* local lookup (this may update the reply_bf) */
2124 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || 2124 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2125 (am_closest_peer (&get->key, 2125 (GDS_am_closest_peer (&get->key,
2126 peer_bf))) 2126 peer_bf)))
2127 { 2127 {
2128 if ((0 != (options & GNUNET_DHT_RO_FIND_PEER))) 2128 if ((0 != (options & GNUNET_DHT_RO_FIND_PEER)))
diff --git a/src/dht/gnunet-service-dht_neighbours.h b/src/dht/gnunet-service-dht_neighbours.h
index 34b76ee8a..bf3ed80a2 100644
--- a/src/dht/gnunet-service-dht_neighbours.h
+++ b/src/dht/gnunet-service-dht_neighbours.h
@@ -32,6 +32,12 @@
32#include "gnunet_dht_service.h" 32#include "gnunet_dht_service.h"
33 33
34/** 34/**
35 * Hash of the identity of this peer.
36 */
37extern struct GNUNET_HashCode my_identity_hash;
38
39
40/**
35 * Perform a PUT operation. Forwards the given request to other 41 * Perform a PUT operation. Forwards the given request to other
36 * peers. Does not store the data locally. Does not give the 42 * peers. Does not store the data locally. Does not give the
37 * data to local clients. May do nothing if this is the only 43 * data to local clients. May do nothing if this is the only
@@ -123,6 +129,22 @@ GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
123 129
124 130
125/** 131/**
132 * Check whether my identity is closer than any known peers. If a
133 * non-null bloomfilter is given, check if this is the closest peer
134 * that hasn't already been routed to.
135 *
136 * @param key hash code to check closeness to
137 * @param bloom bloomfilter, exclude these entries from the decision
138 * @return #GNUNET_YES if node location is closest,
139 * #GNUNET_NO otherwise.
140 */
141int
142GDS_am_closest_peer (const struct GNUNET_HashCode *key,
143 const struct GNUNET_CONTAINER_BloomFilter *bloom);
144
145
146
147/**
126 * Initialize neighbours subsystem. 148 * Initialize neighbours subsystem.
127 * 149 *
128 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 150 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
index 0746d5c57..d7fd1a812 100644
--- a/src/gns/gnunet-bcd.c
+++ b/src/gns/gnunet-bcd.c
@@ -76,7 +76,7 @@ static char *resfile;
76/** 76/**
77 * Port number. 77 * Port number.
78 */ 78 */
79static unsigned int port = 8888; 79static uint16_t port = 8888;
80 80
81 81
82struct Entry 82struct Entry
@@ -351,7 +351,7 @@ prepare_daemon (struct MHD_Daemon *daemon_handle)
351static int 351static int
352server_start () 352server_start ()
353{ 353{
354 if ((0 == port) || (port > UINT16_MAX)) 354 if (0 == port)
355 { 355 {
356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
357 _("Invalid port number %u. Exiting.\n"), 357 _("Invalid port number %u. Exiting.\n"),
@@ -362,7 +362,7 @@ server_start ()
362 _("Businesscard HTTP server starts on %u\n"), 362 _("Businesscard HTTP server starts on %u\n"),
363 port); 363 port);
364 daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG, 364 daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
365 (uint16_t) port, 365 port,
366 NULL /* accept_policy_callback */, NULL, 366 NULL /* accept_policy_callback */, NULL,
367 &access_handler_callback, NULL, 367 &access_handler_callback, NULL,
368 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 512, 368 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 512,
@@ -374,7 +374,7 @@ server_start ()
374 { 374 {
375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
376 _("Could not start businesscard HTTP server on port %u\n"), 376 _("Could not start businesscard HTTP server on port %u\n"),
377 (unsigned short) port); 377 (unsigned int) port);
378 return GNUNET_SYSERR; 378 return GNUNET_SYSERR;
379 } 379 }
380 http_task = prepare_daemon (daemon_handle); 380 http_task = prepare_daemon (daemon_handle);
@@ -516,17 +516,17 @@ main (int argc, char *const *argv)
516{ 516{
517 struct GNUNET_GETOPT_CommandLineOption options[] = { 517 struct GNUNET_GETOPT_CommandLineOption options[] = {
518 518
519 GNUNET_GETOPT_option_uint ('p', 519 GNUNET_GETOPT_option_uint16 ('p',
520 "port", 520 "port",
521 "PORT", 521 "PORT",
522 gettext_noop ("Run HTTP serve on port PORT (default is 8888)"), 522 gettext_noop ("Run HTTP serve on port PORT (default is 8888)"),
523 &port), 523 &port),
524
525 GNUNET_GETOPT_OPTION_END 524 GNUNET_GETOPT_OPTION_END
526 }; 525 };
527 int ret; 526 int ret;
528 527
529 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) 528 if (GNUNET_OK !=
529 GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
530 return 2; 530 return 2;
531 GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL); 531 GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
532 ret = 532 ret =
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
index 02ebcf0f1..0d7d83b4b 100644
--- a/src/gns/gnunet-gns-proxy.c
+++ b/src/gns/gnunet-gns-proxy.c
@@ -636,7 +636,7 @@ struct Socks5Request
636/** 636/**
637 * The port the proxy is running on (default 7777) 637 * The port the proxy is running on (default 7777)
638 */ 638 */
639static unsigned long long port = GNUNET_GNS_PROXY_PORT; 639static uint16_t port = GNUNET_GNS_PROXY_PORT;
640 640
641/** 641/**
642 * The CA file (pem) to use for the proxy CA 642 * The CA file (pem) to use for the proxy CA
@@ -3399,8 +3399,8 @@ run (void *cls,
3399 return; 3399 return;
3400 } 3400 }
3401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3402 "Proxy listens on port %llu\n", 3402 "Proxy listens on port %u\n",
3403 port); 3403 (unsigned int) port);
3404 3404
3405 /* start MHD daemon for HTTP */ 3405 /* start MHD daemon for HTTP */
3406 hd = GNUNET_new (struct MhdHttpList); 3406 hd = GNUNET_new (struct MhdHttpList);
@@ -3437,11 +3437,11 @@ int
3437main (int argc, char *const *argv) 3437main (int argc, char *const *argv)
3438{ 3438{
3439 struct GNUNET_GETOPT_CommandLineOption options[] = { 3439 struct GNUNET_GETOPT_CommandLineOption options[] = {
3440 GNUNET_GETOPT_option_ulong ('p', 3440 GNUNET_GETOPT_option_uint16 ('p',
3441 "port", 3441 "port",
3442 NULL, 3442 NULL,
3443 gettext_noop ("listen on specified port (default: 7777)"), 3443 gettext_noop ("listen on specified port (default: 7777)"),
3444 &port), 3444 &port),
3445 GNUNET_GETOPT_option_string ('a', 3445 GNUNET_GETOPT_option_string ('a',
3446 "authority", 3446 "authority",
3447 NULL, 3447 NULL,
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index 8b20f2ae3..0d04fc6b9 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -60,7 +60,7 @@
60/** 60/**
61 * DHT replication level 61 * DHT replication level
62 */ 62 */
63#define DHT_GNS_REPLICATION_LEVEL 5 63#define DHT_GNS_REPLICATION_LEVEL 10
64 64
65/** 65/**
66 * How deep do we allow recursions to go before we abort? 66 * How deep do we allow recursions to go before we abort?
diff --git a/src/hostlist/gnunet-daemon-hostlist_client.c b/src/hostlist/gnunet-daemon-hostlist_client.c
index 207cc4a81..2283efe6c 100644
--- a/src/hostlist/gnunet-daemon-hostlist_client.c
+++ b/src/hostlist/gnunet-daemon-hostlist_client.c
@@ -28,6 +28,7 @@
28#include "gnunet_hello_lib.h" 28#include "gnunet_hello_lib.h"
29#include "gnunet_statistics_service.h" 29#include "gnunet_statistics_service.h"
30#include "gnunet_transport_service.h" 30#include "gnunet_transport_service.h"
31#include "gnunet_peerinfo_service.h"
31#include "gnunet-daemon-hostlist.h" 32#include "gnunet-daemon-hostlist.h"
32#if HAVE_CURL_CURL_H 33#if HAVE_CURL_CURL_H
33#include <curl/curl.h> 34#include <curl/curl.h>
@@ -142,14 +143,6 @@ struct Hostlist
142}; 143};
143 144
144 145
145struct HelloOffer
146{
147 struct HelloOffer *next;
148 struct HelloOffer *prev;
149 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
150};
151
152
153/** 146/**
154 * Our configuration. 147 * Our configuration.
155 */ 148 */
@@ -315,24 +308,10 @@ static unsigned int stat_hellos_obtained;
315 */ 308 */
316static unsigned int stat_connection_count; 309static unsigned int stat_connection_count;
317 310
318static struct HelloOffer *ho_head;
319
320static struct HelloOffer *ho_tail;
321
322
323/** 311/**
324 * Hello offer complete. Clean up. 312 * Handle to peerinfo service.
325 */ 313 */
326static void 314static struct GNUNET_PEERINFO_Handle *pi;
327done_offer_hello (void *cls)
328{
329 struct HelloOffer *ho = cls;
330
331 GNUNET_CONTAINER_DLL_remove (ho_head,
332 ho_tail,
333 ho);
334 GNUNET_free (ho);
335}
336 315
337 316
338/** 317/**
@@ -353,7 +332,6 @@ callback_download (void *ptr,
353 static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1]; 332 static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1];
354 const char *cbuf = ptr; 333 const char *cbuf = ptr;
355 const struct GNUNET_MessageHeader *msg; 334 const struct GNUNET_MessageHeader *msg;
356 struct HelloOffer *ho;
357 size_t total; 335 size_t total;
358 size_t cpy; 336 size_t cpy;
359 size_t left; 337 size_t left;
@@ -413,22 +391,10 @@ callback_download (void *ptr,
413 ("# valid HELLOs downloaded from hostlist servers"), 391 ("# valid HELLOs downloaded from hostlist servers"),
414 1, GNUNET_NO); 392 1, GNUNET_NO);
415 stat_hellos_obtained++; 393 stat_hellos_obtained++;
416 394 (void) GNUNET_PEERINFO_add_peer (pi,
417 ho = GNUNET_new (struct HelloOffer); 395 (const struct GNUNET_HELLO_Message *) msg,
418 ho->ohh = GNUNET_TRANSPORT_offer_hello (cfg, 396 NULL,
419 msg, 397 NULL);
420 &done_offer_hello,
421 ho);
422 if (NULL == ho->ohh)
423 {
424 GNUNET_free (ho);
425 }
426 else
427 {
428 GNUNET_CONTAINER_DLL_insert (ho_head,
429 ho_tail,
430 ho);
431 }
432 } 398 }
433 else 399 else
434 { 400 {
@@ -1567,6 +1533,7 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1567 stats = st; 1533 stats = st;
1568 1534
1569 /* Read proxy configuration */ 1535 /* Read proxy configuration */
1536 pi = GNUNET_PEERINFO_connect (c);
1570 if (GNUNET_OK == 1537 if (GNUNET_OK ==
1571 GNUNET_CONFIGURATION_get_value_string (cfg, 1538 GNUNET_CONFIGURATION_get_value_string (cfg,
1572 "HOSTLIST", 1539 "HOSTLIST",
@@ -1723,18 +1690,8 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1723void 1690void
1724GNUNET_HOSTLIST_client_stop () 1691GNUNET_HOSTLIST_client_stop ()
1725{ 1692{
1726 struct HelloOffer *ho;
1727
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729 "Hostlist client shutdown\n"); 1694 "Hostlist client shutdown\n");
1730 while (NULL != (ho = ho_head))
1731 {
1732 GNUNET_CONTAINER_DLL_remove (ho_head,
1733 ho_tail,
1734 ho);
1735 GNUNET_TRANSPORT_offer_hello_cancel (ho->ohh);
1736 GNUNET_free (ho);
1737 }
1738 if (NULL != sget) 1695 if (NULL != sget)
1739 { 1696 {
1740 GNUNET_STATISTICS_get_cancel (sget); 1697 GNUNET_STATISTICS_get_cancel (sget);
@@ -1777,7 +1734,11 @@ GNUNET_HOSTLIST_client_stop ()
1777 proxy_username = NULL; 1734 proxy_username = NULL;
1778 GNUNET_free_non_null (proxy_password); 1735 GNUNET_free_non_null (proxy_password);
1779 proxy_password = NULL; 1736 proxy_password = NULL;
1780 1737 if (NULL != pi)
1738 {
1739 GNUNET_PEERINFO_disconnect (pi);
1740 pi = NULL;
1741 }
1781 cfg = NULL; 1742 cfg = NULL;
1782} 1743}
1783 1744
diff --git a/src/include/gnunet_core_service.h b/src/include/gnunet_core_service.h
index ace223c11..77af465ce 100644
--- a/src/include/gnunet_core_service.h
+++ b/src/include/gnunet_core_service.h
@@ -220,7 +220,7 @@ enum GNUNET_CORE_KxState
220 /** 220 /**
221 * No handshake yet. 221 * No handshake yet.
222 */ 222 */
223 GNUNET_CORE_KX_STATE_DOWN, 223 GNUNET_CORE_KX_STATE_DOWN = 0,
224 224
225 /** 225 /**
226 * We've sent our session key. 226 * We've sent our session key.
diff --git a/src/include/gnunet_datacache_lib.h b/src/include/gnunet_datacache_lib.h
index 39a312b17..05ac779d6 100644
--- a/src/include/gnunet_datacache_lib.h
+++ b/src/include/gnunet_datacache_lib.h
@@ -105,6 +105,7 @@ typedef int
105 * 105 *
106 * @param h handle to the datacache 106 * @param h handle to the datacache
107 * @param key key to store data under 107 * @param key key to store data under
108 * @param how close is @a key to our pid?
108 * @param data_size number of bytes in @a data 109 * @param data_size number of bytes in @a data
109 * @param data data to store 110 * @param data data to store
110 * @param type type of the value 111 * @param type type of the value
@@ -116,6 +117,7 @@ typedef int
116int 117int
117GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, 118GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
118 const struct GNUNET_HashCode *key, 119 const struct GNUNET_HashCode *key,
120 uint32_t xor_distance,
119 size_t data_size, 121 size_t data_size,
120 const char *data, 122 const char *data,
121 enum GNUNET_BLOCK_Type type, 123 enum GNUNET_BLOCK_Type type,
diff --git a/src/include/gnunet_datacache_plugin.h b/src/include/gnunet_datacache_plugin.h
index 166c7bc3b..726108c64 100644
--- a/src/include/gnunet_datacache_plugin.h
+++ b/src/include/gnunet_datacache_plugin.h
@@ -109,6 +109,7 @@ struct GNUNET_DATACACHE_PluginFunctions
109 * 109 *
110 * @param cls closure (internal context for the plugin) 110 * @param cls closure (internal context for the plugin)
111 * @param key key to store the value under 111 * @param key key to store the value under
112 * @param xor_distance how close is @a key to our PID?
112 * @param size number of bytes in @a data 113 * @param size number of bytes in @a data
113 * @param data data to store 114 * @param data data to store
114 * @param type type of the value 115 * @param type type of the value
@@ -119,6 +120,7 @@ struct GNUNET_DATACACHE_PluginFunctions
119 */ 120 */
120 ssize_t (*put) (void *cls, 121 ssize_t (*put) (void *cls,
121 const struct GNUNET_HashCode *key, 122 const struct GNUNET_HashCode *key,
123 uint32_t xor_distance,
122 size_t size, 124 size_t size,
123 const char *data, 125 const char *data,
124 enum GNUNET_BLOCK_Type type, 126 enum GNUNET_BLOCK_Type type,
diff --git a/src/include/gnunet_getopt_lib.h b/src/include/gnunet_getopt_lib.h
index e38925f14..88c7825d0 100644
--- a/src/include/gnunet_getopt_lib.h
+++ b/src/include/gnunet_getopt_lib.h
@@ -287,6 +287,23 @@ GNUNET_GETOPT_option_uint (char shortName,
287 287
288 288
289/** 289/**
290 * Allow user to specify an uint16_t.
291 *
292 * @param shortName short name of the option
293 * @param name long name of the option
294 * @param argumentHelp help text for the option argument
295 * @param description long help text for the option
296 * @param[out] val set to the value specified at the command line
297 */
298struct GNUNET_GETOPT_CommandLineOption
299GNUNET_GETOPT_option_uint16 (char shortName,
300 const char *name,
301 const char *argumentHelp,
302 const char *description,
303 uint16_t *val);
304
305
306/**
290 * Allow user to specify an `unsigned long long`. 307 * Allow user to specify an `unsigned long long`.
291 * 308 *
292 * @param shortName short name of the option 309 * @param shortName short name of the option
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index c5e45d5c1..7040f2cbf 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -252,6 +252,12 @@ extern "C"
252#define GNUNET_MESSAGE_TYPE_DV_BOX 53 252#define GNUNET_MESSAGE_TYPE_DV_BOX 53
253 253
254 254
255/**
256 * Experimental message type.
257 */
258#define GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE 55
259
260
255/******************************************************************************* 261/*******************************************************************************
256 * Transport-UDP message types 262 * Transport-UDP message types
257 ******************************************************************************/ 263 ******************************************************************************/
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
index 8b47ed444..09ec04bf8 100644
--- a/src/peerinfo/peerinfo_api.c
+++ b/src/peerinfo/peerinfo_api.c
@@ -565,7 +565,10 @@ GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
565 struct GNUNET_PeerIdentity peer; 565 struct GNUNET_PeerIdentity peer;
566 566
567 if (NULL == h->mq) 567 if (NULL == h->mq)
568 {
569 GNUNET_break (0);
568 return NULL; 570 return NULL;
571 }
569 GNUNET_assert (GNUNET_OK == 572 GNUNET_assert (GNUNET_OK ==
570 GNUNET_HELLO_get_id (hello, 573 GNUNET_HELLO_get_id (hello,
571 &peer)); 574 &peer));
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c
index 4415d0a24..da4f62351 100644
--- a/src/topology/gnunet-daemon-topology.c
+++ b/src/topology/gnunet-daemon-topology.c
@@ -137,6 +137,11 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
137static struct GNUNET_CORE_Handle *handle; 137static struct GNUNET_CORE_Handle *handle;
138 138
139/** 139/**
140 * Handle to the PEERINFO service.
141 */
142static struct GNUNET_PEERINFO_Handle *pi;
143
144/**
140 * Handle to the ATS service. 145 * Handle to the ATS service.
141 */ 146 */
142static struct GNUNET_ATS_ConnectivityHandle *ats; 147static struct GNUNET_ATS_ConnectivityHandle *ats;
@@ -999,16 +1004,6 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
999 1004
1000 1005
1001/** 1006/**
1002 * Hello offer complete. Clean up.
1003 */
1004static void
1005done_offer_hello (void *cls)
1006{
1007 oh = NULL;
1008}
1009
1010
1011/**
1012 * This function is called whenever an encrypted HELLO message is 1007 * This function is called whenever an encrypted HELLO message is
1013 * received. 1008 * received.
1014 * 1009 *
@@ -1076,12 +1071,10 @@ handle_hello (void *cls,
1076 (friend_count < minimum_friend_count)) 1071 (friend_count < minimum_friend_count))
1077 return; 1072 return;
1078 } 1073 }
1079 if (NULL != oh) 1074 (void) GNUNET_PEERINFO_add_peer (pi,
1080 GNUNET_TRANSPORT_offer_hello_cancel (oh); 1075 message,
1081 oh = GNUNET_TRANSPORT_offer_hello (cfg, 1076 NULL,
1082 &message->header, 1077 NULL);
1083 &done_offer_hello,
1084 NULL);
1085} 1078}
1086 1079
1087 1080
@@ -1125,6 +1118,11 @@ cleaning_task (void *cls)
1125 GNUNET_ATS_connectivity_done (ats); 1118 GNUNET_ATS_connectivity_done (ats);
1126 ats = NULL; 1119 ats = NULL;
1127 } 1120 }
1121 if (NULL != pi)
1122 {
1123 GNUNET_PEERINFO_disconnect (pi);
1124 pi = NULL;
1125 }
1128 if (NULL != stats) 1126 if (NULL != stats)
1129 { 1127 {
1130 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 1128 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -1189,6 +1187,7 @@ run (void *cls,
1189 &blacklist_check, 1187 &blacklist_check,
1190 NULL); 1188 NULL);
1191 ats = GNUNET_ATS_connectivity_init (cfg); 1189 ats = GNUNET_ATS_connectivity_init (cfg);
1190 pi = GNUNET_PEERINFO_connect (cfg);
1192 handle = GNUNET_CORE_connect (cfg, 1191 handle = GNUNET_CORE_connect (cfg,
1193 NULL, 1192 NULL,
1194 &core_init, 1193 &core_init,
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index e8c1f5d4a..8697d0941 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -289,6 +289,12 @@ plugin_LTLIBRARIES = \
289 $(WLAN_PLUGIN_LA) \ 289 $(WLAN_PLUGIN_LA) \
290 $(BT_PLUGIN_LA) 290 $(BT_PLUGIN_LA)
291 291
292if HAVE_EXPERIMENTAL
293plugin_LTLIBRARIES += \
294 libgnunet_plugin_transport_xt.la \
295 libgnunet_plugin_transport_xu.la
296endif
297
292# Note: real plugins of course need to be added 298# Note: real plugins of course need to be added
293# to the plugin_LTLIBRARIES above 299# to the plugin_LTLIBRARIES above
294noinst_LTLIBRARIES = \ 300noinst_LTLIBRARIES = \
@@ -306,6 +312,18 @@ libgnunet_plugin_transport_tcp_la_LIBADD = \
306libgnunet_plugin_transport_tcp_la_LDFLAGS = \ 312libgnunet_plugin_transport_tcp_la_LDFLAGS = \
307 $(GN_PLUGIN_LDFLAGS) 313 $(GN_PLUGIN_LDFLAGS)
308 314
315libgnunet_plugin_transport_xt_la_SOURCES = \
316 plugin_transport_xt.c
317libgnunet_plugin_transport_xt_la_LIBADD = \
318 $(top_builddir)/src/hello/libgnunethello.la \
319 $(top_builddir)/src/statistics/libgnunetstatistics.la \
320 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
321 $(top_builddir)/src/nat/libgnunetnatnew.la \
322 $(top_builddir)/src/util/libgnunetutil.la \
323 $(LTLIBINTL)
324libgnunet_plugin_transport_xt_la_LDFLAGS = \
325 $(GN_PLUGIN_LDFLAGS)
326
309libgnunet_plugin_transport_template_la_SOURCES = \ 327libgnunet_plugin_transport_template_la_SOURCES = \
310 plugin_transport_template.c 328 plugin_transport_template.c
311libgnunet_plugin_transport_template_la_LIBADD = \ 329libgnunet_plugin_transport_template_la_LIBADD = \
@@ -354,6 +372,19 @@ libgnunet_plugin_transport_udp_la_LIBADD = \
354libgnunet_plugin_transport_udp_la_LDFLAGS = \ 372libgnunet_plugin_transport_udp_la_LDFLAGS = \
355 $(GN_PLUGIN_LDFLAGS) 373 $(GN_PLUGIN_LDFLAGS)
356 374
375libgnunet_plugin_transport_xu_la_SOURCES = \
376 plugin_transport_xu.c plugin_transport_xu.h
377libgnunet_plugin_transport_udp_la_LIBADD = \
378 $(top_builddir)/src/hello/libgnunethello.la \
379 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
380 $(top_builddir)/src/statistics/libgnunetstatistics.la \
381 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
382 $(top_builddir)/src/nat/libgnunetnatnew.la \
383 $(top_builddir)/src/util/libgnunetutil.la \
384 $(LTLIBINTL)
385libgnunet_plugin_transport_udp_la_LDFLAGS = \
386 $(GN_PLUGIN_LDFLAGS)
387
357libgnunet_plugin_transport_unix_la_SOURCES = \ 388libgnunet_plugin_transport_unix_la_SOURCES = \
358 plugin_transport_unix.c 389 plugin_transport_unix.c
359libgnunet_plugin_transport_unix_la_LIBADD = \ 390libgnunet_plugin_transport_unix_la_LIBADD = \
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
index cd5aeb5e2..91acc18ed 100644
--- a/src/transport/gnunet-service-transport_validation.c
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -1623,15 +1623,20 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
1623 GNUNET_TRANSPORT_VS_UPDATE); 1623 GNUNET_TRANSPORT_VS_UPDATE);
1624 1624
1625 /* build HELLO to store in PEERINFO */ 1625 /* build HELLO to store in PEERINFO */
1626 GNUNET_STATISTICS_update (GST_stats,
1627 gettext_noop ("# HELLOs given to peerinfo"),
1628 1,
1629 GNUNET_NO);
1626 ve->copied = GNUNET_NO; 1630 ve->copied = GNUNET_NO;
1627 hello = GNUNET_HELLO_create (&ve->address->peer.public_key, 1631 hello = GNUNET_HELLO_create (&ve->address->peer.public_key,
1628 &add_valid_peer_address, 1632 &add_valid_peer_address,
1629 ve, 1633 ve,
1630 GNUNET_NO); 1634 GNUNET_NO);
1631 GNUNET_PEERINFO_add_peer (GST_peerinfo, 1635 GNUNET_break (NULL !=
1632 hello, 1636 GNUNET_PEERINFO_add_peer (GST_peerinfo,
1633 NULL, 1637 hello,
1634 NULL); 1638 NULL,
1639 NULL));
1635 GNUNET_free (hello); 1640 GNUNET_free (hello);
1636 return GNUNET_OK; 1641 return GNUNET_OK;
1637} 1642}
diff --git a/src/transport/plugin_transport_xt.c b/src/transport/plugin_transport_xt.c
new file mode 100644
index 000000000..21ed19da5
--- /dev/null
+++ b/src/transport/plugin_transport_xt.c
@@ -0,0 +1,4107 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002--2015 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @file transport/plugin_transport_xt.c
22 * @brief Implementation of the TCP transport service
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_hello_lib.h"
27#include "gnunet_constants.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_nat_service.h"
30#include "gnunet_protocols.h"
31#include "gnunet_resolver_service.h"
32#include "gnunet_signatures.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_transport_service.h"
35#include "gnunet_transport_plugin.h"
36#include "transport.h"
37
38#define LOG(kind,...) GNUNET_log_from (kind, "transport-xt",__VA_ARGS__)
39
40#define PLUGIN_NAME "xt"
41
42/**
43 * How long until we give up on establishing an NAT connection?
44 * Must be > 4 RTT
45 */
46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47
48/**
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
51 */
52struct GNUNET_CONNECTION_TransmitHandle;
53
54/**
55 * @brief handle for a server
56 */
57struct GNUNET_SERVER_Handle;
58
59/**
60 * @brief opaque handle for a client of the server
61 */
62struct GNUNET_SERVER_Client;
63
64/**
65 * @brief opaque handle server returns for aborting transmission to a client.
66 */
67struct GNUNET_SERVER_TransmitHandle;
68
69/**
70 * @brief handle for a network connection
71 */
72struct GNUNET_CONNECTION_Handle;
73
74/**
75 * @brief handle for a network service
76 */
77struct LEGACY_SERVICE_Context;
78
79
80/**
81 * Stops a service that was started with #GNUNET_SERVICE_start().
82 *
83 * @param srv service to stop
84 */
85void
86LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
87
88
89
90/**
91 * Function called to notify a client about the connection begin ready
92 * to queue more data. @a buf will be NULL and @a size zero if the
93 * connection was closed for writing in the meantime.
94 *
95 * @param cls closure
96 * @param size number of bytes available in @a buf
97 * @param buf where the callee should write the message
98 * @return number of bytes written to @a buf
99 */
100typedef size_t
101(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
102 size_t size,
103 void *buf);
104
105/**
106 * Credentials for UNIX domain sockets.
107 */
108struct GNUNET_CONNECTION_Credentials
109{
110 /**
111 * UID of the other end of the connection.
112 */
113 uid_t uid;
114
115 /**
116 * GID of the other end of the connection.
117 */
118 gid_t gid;
119};
120
121
122/**
123 * Functions with this signature are called whenever a client
124 * is disconnected on the network level.
125 *
126 * @param cls closure
127 * @param client identification of the client; NULL
128 * for the last call when the server is destroyed
129 */
130typedef void
131(*GNUNET_SERVER_DisconnectCallback) (void *cls,
132 struct GNUNET_SERVER_Client *client);
133
134
135/**
136 * Functions with this signature are called whenever a client
137 * is connected on the network level.
138 *
139 * @param cls closure
140 * @param client identification of the client
141 */
142typedef void
143(*GNUNET_SERVER_ConnectCallback) (void *cls,
144 struct GNUNET_SERVER_Client *client);
145
146
147
148
149/**
150 * Function to call for access control checks.
151 *
152 * @param cls closure
153 * @param ucred credentials, if available, otherwise NULL
154 * @param addr address
155 * @param addrlen length of address
156 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
157 * for unknown address family (will be denied).
158 */
159typedef int
160(*GNUNET_CONNECTION_AccessCheck) (void *cls,
161 const struct
162 GNUNET_CONNECTION_Credentials *
163 ucred,
164 const struct sockaddr * addr,
165 socklen_t addrlen);
166
167/**
168 * Callback function for data received from the network. Note that
169 * both "available" and "err" would be 0 if the read simply timed out.
170 *
171 * @param cls closure
172 * @param buf pointer to received data
173 * @param available number of bytes availabe in "buf",
174 * possibly 0 (on errors)
175 * @param addr address of the sender
176 * @param addrlen size of addr
177 * @param errCode value of errno (on errors receiving)
178 */
179typedef void
180(*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
181 size_t available,
182 const struct sockaddr * addr,
183 socklen_t addrlen, int errCode);
184
185
186
187/**
188 * Close the connection and free associated resources. There must
189 * not be any pending requests for reading or writing to the
190 * connection at this time.
191 *
192 * @param connection connection to destroy
193 */
194void
195GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
196
197
198/**
199 * Signature of a function to create a custom tokenizer.
200 *
201 * @param cls closure from #GNUNET_SERVER_set_callbacks
202 * @param client handle to client the tokenzier will be used for
203 * @return handle to custom tokenizer ('mst')
204 */
205typedef void*
206(*GNUNET_SERVER_MstCreateCallback) (void *cls,
207 struct GNUNET_SERVER_Client *client);
208
209
210/**
211 * Signature of a function to destroy a custom tokenizer.
212 *
213 * @param cls closure from #GNUNET_SERVER_set_callbacks
214 * @param mst custom tokenizer handle
215 */
216typedef void
217(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
218 void *mst);
219
220/**
221 * Signature of a function to receive data for a custom tokenizer.
222 *
223 * @param cls closure from #GNUNET_SERVER_set_callbacks
224 * @param mst custom tokenizer handle
225 * @param client_identity ID of client for which this is a buffer,
226 * can be NULL (will be passed back to 'cb')
227 * @param buf input data to add
228 * @param size number of bytes in @a buf
229 * @param purge should any excess bytes in the buffer be discarded
230 * (i.e. for packet-based services like UDP)
231 * @param one_shot only call callback once, keep rest of message in buffer
232 * @return #GNUNET_OK if we are done processing (need more data)
233 * #GNUNET_NO if one_shot was set and we have another message ready
234 * #GNUNET_SYSERR if the data stream is corrupt
235 */
236typedef int
237(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
238 struct GNUNET_SERVER_Client *client,
239 const char *buf,
240 size_t size,
241 int purge,
242 int one_shot);
243/**
244 * Functions with this signature are called whenever a message is
245 * received.
246 *
247 * @param cls closure
248 * @param client identification of the client
249 * @param message the actual message
250 */
251typedef void
252(*GNUNET_SERVER_MessageCallback) (void *cls,
253 struct GNUNET_SERVER_Client *client,
254 const struct GNUNET_MessageHeader *message);
255
256/**
257 * Message handler. Each struct specifies how to handle on particular
258 * type of message received.
259 */
260struct GNUNET_SERVER_MessageHandler
261{
262 /**
263 * Function to call for messages of "type".
264 */
265 GNUNET_SERVER_MessageCallback callback;
266
267 /**
268 * Closure argument for @e callback.
269 */
270 void *callback_cls;
271
272 /**
273 * Type of the message this handler covers.
274 */
275 uint16_t type;
276
277 /**
278 * Expected size of messages of this type. Use 0 for
279 * variable-size. If non-zero, messages of the given
280 * type will be discarded (and the connection closed)
281 * if they do not have the right size.
282 */
283 uint16_t expected_size;
284
285};
286
287
288/**
289 * Options for the service (bitmask).
290 */
291enum LEGACY_SERVICE_Options
292{
293 /**
294 * Use defaults. Terminates all client connections and the listen
295 * sockets immediately upon receiving the shutdown signal.
296 */
297 LEGACY_SERVICE_OPTION_NONE = 0,
298
299 /**
300 * Do not trigger server shutdown on signal at all; instead, allow
301 * for the user to terminate the server explicitly when needed
302 * by calling #LEGACY_SERVICE_shutdown().
303 */
304 LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
305
306 /**
307 * Trigger a SOFT server shutdown on signals, allowing active
308 * non-monitor clients to complete their transactions.
309 */
310 LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
311};
312
313
314
315/**
316 * Ask the server to disconnect from the given client. This is the
317 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
318 * except that it allows dropping of a client even when not handling a
319 * message from that client.
320 *
321 * @param client the client to disconnect from
322 */
323void
324GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
325
326/**
327 * Return user context associated with the given client.
328 * Note: you should probably use the macro (call without the underscore).
329 *
330 * @param client client to query
331 * @param size number of bytes in user context struct (for verification only)
332 * @return pointer to user context
333 */
334void *
335GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
336 size_t size);
337
338
339/**
340 * Functions with this signature are called whenever a
341 * complete message is received by the tokenizer.
342 *
343 * Do not call #GNUNET_SERVER_mst_destroy from within
344 * the scope of this callback.
345 *
346 * @param cls closure
347 * @param client identification of the client
348 * @param message the actual message
349 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
350 */
351typedef int
352(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
353 void *client,
354 const struct GNUNET_MessageHeader *message);
355
356
357/**
358 * Create a message stream tokenizer.
359 *
360 * @param cb function to call on completed messages
361 * @param cb_cls closure for @a cb
362 * @return handle to tokenizer
363 */
364struct GNUNET_SERVER_MessageStreamTokenizer *
365GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
366 void *cb_cls);
367
368/**
369 * Add incoming data to the receive buffer and call the
370 * callback for all complete messages.
371 *
372 * @param mst tokenizer to use
373 * @param client_identity ID of client for which this is a buffer,
374 * can be NULL (will be passed back to 'cb')
375 * @param buf input data to add
376 * @param size number of bytes in @a buf
377 * @param purge should any excess bytes in the buffer be discarded
378 * (i.e. for packet-based services like UDP)
379 * @param one_shot only call callback once, keep rest of message in buffer
380 * @return #GNUNET_OK if we are done processing (need more data)
381 * #GNUNET_NO if one_shot was set and we have another message ready
382 * #GNUNET_SYSERR if the data stream is corrupt
383 */
384int
385GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
386 void *client_identity,
387 const char *buf, size_t size,
388 int purge, int one_shot);
389
390
391
392/**
393 * Destroys a tokenizer.
394 *
395 * @param mst tokenizer to destroy
396 */
397void
398GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
399
400
401/**
402 * Set user context to be associated with the given client.
403 * Note: you should probably use the macro (call without the underscore).
404 *
405 * @param client client to query
406 * @param ptr pointer to user context
407 * @param size number of bytes in user context struct (for verification only)
408 */
409void
410GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
411 void *ptr,
412 size_t size);
413/**
414 * Return user context associated with the given client.
415 *
416 * @param client client to query
417 * @param type expected return type (i.e. 'struct Foo')
418 * @return pointer to user context of type 'type *'.
419 */
420#define GNUNET_SERVER_client_get_user_context(client,type) \
421 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
422
423/**
424 * Set user context to be associated with the given client.
425 *
426 * @param client client to query
427 * @param value pointer to user context
428 */
429#define GNUNET_SERVER_client_set_user_context(client,value) \
430 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
431
432
433
434/**
435 * Notify us when the server has enough space to transmit
436 * a message of the given size to the given client.
437 *
438 * @param client client to transmit message to
439 * @param size requested amount of buffer space
440 * @param timeout after how long should we give up (and call
441 * notify with buf NULL and size 0)?
442 * @param callback function to call when space is available
443 * @param callback_cls closure for @a callback
444 * @return non-NULL if the notify callback was queued; can be used
445 * to cancel the request using
446 * #GNUNET_SERVER_notify_transmit_ready_cancel.
447 * NULL if we are already going to notify someone else (busy)
448 */
449struct GNUNET_SERVER_TransmitHandle *
450GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
451 size_t size,
452 struct GNUNET_TIME_Relative timeout,
453 GNUNET_CONNECTION_TransmitReadyNotify callback,
454 void *callback_cls);
455
456/**
457 * Abort transmission request.
458 *
459 * @param th request to abort
460 */
461void
462GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
463
464
465
466
467/**
468 * Notify the server that the given client handle should
469 * be kept (keeps the connection up if possible, increments
470 * the internal reference counter).
471 *
472 * @param client the client to keep
473 */
474void
475GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
476
477
478/**
479 * Notify the server that the given client handle is no
480 * longer required. Decrements the reference counter. If
481 * that counter reaches zero an inactive connection maybe
482 * closed.
483 *
484 * @param client the client to drop
485 */
486void
487GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
488
489
490/**
491 * Function called by the service's run
492 * method to run service-specific setup code.
493 *
494 * @param cls closure
495 * @param server the initialized server
496 * @param cfg configuration to use
497 */
498typedef void
499(*LEGACY_SERVICE_Main) (void *cls,
500 struct GNUNET_SERVER_Handle *server,
501 const struct GNUNET_CONFIGURATION_Handle *cfg);
502
503
504
505/**
506 * Suspend accepting connections from the listen socket temporarily.
507 * Resume activity using #GNUNET_SERVER_resume.
508 *
509 * @param server server to stop accepting connections.
510 */
511void
512GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
513
514/**
515 * Notify us when the server has enough space to transmit
516 * a message of the given size to the given client.
517 *
518 * @param client client to transmit message to
519 * @param size requested amount of buffer space
520 * @param timeout after how long should we give up (and call
521 * notify with buf NULL and size 0)?
522 * @param callback function to call when space is available
523 * @param callback_cls closure for @a callback
524 * @return non-NULL if the notify callback was queued; can be used
525 * to cancel the request using
526 * #GNUNET_SERVER_notify_transmit_ready_cancel.
527 * NULL if we are already going to notify someone else (busy)
528 */
529struct GNUNET_SERVER_TransmitHandle *
530GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
531 size_t size,
532 struct GNUNET_TIME_Relative timeout,
533 GNUNET_CONNECTION_TransmitReadyNotify callback,
534 void *callback_cls);
535
536
537/**
538 * Add a TCP socket-based connection to the set of handles managed by
539 * this server. Use this function for outgoing (P2P) connections that
540 * we initiated (and where this server should process incoming
541 * messages).
542 *
543 * @param server the server to use
544 * @param connection the connection to manage (client must
545 * stop using this connection from now on)
546 * @return the client handle
547 */
548struct GNUNET_SERVER_Client *
549GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
550 struct GNUNET_CONNECTION_Handle *connection);
551
552
553/**
554 * Resume accepting connections from the listen socket.
555 *
556 * @param server server to resume accepting connections.
557 */
558void
559GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
560
561/**
562 * Free resources held by this server.
563 *
564 * @param server server to destroy
565 */
566void
567GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
568
569
570
571
572#include "tcp_connection_legacy.c"
573#include "tcp_server_mst_legacy.c"
574#include "tcp_server_legacy.c"
575#include "tcp_service_legacy.c"
576
577GNUNET_NETWORK_STRUCT_BEGIN
578
579/**
580 * Initial handshake message for a session.
581 */
582struct WelcomeMessage
583{
584 /**
585 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
586 */
587 struct GNUNET_MessageHeader header;
588
589 /**
590 * Identity of the node connecting (TCP client)
591 */
592 struct GNUNET_PeerIdentity clientIdentity;
593
594};
595
596/**
597 * Basically a WELCOME message, but with the purpose
598 * of giving the waiting peer a client handle to use
599 */
600struct TCP_NAT_ProbeMessage
601{
602 /**
603 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
604 */
605 struct GNUNET_MessageHeader header;
606
607 /**
608 * Identity of the sender of the message.
609 */
610 struct GNUNET_PeerIdentity clientIdentity;
611
612};
613GNUNET_NETWORK_STRUCT_END
614
615/**
616 * Context for sending a NAT probe via TCP.
617 */
618struct TCPProbeContext
619{
620
621 /**
622 * Active probes are kept in a DLL.
623 */
624 struct TCPProbeContext *next;
625
626 /**
627 * Active probes are kept in a DLL.
628 */
629 struct TCPProbeContext *prev;
630
631 /**
632 * Probe connection.
633 */
634 struct GNUNET_CONNECTION_Handle *sock;
635
636 /**
637 * Message to be sent.
638 */
639 struct TCP_NAT_ProbeMessage message;
640
641 /**
642 * Handle to the transmission.
643 */
644 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
645
646 /**
647 * Transport plugin handle.
648 */
649 struct Plugin *plugin;
650};
651
652/**
653 * Bits in the `options` field of TCP addresses.
654 */
655enum TcpAddressOptions
656{
657
658 /**
659 * No bits set.
660 */
661 TCP_OPTIONS_NONE = 0,
662
663 /**
664 * See #HTTP_OPTIONS_VERIFY_CERTIFICATE.
665 */
666 TCP_OPTIONS_RESERVED = 1,
667
668 /**
669 * Enable TCP Stealth-style port knocking.
670 */
671 TCP_OPTIONS_TCP_STEALTH = 2
672};
673
674GNUNET_NETWORK_STRUCT_BEGIN
675
676/**
677 * Network format for IPv4 addresses.
678 */
679struct IPv4TcpAddress
680{
681 /**
682 * Optional options and flags for this address,
683 * see `enum TcpAddressOptions`
684 */
685 uint32_t options GNUNET_PACKED;
686
687 /**
688 * IPv4 address, in network byte order.
689 */
690 uint32_t ipv4_addr GNUNET_PACKED;
691
692 /**
693 * Port number, in network byte order.
694 */
695 uint16_t t4_port GNUNET_PACKED;
696
697};
698
699/**
700 * Network format for IPv6 addresses.
701 */
702struct IPv6TcpAddress
703{
704 /**
705 * Optional flags for this address
706 * see `enum TcpAddressOptions`
707 */
708 uint32_t options GNUNET_PACKED;
709
710 /**
711 * IPv6 address.
712 */
713 struct in6_addr ipv6_addr GNUNET_PACKED;
714
715 /**
716 * Port number, in network byte order.
717 */
718 uint16_t t6_port GNUNET_PACKED;
719
720};
721GNUNET_NETWORK_STRUCT_END
722
723/**
724 * Encapsulation of all of the state of the plugin.
725 */
726struct Plugin;
727
728/**
729 * Information kept for each message that is yet to
730 * be transmitted.
731 */
732struct PendingMessage
733{
734
735 /**
736 * This is a doubly-linked list.
737 */
738 struct PendingMessage *next;
739
740 /**
741 * This is a doubly-linked list.
742 */
743 struct PendingMessage *prev;
744
745 /**
746 * The pending message
747 */
748 const char *msg;
749
750 /**
751 * Continuation function to call once the message
752 * has been sent. Can be NULL if there is no
753 * continuation to call.
754 */
755 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
756
757 /**
758 * Closure for @e transmit_cont.
759 */
760 void *transmit_cont_cls;
761
762 /**
763 * Timeout value for the pending message.
764 */
765 struct GNUNET_TIME_Absolute timeout;
766
767 /**
768 * So that the gnunet-service-transport can group messages together,
769 * these pending messages need to accept a message buffer and size
770 * instead of just a `struct GNUNET_MessageHeader`.
771 */
772 size_t message_size;
773
774};
775
776/**
777 * Session handle for TCP connections.
778 */
779struct GNUNET_ATS_Session
780{
781 /**
782 * To whom are we talking to (set to our identity
783 * if we are still waiting for the welcome message)
784 */
785 struct GNUNET_PeerIdentity target;
786
787 /**
788 * Pointer to the global plugin struct.
789 */
790 struct Plugin *plugin;
791
792 /**
793 * The client (used to identify this connection)
794 */
795 struct GNUNET_SERVER_Client *client;
796
797 /**
798 * Task cleaning up a NAT client connection establishment attempt;
799 */
800 struct GNUNET_SCHEDULER_Task *nat_connection_timeout;
801
802 /**
803 * Messages currently pending for transmission
804 * to this peer, if any.
805 */
806 struct PendingMessage *pending_messages_head;
807
808 /**
809 * Messages currently pending for transmission
810 * to this peer, if any.
811 */
812 struct PendingMessage *pending_messages_tail;
813
814 /**
815 * Handle for pending transmission request.
816 */
817 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
818
819 /**
820 * Address of the other peer.
821 */
822 struct GNUNET_HELLO_Address *address;
823
824 /**
825 * ID of task used to delay receiving more to throttle sender.
826 */
827 struct GNUNET_SCHEDULER_Task *receive_delay_task;
828
829 /**
830 * Session timeout task
831 */
832 struct GNUNET_SCHEDULER_Task *timeout_task;
833
834 /**
835 * When will this session time out?
836 */
837 struct GNUNET_TIME_Absolute timeout;
838
839 /**
840 * When will we continue to read from the socket?
841 * (used to enforce inbound quota).
842 */
843 struct GNUNET_TIME_Absolute receive_delay;
844
845 /**
846 * Last activity on this connection. Used to select preferred
847 * connection.
848 */
849 struct GNUNET_TIME_Absolute last_activity;
850
851 /**
852 * Number of bytes waiting for transmission to this peer.
853 */
854 unsigned long long bytes_in_queue;
855
856 /**
857 * Number of messages waiting for transmission to this peer.
858 */
859 unsigned int msgs_in_queue;
860
861 /**
862 * Network type of the address.
863 */
864 enum GNUNET_ATS_Network_Type scope;
865
866 /**
867 * Are we still expecting the welcome message? (#GNUNET_YES/#GNUNET_NO)
868 */
869 int expecting_welcome;
870
871 /**
872 * Was this session created using NAT traversal?
873 */
874 int is_nat;
875
876};
877
878
879/**
880 * Context for address to string conversion, closure
881 * for #append_port().
882 */
883struct PrettyPrinterContext
884{
885 /**
886 * DLL
887 */
888 struct PrettyPrinterContext *next;
889
890 /**
891 * DLL
892 */
893 struct PrettyPrinterContext *prev;
894
895 /**
896 * Our plugin.
897 */
898 struct Plugin *plugin;
899
900 /**
901 * Timeout task
902 */
903 struct GNUNET_SCHEDULER_Task *timeout_task;
904
905 /**
906 * Resolver handle
907 */
908 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
909
910 /**
911 * Function to call with the result.
912 */
913 GNUNET_TRANSPORT_AddressStringCallback asc;
914
915 /**
916 * Clsoure for @e asc.
917 */
918 void *asc_cls;
919
920 /**
921 * IPv6 address
922 */
923 int ipv6;
924
925 /**
926 * Options
927 */
928 uint32_t options;
929
930 /**
931 * Port to add after the IP address.
932 */
933 uint16_t port;
934};
935
936
937/**
938 * Encapsulation of all of the state of the plugin.
939 */
940struct Plugin
941{
942 /**
943 * Our environment.
944 */
945 struct GNUNET_TRANSPORT_PluginEnvironment *env;
946
947 /**
948 * The listen socket.
949 */
950 struct GNUNET_CONNECTION_Handle *lsock;
951
952 /**
953 * Our handle to the NAT module.
954 */
955 struct GNUNET_NAT_Handle *nat;
956
957 /**
958 * Map from peer identities to sessions for the given peer.
959 */
960 struct GNUNET_CONTAINER_MultiPeerMap *sessionmap;
961
962 /**
963 * Handle to the network service.
964 */
965 struct LEGACY_SERVICE_Context *service;
966
967 /**
968 * Handle to the server for this service.
969 */
970 struct GNUNET_SERVER_Handle *server;
971
972 /**
973 * Copy of the handler array where the closures are
974 * set to this struct's instance.
975 */
976 struct GNUNET_SERVER_MessageHandler *handlers;
977
978 /**
979 * Map of peers we have tried to contact behind a NAT
980 */
981 struct GNUNET_CONTAINER_MultiPeerMap *nat_wait_conns;
982
983 /**
984 * List of active TCP probes.
985 */
986 struct TCPProbeContext *probe_head;
987
988 /**
989 * List of active TCP probes.
990 */
991 struct TCPProbeContext *probe_tail;
992
993 /**
994 * Function to call about session status changes.
995 */
996 GNUNET_TRANSPORT_SessionInfoCallback sic;
997
998 /**
999 * Closure for @e sic.
1000 */
1001 void *sic_cls;
1002
1003 /**
1004 * ID of task used to update our addresses when one expires.
1005 */
1006 struct GNUNET_SCHEDULER_Task *address_update_task;
1007
1008 /**
1009 * Running pretty printers: head
1010 */
1011 struct PrettyPrinterContext *ppc_dll_head;
1012
1013 /**
1014 * Running pretty printers: tail
1015 */
1016 struct PrettyPrinterContext *ppc_dll_tail;
1017
1018 /**
1019 * Welcome message used by this peer.
1020 */
1021 struct WelcomeMessage my_welcome;
1022
1023 /**
1024 * How many more TCP sessions are we allowed to open right now?
1025 */
1026 unsigned long long max_connections;
1027
1028 /**
1029 * How many more TCP sessions do we have right now?
1030 */
1031 unsigned long long cur_connections;
1032
1033 /**
1034 * Address options
1035 */
1036 uint32_t myoptions;
1037
1038 /**
1039 * Port that we are actually listening on.
1040 */
1041 uint16_t open_port;
1042
1043 /**
1044 * Port that the user said we would have visible to the
1045 * rest of the world.
1046 */
1047 uint16_t adv_port;
1048
1049};
1050
1051
1052/**
1053 * Get the list of addresses that a server for the given service
1054 * should bind to.
1055 *
1056 * @param service_name name of the service
1057 * @param cfg configuration (which specifies the addresses)
1058 * @param addrs set (call by reference) to an array of pointers to the
1059 * addresses the server should bind to and listen on; the
1060 * array will be NULL-terminated (on success)
1061 * @param addr_lens set (call by reference) to an array of the lengths
1062 * of the respective `struct sockaddr` struct in the @a addrs
1063 * array (on success)
1064 * @return number of addresses found on success,
1065 * #GNUNET_SYSERR if the configuration
1066 * did not specify reasonable finding information or
1067 * if it specified a hostname that could not be resolved;
1068 * #GNUNET_NO if the number of addresses configured is
1069 * zero (in this case, `*addrs` and `*addr_lens` will be
1070 * set to NULL).
1071 */
1072static int
1073get_server_addresses (const char *service_name,
1074 const struct GNUNET_CONFIGURATION_Handle *cfg,
1075 struct sockaddr ***addrs,
1076 socklen_t ** addr_lens)
1077{
1078 int disablev6;
1079 struct GNUNET_NETWORK_Handle *desc;
1080 unsigned long long port;
1081 char *unixpath;
1082 struct addrinfo hints;
1083 struct addrinfo *res;
1084 struct addrinfo *pos;
1085 struct addrinfo *next;
1086 unsigned int i;
1087 int resi;
1088 int ret;
1089 int abstract;
1090 struct sockaddr **saddrs;
1091 socklen_t *saddrlens;
1092 char *hostname;
1093
1094 *addrs = NULL;
1095 *addr_lens = NULL;
1096 desc = NULL;
1097 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
1098 {
1099 if (GNUNET_SYSERR ==
1100 (disablev6 =
1101 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1102 return GNUNET_SYSERR;
1103 }
1104 else
1105 disablev6 = GNUNET_NO;
1106
1107 if (! disablev6)
1108 {
1109 /* probe IPv6 support */
1110 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1111 if (NULL == desc)
1112 {
1113 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1114 (EACCES == errno))
1115 {
1116 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1117 return GNUNET_SYSERR;
1118 }
1119 LOG (GNUNET_ERROR_TYPE_INFO,
1120 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
1121 service_name, STRERROR (errno));
1122 disablev6 = GNUNET_YES;
1123 }
1124 else
1125 {
1126 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1127 desc = NULL;
1128 }
1129 }
1130
1131 port = 0;
1132 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1133 {
1134 if (GNUNET_OK !=
1135 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
1136 "PORT", &port))
1137 {
1138 LOG (GNUNET_ERROR_TYPE_ERROR,
1139 _("Require valid port number for service `%s' in configuration!\n"),
1140 service_name);
1141 }
1142 if (port > 65535)
1143 {
1144 LOG (GNUNET_ERROR_TYPE_ERROR,
1145 _("Require valid port number for service `%s' in configuration!\n"),
1146 service_name);
1147 return GNUNET_SYSERR;
1148 }
1149 }
1150
1151 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1152 {
1153 GNUNET_break (GNUNET_OK ==
1154 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
1155 "BINDTO", &hostname));
1156 }
1157 else
1158 hostname = NULL;
1159
1160 unixpath = NULL;
1161 abstract = GNUNET_NO;
1162#ifdef AF_UNIX
1163 if ((GNUNET_YES ==
1164 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1165 (GNUNET_OK ==
1166 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
1167 &unixpath)) &&
1168 (0 < strlen (unixpath)))
1169 {
1170 /* probe UNIX support */
1171 struct sockaddr_un s_un;
1172
1173 if (strlen (unixpath) >= sizeof (s_un.sun_path))
1174 {
1175 LOG (GNUNET_ERROR_TYPE_WARNING,
1176 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
1177 (unsigned long long) sizeof (s_un.sun_path));
1178 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1179 LOG (GNUNET_ERROR_TYPE_INFO,
1180 _("Using `%s' instead\n"),
1181 unixpath);
1182 }
1183#ifdef LINUX
1184 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1185 "TESTING",
1186 "USE_ABSTRACT_SOCKETS");
1187 if (GNUNET_SYSERR == abstract)
1188 abstract = GNUNET_NO;
1189#endif
1190 if ((GNUNET_YES != abstract)
1191 && (GNUNET_OK !=
1192 GNUNET_DISK_directory_create_for_file (unixpath)))
1193 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1194 "mkdir",
1195 unixpath);
1196 }
1197 if (NULL != unixpath)
1198 {
1199 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1200 if (NULL == desc)
1201 {
1202 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1203 (EACCES == errno))
1204 {
1205 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1206 GNUNET_free_non_null (hostname);
1207 GNUNET_free (unixpath);
1208 return GNUNET_SYSERR;
1209 }
1210 LOG (GNUNET_ERROR_TYPE_INFO,
1211 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1212 service_name,
1213 STRERROR (errno));
1214 GNUNET_free (unixpath);
1215 unixpath = NULL;
1216 }
1217 else
1218 {
1219 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1220 desc = NULL;
1221 }
1222 }
1223#endif
1224
1225 if ((0 == port) && (NULL == unixpath))
1226 {
1227 LOG (GNUNET_ERROR_TYPE_ERROR,
1228 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1229 service_name);
1230 GNUNET_free_non_null (hostname);
1231 return GNUNET_SYSERR;
1232 }
1233 if (0 == port)
1234 {
1235 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1236 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1237 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1238 GNUNET_free_non_null (unixpath);
1239 GNUNET_free_non_null (hostname);
1240 *addrs = saddrs;
1241 *addr_lens = saddrlens;
1242 return 1;
1243 }
1244
1245 if (NULL != hostname)
1246 {
1247 LOG (GNUNET_ERROR_TYPE_DEBUG,
1248 "Resolving `%s' since that is where `%s' will bind to.\n",
1249 hostname,
1250 service_name);
1251 memset (&hints, 0, sizeof (struct addrinfo));
1252 if (disablev6)
1253 hints.ai_family = AF_INET;
1254 hints.ai_protocol = IPPROTO_TCP;
1255 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1256 (NULL == res))
1257 {
1258 LOG (GNUNET_ERROR_TYPE_ERROR,
1259 _("Failed to resolve `%s': %s\n"),
1260 hostname,
1261 gai_strerror (ret));
1262 GNUNET_free (hostname);
1263 GNUNET_free_non_null (unixpath);
1264 return GNUNET_SYSERR;
1265 }
1266 next = res;
1267 i = 0;
1268 while (NULL != (pos = next))
1269 {
1270 next = pos->ai_next;
1271 if ((disablev6) && (pos->ai_family == AF_INET6))
1272 continue;
1273 i++;
1274 }
1275 if (0 == i)
1276 {
1277 LOG (GNUNET_ERROR_TYPE_ERROR,
1278 _("Failed to find %saddress for `%s'.\n"),
1279 disablev6 ? "IPv4 " : "",
1280 hostname);
1281 freeaddrinfo (res);
1282 GNUNET_free (hostname);
1283 GNUNET_free_non_null (unixpath);
1284 return GNUNET_SYSERR;
1285 }
1286 resi = i;
1287 if (NULL != unixpath)
1288 resi++;
1289 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1290 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1291 i = 0;
1292 if (NULL != unixpath)
1293 {
1294 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1295 i++;
1296 }
1297 next = res;
1298 while (NULL != (pos = next))
1299 {
1300 next = pos->ai_next;
1301 if ((disablev6) && (AF_INET6 == pos->ai_family))
1302 continue;
1303 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1304 continue; /* not TCP */
1305 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1306 continue; /* huh? */
1307 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1308 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1309 if (AF_INET == pos->ai_family)
1310 {
1311 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1312 saddrlens[i] = pos->ai_addrlen;
1313 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1314 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1315 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1316 }
1317 else
1318 {
1319 GNUNET_assert (AF_INET6 == pos->ai_family);
1320 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1321 saddrlens[i] = pos->ai_addrlen;
1322 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1323 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1324 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1325 }
1326 i++;
1327 }
1328 GNUNET_free (hostname);
1329 freeaddrinfo (res);
1330 resi = i;
1331 }
1332 else
1333 {
1334 /* will bind against everything, just set port */
1335 if (disablev6)
1336 {
1337 /* V4-only */
1338 resi = 1;
1339 if (NULL != unixpath)
1340 resi++;
1341 i = 0;
1342 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1343 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1344 if (NULL != unixpath)
1345 {
1346 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1347 i++;
1348 }
1349 saddrlens[i] = sizeof (struct sockaddr_in);
1350 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1351#if HAVE_SOCKADDR_IN_SIN_LEN
1352 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1353#endif
1354 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1355 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1356 }
1357 else
1358 {
1359 /* dual stack */
1360 resi = 2;
1361 if (NULL != unixpath)
1362 resi++;
1363 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1364 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1365 i = 0;
1366 if (NULL != unixpath)
1367 {
1368 add_unixpath (saddrs, saddrlens, unixpath, abstract);
1369 i++;
1370 }
1371 saddrlens[i] = sizeof (struct sockaddr_in6);
1372 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1373#if HAVE_SOCKADDR_IN_SIN_LEN
1374 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1375#endif
1376 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1377 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1378 i++;
1379 saddrlens[i] = sizeof (struct sockaddr_in);
1380 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1381#if HAVE_SOCKADDR_IN_SIN_LEN
1382 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1383#endif
1384 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1385 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1386 }
1387 }
1388 GNUNET_free_non_null (unixpath);
1389 *addrs = saddrs;
1390 *addr_lens = saddrlens;
1391 return resi;
1392}
1393/* end ancient copy-and-paste */
1394
1395
1396/**
1397 * If a session monitor is attached, notify it about the new
1398 * session state.
1399 *
1400 * @param plugin our plugin
1401 * @param session session that changed state
1402 * @param state new state of the session
1403 */
1404static void
1405notify_session_monitor (struct Plugin *plugin,
1406 struct GNUNET_ATS_Session *session,
1407 enum GNUNET_TRANSPORT_SessionState state)
1408{
1409 struct GNUNET_TRANSPORT_SessionInfo info;
1410
1411 if (NULL == plugin->sic)
1412 return;
1413 memset (&info, 0, sizeof (info));
1414 info.state = state;
1415 info.is_inbound = GNUNET_HELLO_address_check_option (session->address,
1416 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1417 info.num_msg_pending = session->msgs_in_queue;
1418 info.num_bytes_pending = session->bytes_in_queue;
1419 if (NULL != session->receive_delay_task)
1420 info.receive_delay = session->receive_delay;
1421 info.session_timeout = session->timeout;
1422 info.address = session->address;
1423 plugin->sic (plugin->sic_cls,
1424 session,
1425 &info);
1426}
1427
1428
1429/**
1430 * Our external IP address/port mapping has changed.
1431 *
1432 * @param cls closure, the `struct Plugin`
1433 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1434 * the previous (now invalid) one
1435 * @param ac address class the address belongs to
1436 * @param addr either the previous or the new public IP address
1437 * @param addrlen actual length of @a addr
1438 */
1439static void
1440tcp_nat_port_map_callback (void *cls,
1441 int add_remove,
1442 enum GNUNET_NAT_AddressClass ac,
1443 const struct sockaddr *addr,
1444 socklen_t addrlen)
1445{
1446 struct Plugin *plugin = cls;
1447 struct GNUNET_HELLO_Address *address;
1448 struct IPv4TcpAddress t4;
1449 struct IPv6TcpAddress t6;
1450 void *arg;
1451 size_t args;
1452
1453 if (GNUNET_NAT_AC_LOOPBACK == ac)
1454 return;
1455 if (GNUNET_NAT_AC_LAN == ac)
1456 return;
1457 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
1458 return;
1459 LOG (GNUNET_ERROR_TYPE_INFO,
1460 "NAT notification to %s address `%s'\n",
1461 (GNUNET_YES == add_remove) ? "add" : "remove",
1462 GNUNET_a2s (addr, addrlen));
1463 /* convert 'addr' to our internal format */
1464 switch (addr->sa_family)
1465 {
1466 case AF_INET:
1467 GNUNET_assert(addrlen == sizeof(struct sockaddr_in));
1468 memset (&t4, 0, sizeof(t4));
1469 t4.options = htonl (plugin->myoptions);
1470 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1471 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
1472 arg = &t4;
1473 args = sizeof (t4);
1474 break;
1475 case AF_INET6:
1476 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1477 memset (&t6, 0, sizeof(t6));
1478 GNUNET_memcpy (&t6.ipv6_addr,
1479 &((struct sockaddr_in6 *) addr)->sin6_addr,
1480 sizeof(struct in6_addr));
1481 t6.options = htonl (plugin->myoptions);
1482 t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
1483 arg = &t6;
1484 args = sizeof (t6);
1485 break;
1486 default:
1487 GNUNET_break(0);
1488 return;
1489 }
1490 /* modify our published address list */
1491 GNUNET_assert ((args == sizeof (struct IPv4TcpAddress)) ||
1492 (args == sizeof (struct IPv6TcpAddress)));
1493 /* TODO: use 'ac' here in the future... */
1494 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1495 PLUGIN_NAME,
1496 arg,
1497 args,
1498 GNUNET_HELLO_ADDRESS_INFO_NONE);
1499 plugin->env->notify_address (plugin->env->cls,
1500 add_remove,
1501 address);
1502 GNUNET_HELLO_address_free (address);
1503}
1504
1505
1506/**
1507 * Function called for a quick conversion of the binary address to
1508 * a numeric address. Note that the caller must not free the
1509 * address and that the next call to this function is allowed
1510 * to override the address again.
1511 *
1512 * @param cls closure (`struct Plugin*`)
1513 * @param addr binary address
1514 * @param addrlen length of @a addr
1515 * @return string representing the same address
1516 */
1517static const char *
1518tcp_plugin_address_to_string (void *cls,
1519 const void *addr,
1520 size_t addrlen)
1521{
1522 static char rbuf[INET6_ADDRSTRLEN + 12];
1523 char buf[INET6_ADDRSTRLEN];
1524 const void *sb;
1525 struct in_addr a4;
1526 struct in6_addr a6;
1527 const struct IPv4TcpAddress *t4;
1528 const struct IPv6TcpAddress *t6;
1529 int af;
1530 uint16_t port;
1531 uint32_t options;
1532
1533 switch (addrlen)
1534 {
1535 case sizeof(struct IPv6TcpAddress):
1536 t6 = addr;
1537 af = AF_INET6;
1538 port = ntohs (t6->t6_port);
1539 options = ntohl (t6->options);
1540 GNUNET_memcpy (&a6, &t6->ipv6_addr, sizeof(a6));
1541 sb = &a6;
1542 break;
1543 case sizeof(struct IPv4TcpAddress):
1544 t4 = addr;
1545 af = AF_INET;
1546 port = ntohs (t4->t4_port);
1547 options = ntohl (t4->options);
1548 GNUNET_memcpy (&a4, &t4->ipv4_addr, sizeof(a4));
1549 sb = &a4;
1550 break;
1551 default:
1552 LOG (GNUNET_ERROR_TYPE_WARNING,
1553 _("Unexpected address length: %u bytes\n"),
1554 (unsigned int) addrlen);
1555 return NULL ;
1556 }
1557 if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
1558 {
1559 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1560 "inet_ntop");
1561 return NULL ;
1562 }
1563 GNUNET_snprintf (rbuf, sizeof(rbuf),
1564 (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u",
1565 PLUGIN_NAME,
1566 options,
1567 buf,
1568 port);
1569 return rbuf;
1570}
1571
1572
1573/**
1574 * Function called to convert a string address to
1575 * a binary address.
1576 *
1577 * @param cls closure (`struct Plugin*`)
1578 * @param addr string address
1579 * @param addrlen length of the address
1580 * @param buf location to store the buffer
1581 * @param added location to store the number of bytes in the buffer.
1582 * If the function returns #GNUNET_SYSERR, its contents are undefined.
1583 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1584 */
1585static int
1586tcp_plugin_string_to_address (void *cls,
1587 const char *addr,
1588 uint16_t addrlen,
1589 void **buf,
1590 size_t *added)
1591{
1592 struct sockaddr_storage socket_address;
1593 char *address;
1594 char *plugin;
1595 char *optionstr;
1596 uint32_t options;
1597
1598 /* Format tcp.options.address:port */
1599 address = NULL;
1600 plugin = NULL;
1601 optionstr = NULL;
1602 if ((NULL == addr) || (0 == addrlen))
1603 {
1604 GNUNET_break(0);
1605 return GNUNET_SYSERR;
1606 }
1607 if ('\0' != addr[addrlen - 1])
1608 {
1609 GNUNET_break(0);
1610 return GNUNET_SYSERR;
1611 }
1612 if (strlen (addr) != addrlen - 1)
1613 {
1614 GNUNET_break(0);
1615 return GNUNET_SYSERR;
1616 }
1617 plugin = GNUNET_strdup (addr);
1618 optionstr = strchr (plugin, '.');
1619 if (NULL == optionstr)
1620 {
1621 GNUNET_break(0);
1622 GNUNET_free(plugin);
1623 return GNUNET_SYSERR;
1624 }
1625 optionstr[0] = '\0';
1626 optionstr++;
1627 options = atol (optionstr);
1628 address = strchr (optionstr, '.');
1629 if (NULL == address)
1630 {
1631 GNUNET_break(0);
1632 GNUNET_free(plugin);
1633 return GNUNET_SYSERR;
1634 }
1635 address[0] = '\0';
1636 address++;
1637
1638 if (GNUNET_OK !=
1639 GNUNET_STRINGS_to_address_ip (address,
1640 strlen (address),
1641 &socket_address))
1642 {
1643 GNUNET_break(0);
1644 GNUNET_free(plugin);
1645 return GNUNET_SYSERR;
1646 }
1647
1648 GNUNET_free(plugin);
1649 switch (socket_address.ss_family)
1650 {
1651 case AF_INET:
1652 {
1653 struct IPv4TcpAddress *t4;
1654 struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address;
1655 t4 = GNUNET_new (struct IPv4TcpAddress);
1656 t4->options = htonl (options);
1657 t4->ipv4_addr = in4->sin_addr.s_addr;
1658 t4->t4_port = in4->sin_port;
1659 *buf = t4;
1660 *added = sizeof(struct IPv4TcpAddress);
1661 return GNUNET_OK;
1662 }
1663 case AF_INET6:
1664 {
1665 struct IPv6TcpAddress *t6;
1666 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address;
1667 t6 = GNUNET_new (struct IPv6TcpAddress);
1668 t6->options = htonl (options);
1669 t6->ipv6_addr = in6->sin6_addr;
1670 t6->t6_port = in6->sin6_port;
1671 *buf = t6;
1672 *added = sizeof(struct IPv6TcpAddress);
1673 return GNUNET_OK;
1674 }
1675 default:
1676 return GNUNET_SYSERR;
1677 }
1678}
1679
1680
1681/**
1682 * Find the session handle for the given client.
1683 * Currently uses both the hashmap and the client
1684 * context, as the client context is new and the
1685 * logic still needs to be tested.
1686 *
1687 * @param plugin the plugin
1688 * @param client which client to find the session handle for
1689 * @return NULL if no matching session exists
1690 */
1691static struct GNUNET_ATS_Session *
1692lookup_session_by_client (struct Plugin *plugin,
1693 struct GNUNET_SERVER_Client *client)
1694{
1695 return GNUNET_SERVER_client_get_user_context (client,
1696 struct GNUNET_ATS_Session);
1697}
1698
1699
1700/**
1701 * Functions with this signature are called whenever we need
1702 * to close a session due to a disconnect or failure to
1703 * establish a connection.
1704 *
1705 * @param cls the `struct Plugin`
1706 * @param session session to close down
1707 * @return #GNUNET_OK on success
1708 */
1709static int
1710tcp_plugin_disconnect_session (void *cls,
1711 struct GNUNET_ATS_Session *session)
1712{
1713 struct Plugin *plugin = cls;
1714 struct PendingMessage *pm;
1715
1716 LOG (GNUNET_ERROR_TYPE_DEBUG,
1717 "Disconnecting session of peer `%s' address `%s'\n",
1718 GNUNET_i2s (&session->target),
1719 tcp_plugin_address_to_string (session->plugin,
1720 session->address->address,
1721 session->address->address_length));
1722
1723 if (NULL != session->timeout_task)
1724 {
1725 GNUNET_SCHEDULER_cancel (session->timeout_task);
1726 session->timeout_task = NULL;
1727 session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
1728 }
1729
1730 if (GNUNET_YES ==
1731 GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
1732 &session->target,
1733 session))
1734 {
1735 GNUNET_STATISTICS_update (session->plugin->env->stats,
1736 gettext_noop ("# TCP sessions active"),
1737 -1,
1738 GNUNET_NO);
1739 }
1740 else
1741 {
1742 GNUNET_assert (GNUNET_YES ==
1743 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
1744 &session->target,
1745 session));
1746 }
1747 if (NULL != session->client)
1748 GNUNET_SERVER_client_set_user_context (session->client,
1749 NULL);
1750
1751 /* clean up state */
1752 if (NULL != session->transmit_handle)
1753 {
1754 GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
1755 session->transmit_handle = NULL;
1756 }
1757 session->plugin->env->session_end (session->plugin->env->cls,
1758 session->address,
1759 session);
1760
1761 if (NULL != session->nat_connection_timeout)
1762 {
1763 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
1764 session->nat_connection_timeout = NULL;
1765 }
1766
1767 while (NULL != (pm = session->pending_messages_head))
1768 {
1769 LOG (GNUNET_ERROR_TYPE_DEBUG,
1770 (NULL != pm->transmit_cont)
1771 ? "Could not deliver message to `%s' at %s.\n"
1772 : "Could not deliver message to `%s' at %s, notifying.\n",
1773 GNUNET_i2s (&session->target),
1774 tcp_plugin_address_to_string (session->plugin,
1775 session->address->address,
1776 session->address->address_length));
1777 GNUNET_STATISTICS_update (session->plugin->env->stats,
1778 gettext_noop ("# bytes currently in TCP buffers"),
1779 -(int64_t) pm->message_size, GNUNET_NO);
1780 GNUNET_STATISTICS_update (session->plugin->env->stats,
1781 gettext_noop ("# bytes discarded by TCP (disconnect)"),
1782 pm->message_size,
1783 GNUNET_NO);
1784 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
1785 session->pending_messages_tail,
1786 pm);
1787 GNUNET_assert (0 < session->msgs_in_queue);
1788 session->msgs_in_queue--;
1789 GNUNET_assert (pm->message_size <= session->bytes_in_queue);
1790 session->bytes_in_queue -= pm->message_size;
1791 if (NULL != pm->transmit_cont)
1792 pm->transmit_cont (pm->transmit_cont_cls,
1793 &session->target,
1794 GNUNET_SYSERR,
1795 pm->message_size,
1796 0);
1797 GNUNET_free (pm);
1798 }
1799 GNUNET_assert (0 == session->msgs_in_queue);
1800 GNUNET_assert (0 == session->bytes_in_queue);
1801 notify_session_monitor (session->plugin,
1802 session,
1803 GNUNET_TRANSPORT_SS_DONE);
1804
1805 if (NULL != session->receive_delay_task)
1806 {
1807 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
1808 session->receive_delay_task = NULL;
1809 }
1810 if (NULL != session->client)
1811 {
1812 GNUNET_SERVER_client_disconnect (session->client);
1813 session->client = NULL;
1814 }
1815 GNUNET_HELLO_address_free (session->address);
1816 GNUNET_assert (NULL == session->transmit_handle);
1817 GNUNET_free (session);
1818 return GNUNET_OK;
1819}
1820
1821
1822/**
1823 * Function that is called to get the keepalive factor.
1824 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
1825 * calculate the interval between keepalive packets.
1826 *
1827 * @param cls closure with the `struct Plugin`
1828 * @return keepalive factor
1829 */
1830static unsigned int
1831tcp_plugin_query_keepalive_factor (void *cls)
1832{
1833 return 3;
1834}
1835
1836
1837/**
1838 * Session was idle for too long, so disconnect it
1839 *
1840 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1841 */
1842static void
1843session_timeout (void *cls)
1844{
1845 struct GNUNET_ATS_Session *s = cls;
1846 struct GNUNET_TIME_Relative left;
1847
1848 s->timeout_task = NULL;
1849 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1850 if (0 != left.rel_value_us)
1851 {
1852 /* not actually our turn yet, but let's at least update
1853 the monitor, it may think we're about to die ... */
1854 notify_session_monitor (s->plugin,
1855 s,
1856 GNUNET_TRANSPORT_SS_UPDATE);
1857 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1858 &session_timeout,
1859 s);
1860 return;
1861 }
1862 LOG (GNUNET_ERROR_TYPE_DEBUG,
1863 "Session %p was idle for %s, disconnecting\n",
1864 s,
1865 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1866 GNUNET_YES));
1867 /* call session destroy function */
1868 tcp_plugin_disconnect_session (s->plugin,
1869 s);
1870}
1871
1872
1873/**
1874 * Increment session timeout due to activity.
1875 *
1876 * @param s session to increment timeout for
1877 */
1878static void
1879reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1880{
1881 GNUNET_assert (NULL != s->timeout_task);
1882 s->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1883}
1884
1885
1886/**
1887 * Create a new session. Also queues a welcome message.
1888 *
1889 * @param plugin the plugin
1890 * @param address the address to create the session for
1891 * @param scope network scope the address is from
1892 * @param client client to use, reference counter must have already been increased
1893 * @param is_nat this a NAT session, we should wait for a client to
1894 * connect to us from an address, then assign that to
1895 * the session
1896 * @return new session object
1897 */
1898static struct GNUNET_ATS_Session *
1899create_session (struct Plugin *plugin,
1900 const struct GNUNET_HELLO_Address *address,
1901 enum GNUNET_ATS_Network_Type scope,
1902 struct GNUNET_SERVER_Client *client,
1903 int is_nat)
1904{
1905 struct GNUNET_ATS_Session *session;
1906 struct PendingMessage *pm;
1907
1908 if (GNUNET_YES != is_nat)
1909 GNUNET_assert (NULL != client);
1910 else
1911 GNUNET_assert (NULL == client);
1912
1913 LOG (GNUNET_ERROR_TYPE_DEBUG,
1914 "Creating new session for peer `%s' at address %s\n",
1915 GNUNET_i2s (&address->peer),
1916 tcp_plugin_address_to_string (plugin,
1917 address->address,
1918 address->address_length));
1919 session = GNUNET_new (struct GNUNET_ATS_Session);
1920 session->last_activity = GNUNET_TIME_absolute_get ();
1921 session->plugin = plugin;
1922 session->is_nat = is_nat;
1923 if (NULL != client)
1924 {
1925 session->client = client;
1926 GNUNET_SERVER_client_set_user_context (client,
1927 session);
1928 }
1929 session->address = GNUNET_HELLO_address_copy (address);
1930 session->target = address->peer;
1931 session->expecting_welcome = GNUNET_YES;
1932 session->scope = scope;
1933 pm = GNUNET_malloc (sizeof (struct PendingMessage) +
1934 sizeof (struct WelcomeMessage));
1935 pm->msg = (const char *) &pm[1];
1936 pm->message_size = sizeof(struct WelcomeMessage);
1937 GNUNET_memcpy (&pm[1],
1938 &plugin->my_welcome,
1939 sizeof(struct WelcomeMessage));
1940 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
1941 GNUNET_STATISTICS_update (plugin->env->stats,
1942 gettext_noop ("# bytes currently in TCP buffers"),
1943 pm->message_size,
1944 GNUNET_NO);
1945 GNUNET_CONTAINER_DLL_insert (session->pending_messages_head,
1946 session->pending_messages_tail,
1947 pm);
1948 session->msgs_in_queue++;
1949 session->bytes_in_queue += pm->message_size;
1950 session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1951 session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1952 &session_timeout,
1953 session);
1954 notify_session_monitor (session->plugin,
1955 session,
1956 GNUNET_TRANSPORT_SS_INIT);
1957 if (GNUNET_YES != is_nat)
1958 {
1959 GNUNET_STATISTICS_update (plugin->env->stats,
1960 gettext_noop ("# TCP sessions active"),
1961 1,
1962 GNUNET_NO);
1963 notify_session_monitor (session->plugin,
1964 session,
1965 GNUNET_TRANSPORT_SS_UP);
1966 }
1967 else
1968 {
1969 notify_session_monitor (session->plugin,
1970 session,
1971 GNUNET_TRANSPORT_SS_HANDSHAKE);
1972 }
1973 return session;
1974}
1975
1976
1977/**
1978 * If we have pending messages, ask the server to
1979 * transmit them (schedule the respective tasks, etc.)
1980 *
1981 * @param session for which session should we do this
1982 */
1983static void
1984process_pending_messages (struct GNUNET_ATS_Session *session);
1985
1986
1987/**
1988 * Function called to notify a client about the socket
1989 * being ready to queue more data. "buf" will be
1990 * NULL and "size" zero if the socket was closed for
1991 * writing in the meantime.
1992 *
1993 * @param cls closure
1994 * @param size number of bytes available in @a buf
1995 * @param buf where the callee should write the message
1996 * @return number of bytes written to @a buf
1997 */
1998static size_t
1999do_transmit (void *cls,
2000 size_t size,
2001 void *buf)
2002{
2003 struct GNUNET_ATS_Session *session = cls;
2004 struct GNUNET_PeerIdentity pid;
2005 struct Plugin *plugin;
2006 struct PendingMessage *pos;
2007 struct PendingMessage *hd;
2008 struct PendingMessage *tl;
2009 struct GNUNET_TIME_Absolute now;
2010 char *cbuf;
2011 size_t ret;
2012
2013 session->transmit_handle = NULL;
2014 plugin = session->plugin;
2015 if (NULL == buf)
2016 {
2017 LOG (GNUNET_ERROR_TYPE_DEBUG,
2018 "Timeout trying to transmit to peer `%s', discarding message queue.\n",
2019 GNUNET_i2s (&session->target));
2020 /* timeout; cancel all messages that have already expired */
2021 hd = NULL;
2022 tl = NULL;
2023 ret = 0;
2024 now = GNUNET_TIME_absolute_get ();
2025 while ( (NULL != (pos = session->pending_messages_head)) &&
2026 (pos->timeout.abs_value_us <= now.abs_value_us) )
2027 {
2028 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2029 session->pending_messages_tail,
2030 pos);
2031 GNUNET_assert (0 < session->msgs_in_queue);
2032 session->msgs_in_queue--;
2033 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2034 session->bytes_in_queue -= pos->message_size;
2035 LOG (GNUNET_ERROR_TYPE_DEBUG,
2036 "Failed to transmit %u byte message to `%s'.\n",
2037 pos->message_size,
2038 GNUNET_i2s (&session->target));
2039 ret += pos->message_size;
2040 GNUNET_CONTAINER_DLL_insert_after (hd,
2041 tl,
2042 tl,
2043 pos);
2044 }
2045 /* do this call before callbacks (so that if callbacks destroy
2046 * session, they have a chance to cancel actions done by this
2047 * call) */
2048 process_pending_messages (session);
2049 pid = session->target;
2050 /* no do callbacks and do not use session again since
2051 * the callbacks may abort the session */
2052 while (NULL != (pos = hd))
2053 {
2054 GNUNET_CONTAINER_DLL_remove (hd,
2055 tl,
2056 pos);
2057 if (NULL != pos->transmit_cont)
2058 pos->transmit_cont (pos->transmit_cont_cls,
2059 &pid,
2060 GNUNET_SYSERR,
2061 pos->message_size,
2062 0);
2063 GNUNET_free (pos);
2064 }
2065 GNUNET_STATISTICS_update (plugin->env->stats,
2066 gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret,
2067 GNUNET_NO);
2068 GNUNET_STATISTICS_update (plugin->env->stats,
2069 gettext_noop ("# bytes discarded by TCP (timeout)"),
2070 ret,
2071 GNUNET_NO);
2072 if (0 < ret)
2073 notify_session_monitor (session->plugin,
2074 session,
2075 GNUNET_TRANSPORT_SS_UPDATE);
2076 return 0;
2077 }
2078 /* copy all pending messages that would fit */
2079 ret = 0;
2080 cbuf = buf;
2081 hd = NULL;
2082 tl = NULL;
2083 while (NULL != (pos = session->pending_messages_head))
2084 {
2085 if (ret + pos->message_size > size)
2086 break;
2087 GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
2088 session->pending_messages_tail,
2089 pos);
2090 GNUNET_assert (0 < session->msgs_in_queue);
2091 session->msgs_in_queue--;
2092 GNUNET_assert (pos->message_size <= session->bytes_in_queue);
2093 session->bytes_in_queue -= pos->message_size;
2094 GNUNET_assert(size >= pos->message_size);
2095 LOG (GNUNET_ERROR_TYPE_DEBUG,
2096 "Transmitting message of type %u size %u to peer %s at %s\n",
2097 ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type),
2098 pos->message_size,
2099 GNUNET_i2s (&session->target),
2100 tcp_plugin_address_to_string (session->plugin,
2101 session->address->address,
2102 session->address->address_length));
2103 /* FIXME: this GNUNET_memcpy can be up to 7% of our total runtime */
2104 GNUNET_memcpy (cbuf,
2105 pos->msg,
2106 pos->message_size);
2107 cbuf += pos->message_size;
2108 ret += pos->message_size;
2109 size -= pos->message_size;
2110 GNUNET_CONTAINER_DLL_insert_tail (hd,
2111 tl,
2112 pos);
2113 }
2114 notify_session_monitor (session->plugin,
2115 session,
2116 GNUNET_TRANSPORT_SS_UPDATE);
2117 /* schedule 'continuation' before callbacks so that callbacks that
2118 * cancel everything don't cause us to use a session that no longer
2119 * exists... */
2120 process_pending_messages (session);
2121 session->last_activity = GNUNET_TIME_absolute_get ();
2122 pid = session->target;
2123 /* we'll now call callbacks that may cancel the session; hence
2124 * we should not use 'session' after this point */
2125 while (NULL != (pos = hd))
2126 {
2127 GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
2128 if (NULL != pos->transmit_cont)
2129 pos->transmit_cont (pos->transmit_cont_cls,
2130 &pid,
2131 GNUNET_OK,
2132 pos->message_size,
2133 pos->message_size); /* FIXME: include TCP overhead */
2134 GNUNET_free (pos);
2135 }
2136 GNUNET_assert (NULL == hd);
2137 GNUNET_assert (NULL == tl);
2138 GNUNET_STATISTICS_update (plugin->env->stats,
2139 gettext_noop ("# bytes currently in TCP buffers"),
2140 - (int64_t) ret,
2141 GNUNET_NO);
2142 GNUNET_STATISTICS_update (plugin->env->stats,
2143 gettext_noop ("# bytes transmitted via TCP"),
2144 ret,
2145 GNUNET_NO);
2146 return ret;
2147}
2148
2149
2150/**
2151 * If we have pending messages, ask the server to
2152 * transmit them (schedule the respective tasks, etc.)
2153 *
2154 * @param session for which session should we do this
2155 */
2156static void
2157process_pending_messages (struct GNUNET_ATS_Session *session)
2158{
2159 struct PendingMessage *pm;
2160
2161 GNUNET_assert (NULL != session->client);
2162 if (NULL != session->transmit_handle)
2163 return;
2164 if (NULL == (pm = session->pending_messages_head))
2165 return;
2166
2167 session->transmit_handle
2168 = GNUNET_SERVER_notify_transmit_ready (session->client,
2169 pm->message_size,
2170 GNUNET_TIME_absolute_get_remaining (pm->timeout),
2171 &do_transmit,
2172 session);
2173}
2174
2175
2176/**
2177 * Function that can be used by the transport service to transmit
2178 * a message using the plugin. Note that in the case of a
2179 * peer disconnecting, the continuation MUST be called
2180 * prior to the disconnect notification itself. This function
2181 * will be called with this peer's HELLO message to initiate
2182 * a fresh connection to another peer.
2183 *
2184 * @param cls closure
2185 * @param session which session must be used
2186 * @param msgbuf the message to transmit
2187 * @param msgbuf_size number of bytes in @a msgbuf
2188 * @param priority how important is the message (most plugins will
2189 * ignore message priority and just FIFO)
2190 * @param to how long to wait at most for the transmission (does not
2191 * require plugins to discard the message after the timeout,
2192 * just advisory for the desired delay; most plugins will ignore
2193 * this as well)
2194 * @param cont continuation to call once the message has
2195 * been transmitted (or if the transport is ready
2196 * for the next transmission call; or if the
2197 * peer disconnected...); can be NULL
2198 * @param cont_cls closure for @a cont
2199 * @return number of bytes used (on the physical network, with overheads);
2200 * -1 on hard errors (i.e. address invalid); 0 is a legal value
2201 * and does NOT mean that the message was not transmitted (DV)
2202 */
2203static ssize_t
2204tcp_plugin_send (void *cls,
2205 struct GNUNET_ATS_Session *session,
2206 const char *msgbuf,
2207 size_t msgbuf_size,
2208 unsigned int priority,
2209 struct GNUNET_TIME_Relative to,
2210 GNUNET_TRANSPORT_TransmitContinuation cont,
2211 void *cont_cls)
2212{
2213 struct Plugin * plugin = cls;
2214 struct PendingMessage *pm;
2215
2216 /* create new message entry */
2217 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
2218 pm->msg = (const char *) &pm[1];
2219 GNUNET_memcpy (&pm[1], msgbuf, msgbuf_size);
2220 pm->message_size = msgbuf_size;
2221 pm->timeout = GNUNET_TIME_relative_to_absolute (to);
2222 pm->transmit_cont = cont;
2223 pm->transmit_cont_cls = cont_cls;
2224
2225 LOG (GNUNET_ERROR_TYPE_DEBUG,
2226 "Asked to transmit %u bytes to `%s', added message to list.\n",
2227 msgbuf_size,
2228 GNUNET_i2s (&session->target));
2229
2230 if (GNUNET_YES ==
2231 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
2232 &session->target,
2233 session))
2234 {
2235 GNUNET_assert (NULL != session->client);
2236 GNUNET_SERVER_client_set_timeout (session->client,
2237 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2238 GNUNET_STATISTICS_update (plugin->env->stats,
2239 gettext_noop ("# bytes currently in TCP buffers"),
2240 msgbuf_size,
2241 GNUNET_NO);
2242
2243 /* append pm to pending_messages list */
2244 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2245 session->pending_messages_tail,
2246 pm);
2247 notify_session_monitor (session->plugin,
2248 session,
2249 GNUNET_TRANSPORT_SS_UPDATE);
2250 session->msgs_in_queue++;
2251 session->bytes_in_queue += pm->message_size;
2252 process_pending_messages (session);
2253 return msgbuf_size;
2254 }
2255 if (GNUNET_YES ==
2256 GNUNET_CONTAINER_multipeermap_contains_value (plugin->nat_wait_conns,
2257 &session->target,
2258 session))
2259 {
2260 LOG (GNUNET_ERROR_TYPE_DEBUG,
2261 "This NAT WAIT session for peer `%s' is not yet ready!\n",
2262 GNUNET_i2s (&session->target));
2263 GNUNET_STATISTICS_update (plugin->env->stats,
2264 gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size,
2265 GNUNET_NO);
2266 /* append pm to pending_messages list */
2267 GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
2268 session->pending_messages_tail,
2269 pm);
2270 session->msgs_in_queue++;
2271 session->bytes_in_queue += pm->message_size;
2272 notify_session_monitor (session->plugin,
2273 session,
2274 GNUNET_TRANSPORT_SS_HANDSHAKE);
2275 return msgbuf_size;
2276 }
2277 LOG (GNUNET_ERROR_TYPE_ERROR,
2278 "Invalid session %p\n",
2279 session);
2280 if (NULL != cont)
2281 cont (cont_cls,
2282 &session->target,
2283 GNUNET_SYSERR,
2284 pm->message_size,
2285 0);
2286 GNUNET_break (0);
2287 GNUNET_free (pm);
2288 return GNUNET_SYSERR; /* session does not exist here */
2289}
2290
2291
2292/**
2293 * Closure for #session_lookup_it().
2294 */
2295struct GNUNET_ATS_SessionItCtx
2296{
2297 /**
2298 * Address we are looking for.
2299 */
2300 const struct GNUNET_HELLO_Address *address;
2301
2302 /**
2303 * Where to store the session (if we found it).
2304 */
2305 struct GNUNET_ATS_Session *result;
2306
2307};
2308
2309
2310/**
2311 * Look for a session by address.
2312 *
2313 * @param cls the `struct GNUNET_ATS_SessionItCtx`
2314 * @param key unused
2315 * @param value a `struct GNUNET_ATS_Session`
2316 * @return #GNUNET_YES to continue looking, #GNUNET_NO if we found the session
2317 */
2318static int
2319session_lookup_it (void *cls,
2320 const struct GNUNET_PeerIdentity *key,
2321 void *value)
2322{
2323 struct GNUNET_ATS_SessionItCtx *si_ctx = cls;
2324 struct GNUNET_ATS_Session *session = value;
2325
2326 if (0 !=
2327 GNUNET_HELLO_address_cmp (si_ctx->address,
2328 session->address))
2329 return GNUNET_YES;
2330 si_ctx->result = session;
2331 return GNUNET_NO;
2332}
2333
2334
2335/**
2336 * Task cleaning up a NAT connection attempt after timeout
2337 *
2338 * @param cls the `struct GNUNET_ATS_Session`
2339 */
2340static void
2341nat_connect_timeout (void *cls)
2342{
2343 struct GNUNET_ATS_Session *session = cls;
2344
2345 session->nat_connection_timeout = NULL;
2346 LOG (GNUNET_ERROR_TYPE_DEBUG,
2347 "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n",
2348 GNUNET_i2s (&session->target),
2349 tcp_plugin_address_to_string (session->plugin,
2350 session->address->address,
2351 session->address->address_length));
2352 tcp_plugin_disconnect_session (session->plugin,
2353 session);
2354}
2355
2356
2357/**
2358 * Function that will be called whenever the transport service wants to
2359 * notify the plugin that a session is still active and in use and
2360 * therefore the session timeout for this session has to be updated
2361 *
2362 * @param cls closure
2363 * @param peer which peer was the session for
2364 * @param session which session is being updated
2365 */
2366static void
2367tcp_plugin_update_session_timeout (void *cls,
2368 const struct GNUNET_PeerIdentity *peer,
2369 struct GNUNET_ATS_Session *session)
2370{
2371 reschedule_session_timeout (session);
2372}
2373
2374
2375/**
2376 * Task to signal the server that we can continue
2377 * receiving from the TCP client now.
2378 *
2379 * @param cls the `struct GNUNET_ATS_Session *`
2380 */
2381static void
2382delayed_done (void *cls)
2383{
2384 struct GNUNET_ATS_Session *session = cls;
2385
2386 session->receive_delay_task = NULL;
2387 reschedule_session_timeout (session);
2388 GNUNET_SERVER_receive_done (session->client,
2389 GNUNET_OK);
2390}
2391
2392
2393/**
2394 * Function that will be called whenever the transport service wants to
2395 * notify the plugin that the inbound quota changed and that the plugin
2396 * should update it's delay for the next receive value
2397 *
2398 * @param cls closure
2399 * @param peer which peer was the session for
2400 * @param session which session is being updated
2401 * @param delay new delay to use for receiving
2402 */
2403static void
2404tcp_plugin_update_inbound_delay (void *cls,
2405 const struct GNUNET_PeerIdentity *peer,
2406 struct GNUNET_ATS_Session *session,
2407 struct GNUNET_TIME_Relative delay)
2408{
2409 if (NULL == session->receive_delay_task)
2410 return;
2411 LOG (GNUNET_ERROR_TYPE_DEBUG,
2412 "New inbound delay %s\n",
2413 GNUNET_STRINGS_relative_time_to_string (delay,
2414 GNUNET_NO));
2415 session->receive_delay = GNUNET_TIME_relative_to_absolute (delay);
2416 GNUNET_SCHEDULER_cancel (session->receive_delay_task);
2417 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
2418 &delayed_done,
2419 session);
2420}
2421
2422
2423/**
2424 * Create a new session to transmit data to the target
2425 * This session will used to send data to this peer and the plugin will
2426 * notify us by calling the env->session_end function
2427 *
2428 * @param cls closure
2429 * @param address the address to use
2430 * @return the session if the address is valid, NULL otherwise
2431 */
2432static struct GNUNET_ATS_Session *
2433tcp_plugin_get_session (void *cls,
2434 const struct GNUNET_HELLO_Address *address)
2435{
2436 struct Plugin *plugin = cls;
2437 struct GNUNET_ATS_Session *session = NULL;
2438 int af;
2439 const void *sb;
2440 size_t sbs;
2441 struct GNUNET_CONNECTION_Handle *sa;
2442 struct sockaddr_in a4;
2443 struct sockaddr_in6 a6;
2444 const struct IPv4TcpAddress *t4;
2445 const struct IPv6TcpAddress *t6;
2446 unsigned int options;
2447 enum GNUNET_ATS_Network_Type net_type;
2448 unsigned int is_natd = GNUNET_NO;
2449 size_t addrlen;
2450#ifdef TCP_STEALTH
2451 struct GNUNET_NETWORK_Handle *s;
2452#endif
2453
2454 addrlen = address->address_length;
2455 LOG (GNUNET_ERROR_TYPE_DEBUG,
2456 "Trying to get session for `%s' address of peer `%s'\n",
2457 tcp_plugin_address_to_string (plugin,
2458 address->address,
2459 address->address_length),
2460 GNUNET_i2s (&address->peer));
2461
2462 if (GNUNET_HELLO_address_check_option (address,
2463 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2464 {
2465 GNUNET_break (0);
2466 return NULL;
2467 }
2468
2469 /* look for existing session */
2470 if (GNUNET_YES ==
2471 GNUNET_CONTAINER_multipeermap_contains (plugin->sessionmap,
2472 &address->peer))
2473 {
2474 struct GNUNET_ATS_SessionItCtx si_ctx;
2475
2476 si_ctx.address = address;
2477 si_ctx.result = NULL;
2478 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2479 &address->peer,
2480 &session_lookup_it,
2481 &si_ctx);
2482 if (NULL != si_ctx.result)
2483 {
2484 session = si_ctx.result;
2485 LOG (GNUNET_ERROR_TYPE_DEBUG,
2486 "Found existing session for `%s' address `%s'\n",
2487 GNUNET_i2s (&address->peer),
2488 tcp_plugin_address_to_string (plugin,
2489 address->address,
2490 address->address_length));
2491 return session;
2492 }
2493 /* This is a bit of a hack, limiting TCP to never allow more than
2494 one TCP connection to any given peer at the same time.
2495 Without this, peers sometimes disagree about which of the TCP
2496 connections they should use, causing one side to believe that
2497 they transmit successfully, while the other receives nothing. */
2498 return NULL; /* Refuse to have more than one TCP connection per
2499 peer pair at the same time. */
2500 }
2501
2502 if (addrlen == sizeof(struct IPv6TcpAddress))
2503 {
2504 GNUNET_assert (NULL != address->address); /* make static analysis happy */
2505 t6 = address->address;
2506 options = t6->options;
2507 af = AF_INET6;
2508 memset (&a6, 0, sizeof(a6));
2509#if HAVE_SOCKADDR_IN_SIN_LEN
2510 a6.sin6_len = sizeof (a6);
2511#endif
2512 a6.sin6_family = AF_INET6;
2513 a6.sin6_port = t6->t6_port;
2514 if (t6->t6_port == 0)
2515 is_natd = GNUNET_YES;
2516 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2517 sb = &a6;
2518 sbs = sizeof(a6);
2519 }
2520 else if (addrlen == sizeof(struct IPv4TcpAddress))
2521 {
2522 GNUNET_assert(NULL != address->address); /* make static analysis happy */
2523 t4 = address->address;
2524 options = t4->options;
2525 af = AF_INET;
2526 memset (&a4, 0, sizeof(a4));
2527#if HAVE_SOCKADDR_IN_SIN_LEN
2528 a4.sin_len = sizeof (a4);
2529#endif
2530 a4.sin_family = AF_INET;
2531 a4.sin_port = t4->t4_port;
2532 if (t4->t4_port == 0)
2533 is_natd = GNUNET_YES;
2534 a4.sin_addr.s_addr = t4->ipv4_addr;
2535 sb = &a4;
2536 sbs = sizeof(a4);
2537 }
2538 else
2539 {
2540 GNUNET_STATISTICS_update (plugin->env->stats,
2541 gettext_noop ("# requests to create session with invalid address"),
2542 1,
2543 GNUNET_NO);
2544 return NULL;
2545 }
2546
2547 net_type = plugin->env->get_address_type (plugin->env->cls,
2548 sb,
2549 sbs);
2550 GNUNET_break (net_type != GNUNET_ATS_NET_UNSPECIFIED);
2551
2552 if ( (is_natd == GNUNET_YES) &&
2553 (addrlen == sizeof(struct IPv6TcpAddress)) )
2554 {
2555 /* NAT client only works with IPv4 addresses */
2556 return NULL;
2557 }
2558
2559 if (plugin->cur_connections >= plugin->max_connections)
2560 {
2561 /* saturated */
2562 return NULL;
2563 }
2564
2565 if ( (is_natd == GNUNET_YES) &&
2566 (GNUNET_YES ==
2567 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2568 &address->peer)))
2569 {
2570 /* Only do one NAT punch attempt per peer identity */
2571 return NULL;
2572 }
2573
2574 if ( (is_natd == GNUNET_YES) &&
2575 (NULL != plugin->nat) &&
2576 (GNUNET_NO ==
2577 GNUNET_CONTAINER_multipeermap_contains (plugin->nat_wait_conns,
2578 &address->peer)))
2579 {
2580 struct sockaddr_in local_sa;
2581
2582 LOG (GNUNET_ERROR_TYPE_DEBUG,
2583 "Found valid IPv4 NAT address (creating session)!\n");
2584 session = create_session (plugin,
2585 address,
2586 net_type,
2587 NULL,
2588 GNUNET_YES);
2589 session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
2590 &nat_connect_timeout,
2591 session);
2592 GNUNET_assert (GNUNET_OK ==
2593 GNUNET_CONTAINER_multipeermap_put (plugin->nat_wait_conns,
2594 &session->target,
2595 session,
2596 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2597
2598 LOG (GNUNET_ERROR_TYPE_DEBUG,
2599 "Created NAT WAIT connection to `%s' at `%s'\n",
2600 GNUNET_i2s (&session->target),
2601 GNUNET_a2s (sb, sbs));
2602 memset (&local_sa,
2603 0,
2604 sizeof (local_sa));
2605 local_sa.sin_family = AF_INET;
2606 local_sa.sin_port = htons (plugin->open_port);
2607 /* We leave sin_address at 0, let the kernel figure it out,
2608 even if our bind() is more specific. (May want to reconsider
2609 later.) */
2610 if (GNUNET_OK ==
2611 GNUNET_NAT_request_reversal (plugin->nat,
2612 &local_sa,
2613 &a4))
2614 return session;
2615 LOG (GNUNET_ERROR_TYPE_DEBUG,
2616 "Running NAT client for `%s' at `%s' failed\n",
2617 GNUNET_i2s (&session->target),
2618 GNUNET_a2s (sb, sbs));
2619 tcp_plugin_disconnect_session (plugin,
2620 session);
2621 return NULL;
2622 }
2623
2624 /* create new outbound session */
2625 if (0 != (options & TCP_OPTIONS_TCP_STEALTH))
2626 {
2627#ifdef TCP_STEALTH
2628 s = GNUNET_NETWORK_socket_create (af, SOCK_STREAM, 0);
2629 if (NULL == s)
2630 {
2631 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
2632 "socket");
2633 sa = NULL;
2634 }
2635 else
2636 {
2637 if ( (GNUNET_OK !=
2638 GNUNET_NETWORK_socket_setsockopt (s,
2639 IPPROTO_TCP,
2640 TCP_STEALTH,
2641 &session->target,
2642 sizeof (struct GNUNET_PeerIdentity))) ||
2643 (GNUNET_OK !=
2644 GNUNET_NETWORK_socket_setsockopt (s,
2645 IPPROTO_TCP,
2646 TCP_STEALTH_INTEGRITY,
2647 &plugin->my_welcome,
2648 sizeof (struct WelcomeMessage))) )
2649 {
2650 /* TCP STEALTH not supported by kernel */
2651 GNUNET_break (GNUNET_OK ==
2652 GNUNET_NETWORK_socket_close (s));
2653 sa = NULL;
2654 }
2655 else
2656 {
2657 sa = GNUNET_CONNECTION_connect_socket (s, sb, sbs);
2658 }
2659 }
2660#else
2661 sa = NULL;
2662#endif
2663 }
2664 else
2665 {
2666 sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
2667 }
2668 if (NULL == sa)
2669 {
2670 LOG (GNUNET_ERROR_TYPE_DEBUG,
2671 "Failed to create connection to `%s' at `%s'\n",
2672 GNUNET_i2s (&address->peer),
2673 GNUNET_a2s (sb, sbs));
2674 return NULL;
2675 }
2676 LOG (GNUNET_ERROR_TYPE_DEBUG,
2677 "Asked to transmit to `%s', creating fresh session using address `%s'.\n",
2678 GNUNET_i2s (&address->peer),
2679 GNUNET_a2s (sb, sbs));
2680
2681 session = create_session (plugin,
2682 address,
2683 net_type,
2684 GNUNET_SERVER_connect_socket (plugin->server,
2685 sa),
2686 GNUNET_NO);
2687 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
2688 &session->target,
2689 session,
2690 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2691 /* Send TCP Welcome */
2692 process_pending_messages (session);
2693
2694 return session;
2695}
2696
2697
2698/**
2699 * We have been asked to destroy all connections to a particular peer.
2700 * This function is called on each applicable session and must tear it
2701 * down.
2702 *
2703 * @param cls the `struct Plugin *`
2704 * @param key the peer which the session belongs to (unused)
2705 * @param value the `struct GNUNET_ATS_Session`
2706 * @return #GNUNET_YES (continue to iterate)
2707 */
2708static int
2709session_disconnect_it (void *cls,
2710 const struct GNUNET_PeerIdentity *key,
2711 void *value)
2712{
2713 struct Plugin *plugin = cls;
2714 struct GNUNET_ATS_Session *session = value;
2715
2716 GNUNET_STATISTICS_update (session->plugin->env->stats,
2717 gettext_noop ("# transport-service disconnect requests for TCP"),
2718 1,
2719 GNUNET_NO);
2720 tcp_plugin_disconnect_session (plugin,
2721 session);
2722 return GNUNET_YES;
2723}
2724
2725
2726/**
2727 * Function that can be called to force a disconnect from the
2728 * specified neighbour. This should also cancel all previously
2729 * scheduled transmissions. Obviously the transmission may have been
2730 * partially completed already, which is OK. The plugin is supposed
2731 * to close the connection (if applicable) and no longer call the
2732 * transmit continuation(s).
2733 *
2734 * Finally, plugin MUST NOT call the services's receive function to
2735 * notify the service that the connection to the specified target was
2736 * closed after a getting this call.
2737 *
2738 * @param cls closure
2739 * @param target peer for which the last transmission is
2740 * to be cancelled
2741 */
2742static void
2743tcp_plugin_disconnect (void *cls,
2744 const struct GNUNET_PeerIdentity *target)
2745{
2746 struct Plugin *plugin = cls;
2747
2748 LOG (GNUNET_ERROR_TYPE_DEBUG,
2749 "Disconnecting peer `%s'\n",
2750 GNUNET_i2s (target));
2751 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessionmap,
2752 target,
2753 &session_disconnect_it,
2754 plugin);
2755 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->nat_wait_conns,
2756 target,
2757 &session_disconnect_it,
2758 plugin);
2759}
2760
2761
2762/**
2763 * We are processing an address pretty printing request and finished
2764 * the IP resolution (if applicable). Append our port and forward the
2765 * result. If called with @a hostname NULL, we are done and should
2766 * clean up the pretty printer (otherwise, there might be multiple
2767 * hostnames for the IP address and we might receive more).
2768 *
2769 * @param cls the `struct PrettyPrinterContext *`
2770 * @param hostname hostname part of the address
2771 */
2772static void
2773append_port (void *cls,
2774 const char *hostname)
2775{
2776 struct PrettyPrinterContext *ppc = cls;
2777 struct Plugin *plugin = ppc->plugin;
2778 char *ret;
2779
2780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2781 "append_port called with hostname `%s'\n",
2782 hostname);
2783 if (NULL == hostname)
2784 {
2785 /* Final call, done */
2786 ppc->resolver_handle = NULL;
2787 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2788 plugin->ppc_dll_tail,
2789 ppc);
2790 ppc->asc (ppc->asc_cls,
2791 NULL,
2792 GNUNET_OK);
2793 GNUNET_free (ppc);
2794 return;
2795 }
2796 if (GNUNET_YES == ppc->ipv6)
2797 GNUNET_asprintf (&ret,
2798 "%s.%u.[%s]:%d",
2799 PLUGIN_NAME,
2800 ppc->options,
2801 hostname,
2802 ppc->port);
2803 else
2804 GNUNET_asprintf (&ret,
2805 "%s.%u.%s:%d",
2806 PLUGIN_NAME,
2807 ppc->options,
2808 hostname,
2809 ppc->port);
2810 ppc->asc (ppc->asc_cls,
2811 ret,
2812 GNUNET_OK);
2813 GNUNET_free (ret);
2814}
2815
2816
2817/**
2818 * Convert the transports address to a nice, human-readable format.
2819 *
2820 * @param cls closure with the `struct Plugin`
2821 * @param type name of the transport that generated the address
2822 * @param addr one of the addresses of the host, NULL for the last address
2823 * the specific address format depends on the transport
2824 * @param addrlen length of the @a addr
2825 * @param numeric should (IP) addresses be displayed in numeric form?
2826 * @param timeout after how long should we give up?
2827 * @param asc function to call on each string
2828 * @param asc_cls closure for @a asc
2829 */
2830static void
2831tcp_plugin_address_pretty_printer (void *cls,
2832 const char *type,
2833 const void *addr,
2834 size_t addrlen,
2835 int numeric,
2836 struct GNUNET_TIME_Relative timeout,
2837 GNUNET_TRANSPORT_AddressStringCallback asc,
2838 void *asc_cls)
2839{
2840 struct Plugin *plugin = cls;
2841 struct PrettyPrinterContext *ppc;
2842 const void *sb;
2843 size_t sbs;
2844 struct sockaddr_in a4;
2845 struct sockaddr_in6 a6;
2846 const struct IPv4TcpAddress *t4;
2847 const struct IPv6TcpAddress *t6;
2848 uint16_t port;
2849 uint32_t options;
2850
2851 if (sizeof(struct IPv6TcpAddress) == addrlen)
2852 {
2853 t6 = addr;
2854 memset (&a6, 0, sizeof(a6));
2855 a6.sin6_family = AF_INET6;
2856 a6.sin6_port = t6->t6_port;
2857 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
2858 port = ntohs (t6->t6_port);
2859 options = ntohl (t6->options);
2860 sb = &a6;
2861 sbs = sizeof(a6);
2862 }
2863 else if (sizeof(struct IPv4TcpAddress) == addrlen)
2864 {
2865 t4 = addr;
2866 memset (&a4, 0, sizeof(a4));
2867 a4.sin_family = AF_INET;
2868 a4.sin_port = t4->t4_port;
2869 a4.sin_addr.s_addr = t4->ipv4_addr;
2870 port = ntohs (t4->t4_port);
2871 options = ntohl (t4->options);
2872 sb = &a4;
2873 sbs = sizeof(a4);
2874 }
2875 else
2876 {
2877 /* invalid address */
2878 LOG (GNUNET_ERROR_TYPE_WARNING,
2879 _("Unexpected address length: %u bytes\n"),
2880 (unsigned int) addrlen);
2881 asc (asc_cls, NULL, GNUNET_SYSERR);
2882 asc (asc_cls, NULL, GNUNET_OK);
2883 return;
2884 }
2885 ppc = GNUNET_new (struct PrettyPrinterContext);
2886 ppc->plugin = plugin;
2887 if (addrlen == sizeof(struct IPv6TcpAddress))
2888 ppc->ipv6 = GNUNET_YES;
2889 else
2890 ppc->ipv6 = GNUNET_NO;
2891 ppc->asc = asc;
2892 ppc->asc_cls = asc_cls;
2893 ppc->port = port;
2894 ppc->options = options;
2895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2896 "Starting DNS reverse lookup\n");
2897 ppc->resolver_handle = GNUNET_RESOLVER_hostname_get (sb,
2898 sbs,
2899 ! numeric,
2900 timeout,
2901 &append_port,
2902 ppc);
2903 if (NULL == ppc->resolver_handle)
2904 {
2905 GNUNET_break (0);
2906 GNUNET_free (ppc);
2907 return;
2908 }
2909 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
2910 plugin->ppc_dll_tail,
2911 ppc);
2912}
2913
2914
2915/**
2916 * Function that will be called to check if a binary address for this
2917 * plugin is well-formed and corresponds to an address for THIS peer
2918 * (as per our configuration). Naturally, if absolutely necessary,
2919 * plugins can be a bit conservative in their answer, but in general
2920 * plugins should make sure that the address does not redirect
2921 * traffic to a 3rd party that might try to man-in-the-middle our
2922 * traffic.
2923 *
2924 * @param cls closure, our `struct Plugin *`
2925 * @param addr pointer to the address
2926 * @param addrlen length of @a addr
2927 * @return #GNUNET_OK if this is a plausible address for this peer
2928 * and transport, #GNUNET_SYSERR if not
2929 */
2930static int
2931tcp_plugin_check_address (void *cls,
2932 const void *addr,
2933 size_t addrlen)
2934{
2935 struct Plugin *plugin = cls;
2936 const struct IPv4TcpAddress *v4;
2937 const struct IPv6TcpAddress *v6;
2938
2939 if ( (addrlen != sizeof(struct IPv4TcpAddress)) &&
2940 (addrlen != sizeof(struct IPv6TcpAddress)) )
2941 {
2942 GNUNET_break_op (0);
2943 return GNUNET_SYSERR;
2944 }
2945
2946 if (addrlen == sizeof(struct IPv4TcpAddress))
2947 {
2948 struct sockaddr_in s4;
2949
2950 v4 = (const struct IPv4TcpAddress *) addr;
2951 if (0 != memcmp (&v4->options,
2952 &plugin->myoptions,
2953 sizeof(uint32_t)))
2954 {
2955 GNUNET_break (0);
2956 return GNUNET_SYSERR;
2957 }
2958 memset (&s4, 0, sizeof (s4));
2959 s4.sin_family = AF_INET;
2960#if HAVE_SOCKADDR_IN_SIN_LEN
2961 s4.sin_len = sizeof (s4);
2962#endif
2963 s4.sin_port = v4->t4_port;
2964 s4.sin_addr.s_addr = v4->ipv4_addr;
2965
2966 if (GNUNET_OK !=
2967 GNUNET_NAT_test_address (plugin->nat,
2968 &s4,
2969 sizeof (struct sockaddr_in)))
2970 return GNUNET_SYSERR;
2971 }
2972 else
2973 {
2974 struct sockaddr_in6 s6;
2975
2976 v6 = (const struct IPv6TcpAddress *) addr;
2977 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2978 {
2979 GNUNET_break_op (0);
2980 return GNUNET_SYSERR;
2981 }
2982 if (0 != memcmp (&v6->options,
2983 &plugin->myoptions,
2984 sizeof (uint32_t)))
2985 {
2986 GNUNET_break (0);
2987 return GNUNET_SYSERR;
2988 }
2989 memset (&s6, 0, sizeof (s6));
2990 s6.sin6_family = AF_INET6;
2991#if HAVE_SOCKADDR_IN_SIN_LEN
2992 s6.sin6_len = sizeof (s6);
2993#endif
2994 s6.sin6_port = v6->t6_port;
2995 s6.sin6_addr = v6->ipv6_addr;
2996
2997 if (GNUNET_OK !=
2998 GNUNET_NAT_test_address (plugin->nat,
2999 &s6,
3000 sizeof(struct sockaddr_in6)))
3001 return GNUNET_SYSERR;
3002 }
3003 return GNUNET_OK;
3004}
3005
3006
3007/**
3008 * We've received a nat probe from this peer via TCP. Finish
3009 * creating the client session and resume sending of queued
3010 * messages.
3011 *
3012 * @param cls closure
3013 * @param client identification of the client
3014 * @param message the actual message
3015 */
3016static void
3017handle_tcp_nat_probe (void *cls,
3018 struct GNUNET_SERVER_Client *client,
3019 const struct GNUNET_MessageHeader *message)
3020{
3021 struct Plugin *plugin = cls;
3022 struct GNUNET_ATS_Session *session;
3023 const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
3024 size_t alen;
3025 void *vaddr;
3026 struct IPv4TcpAddress *t4;
3027 struct IPv6TcpAddress *t6;
3028 const struct sockaddr_in *s4;
3029 const struct sockaddr_in6 *s6;
3030
3031 LOG (GNUNET_ERROR_TYPE_DEBUG,
3032 "Received NAT probe\n");
3033 /* We have received a TCP NAT probe, meaning we (hopefully) initiated
3034 * a connection to this peer by running gnunet-nat-client. This peer
3035 * received the punch message and now wants us to use the new connection
3036 * as the default for that peer. Do so and then send a WELCOME message
3037 * so we can really be connected!
3038 */
3039 if (ntohs (message->size) != sizeof(struct TCP_NAT_ProbeMessage))
3040 {
3041 GNUNET_break_op(0);
3042 GNUNET_SERVER_receive_done (client,
3043 GNUNET_SYSERR);
3044 return;
3045 }
3046
3047 tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
3048 if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
3049 sizeof(struct GNUNET_PeerIdentity)))
3050 {
3051 /* refuse connections from ourselves */
3052 GNUNET_SERVER_receive_done (client,
3053 GNUNET_SYSERR);
3054 return;
3055 }
3056
3057 session = GNUNET_CONTAINER_multipeermap_get (plugin->nat_wait_conns,
3058 &tcp_nat_probe->clientIdentity);
3059 if (NULL == session)
3060 {
3061 LOG (GNUNET_ERROR_TYPE_DEBUG,
3062 "Did NOT find session for NAT probe!\n");
3063 GNUNET_SERVER_receive_done (client,
3064 GNUNET_OK);
3065 return;
3066 }
3067 LOG (GNUNET_ERROR_TYPE_DEBUG,
3068 "Found session for NAT probe!\n");
3069
3070 if (NULL != session->nat_connection_timeout)
3071 {
3072 GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
3073 session->nat_connection_timeout = NULL;
3074 }
3075
3076 if (GNUNET_OK !=
3077 GNUNET_SERVER_client_get_address (client,
3078 &vaddr,
3079 &alen))
3080 {
3081 GNUNET_break(0);
3082 GNUNET_SERVER_receive_done (client,
3083 GNUNET_SYSERR);
3084 tcp_plugin_disconnect_session (plugin,
3085 session);
3086 return;
3087 }
3088 GNUNET_assert (GNUNET_YES ==
3089 GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
3090 &tcp_nat_probe->clientIdentity,
3091 session));
3092 GNUNET_SERVER_client_set_user_context (client,
3093 session);
3094 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3095 &session->target,
3096 session,
3097 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3098 session->last_activity = GNUNET_TIME_absolute_get ();
3099 LOG (GNUNET_ERROR_TYPE_DEBUG,
3100 "Found address `%s' for incoming connection\n",
3101 GNUNET_a2s (vaddr, alen));
3102 switch (((const struct sockaddr *) vaddr)->sa_family)
3103 {
3104 case AF_INET:
3105 s4 = vaddr;
3106 t4 = GNUNET_new (struct IPv4TcpAddress);
3107 t4->options = htonl (TCP_OPTIONS_NONE);
3108 t4->t4_port = s4->sin_port;
3109 t4->ipv4_addr = s4->sin_addr.s_addr;
3110 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3111 PLUGIN_NAME,
3112 &t4,
3113 sizeof(struct IPv4TcpAddress),
3114 GNUNET_HELLO_ADDRESS_INFO_NONE);
3115 break;
3116 case AF_INET6:
3117 s6 = vaddr;
3118 t6 = GNUNET_new (struct IPv6TcpAddress);
3119 t6->options = htonl (TCP_OPTIONS_NONE);
3120 t6->t6_port = s6->sin6_port;
3121 GNUNET_memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3122 session->address = GNUNET_HELLO_address_allocate (&tcp_nat_probe->clientIdentity,
3123 PLUGIN_NAME,
3124 &t6,
3125 sizeof(struct IPv6TcpAddress),
3126 GNUNET_HELLO_ADDRESS_INFO_NONE);
3127 break;
3128 default:
3129 GNUNET_break_op(0);
3130 LOG(GNUNET_ERROR_TYPE_DEBUG,
3131 "Bad address for incoming connection!\n");
3132 GNUNET_free(vaddr);
3133 GNUNET_SERVER_receive_done (client,
3134 GNUNET_SYSERR);
3135 tcp_plugin_disconnect_session (plugin,
3136 session);
3137 return;
3138 }
3139 GNUNET_free (vaddr);
3140 GNUNET_break (NULL == session->client);
3141 session->client = client;
3142 GNUNET_STATISTICS_update (plugin->env->stats,
3143 gettext_noop ("# TCP sessions active"),
3144 1,
3145 GNUNET_NO);
3146 process_pending_messages (session);
3147 GNUNET_SERVER_receive_done (client,
3148 GNUNET_OK);
3149}
3150
3151
3152/**
3153 * We've received a welcome from this peer via TCP. Possibly create a
3154 * fresh client record and send back our welcome.
3155 *
3156 * @param cls closure
3157 * @param client identification of the client
3158 * @param message the actual message
3159 */
3160static void
3161handle_tcp_welcome (void *cls,
3162 struct GNUNET_SERVER_Client *client,
3163 const struct GNUNET_MessageHeader *message)
3164{
3165 struct Plugin *plugin = cls;
3166 const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
3167 struct GNUNET_HELLO_Address *address;
3168 struct GNUNET_ATS_Session *session;
3169 size_t alen;
3170 void *vaddr;
3171 struct IPv4TcpAddress t4;
3172 struct IPv6TcpAddress t6;
3173 const struct sockaddr_in *s4;
3174 const struct sockaddr_in6 *s6;
3175
3176 if (0 == memcmp (&wm->clientIdentity,
3177 plugin->env->my_identity,
3178 sizeof(struct GNUNET_PeerIdentity)))
3179 {
3180 /* refuse connections from ourselves */
3181 if (GNUNET_OK ==
3182 GNUNET_SERVER_client_get_address (client,
3183 &vaddr,
3184 &alen))
3185 {
3186 LOG (GNUNET_ERROR_TYPE_INFO,
3187 "Received WELCOME message from my own identity `%s' on address `%s'\n",
3188 GNUNET_i2s (&wm->clientIdentity),
3189 GNUNET_a2s (vaddr, alen));
3190 GNUNET_free (vaddr);
3191 }
3192 GNUNET_SERVER_receive_done (client,
3193 GNUNET_SYSERR);
3194 return;
3195 }
3196
3197 if (GNUNET_OK ==
3198 GNUNET_SERVER_client_get_address (client,
3199 &vaddr,
3200 &alen))
3201 {
3202 LOG(GNUNET_ERROR_TYPE_DEBUG,
3203 "Received WELCOME message from `%s' on address `%s'\n",
3204 GNUNET_i2s (&wm->clientIdentity),
3205 GNUNET_a2s (vaddr, alen));
3206 GNUNET_free (vaddr);
3207 }
3208 GNUNET_STATISTICS_update (plugin->env->stats,
3209 gettext_noop ("# TCP WELCOME messages received"),
3210 1,
3211 GNUNET_NO);
3212 session = lookup_session_by_client (plugin,
3213 client);
3214 if (NULL != session)
3215 {
3216 if (GNUNET_OK ==
3217 GNUNET_SERVER_client_get_address (client,
3218 &vaddr,
3219 &alen))
3220 {
3221 LOG (GNUNET_ERROR_TYPE_DEBUG,
3222 "Found existing session %p for peer `%s'\n",
3223 session,
3224 GNUNET_a2s (vaddr, alen));
3225 GNUNET_free (vaddr);
3226 }
3227 }
3228 else
3229 {
3230 if (GNUNET_OK ==
3231 GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
3232 {
3233 if (alen == sizeof(struct sockaddr_in))
3234 {
3235 s4 = vaddr;
3236 memset (&t4, '\0', sizeof (t4));
3237 t4.options = htonl (TCP_OPTIONS_NONE);
3238 t4.t4_port = s4->sin_port;
3239 t4.ipv4_addr = s4->sin_addr.s_addr;
3240 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3241 PLUGIN_NAME,
3242 &t4,
3243 sizeof(t4),
3244 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3245 }
3246 else if (alen == sizeof(struct sockaddr_in6))
3247 {
3248 s6 = vaddr;
3249 memset (&t6, '\0', sizeof (t6));
3250 t6.options = htonl (TCP_OPTIONS_NONE);
3251 t6.t6_port = s6->sin6_port;
3252 GNUNET_memcpy (&t6.ipv6_addr, &s6->sin6_addr, sizeof(struct in6_addr));
3253 address = GNUNET_HELLO_address_allocate (&wm->clientIdentity,
3254 PLUGIN_NAME,
3255 &t6,
3256 sizeof (t6),
3257 GNUNET_HELLO_ADDRESS_INFO_INBOUND);
3258 }
3259 else
3260 {
3261 GNUNET_break (0);
3262 GNUNET_free_non_null (vaddr);
3263 GNUNET_SERVER_receive_done (client,
3264 GNUNET_SYSERR);
3265 return;
3266 }
3267 session = create_session (plugin,
3268 address,
3269 plugin->env->get_address_type (plugin->env->cls,
3270 vaddr,
3271 alen),
3272 client,
3273 GNUNET_NO);
3274 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != session->scope);
3275 GNUNET_HELLO_address_free (address);
3276 LOG (GNUNET_ERROR_TYPE_DEBUG,
3277 "Creating new%s session %p for peer `%s' client %p\n",
3278 GNUNET_HELLO_address_check_option (session->address,
3279 GNUNET_HELLO_ADDRESS_INFO_INBOUND)
3280 ? " inbound" : "",
3281 session,
3282 tcp_plugin_address_to_string (plugin,
3283 session->address->address,
3284 session->address->address_length),
3285 client);
3286 GNUNET_free (vaddr);
3287 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessionmap,
3288 &session->target,
3289 session,
3290 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3291 /* Notify transport and ATS about new session */
3292 plugin->env->session_start (plugin->env->cls,
3293 session->address,
3294 session,
3295 session->scope);
3296 }
3297 else
3298 {
3299 LOG(GNUNET_ERROR_TYPE_DEBUG,
3300 "Did not obtain TCP socket address for incoming connection\n");
3301 GNUNET_break(0);
3302 GNUNET_SERVER_receive_done (client,
3303 GNUNET_SYSERR);
3304 return;
3305 }
3306 }
3307
3308 if (GNUNET_YES != session->expecting_welcome)
3309 {
3310 GNUNET_break_op (0);
3311 GNUNET_SERVER_receive_done (client,
3312 GNUNET_SYSERR);
3313 return;
3314 }
3315 session->last_activity = GNUNET_TIME_absolute_get ();
3316 session->expecting_welcome = GNUNET_NO;
3317
3318 process_pending_messages (session);
3319 GNUNET_SERVER_client_set_timeout (client,
3320 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3321 GNUNET_SERVER_receive_done (client,
3322 GNUNET_OK);
3323}
3324
3325
3326/**
3327 * We've received data for this peer via TCP. Unbox,
3328 * compute latency and forward.
3329 *
3330 * @param cls closure
3331 * @param client identification of the client
3332 * @param message the actual message
3333 */
3334static void
3335handle_tcp_data (void *cls,
3336 struct GNUNET_SERVER_Client *client,
3337 const struct GNUNET_MessageHeader *message)
3338{
3339 struct Plugin *plugin = cls;
3340 struct GNUNET_ATS_Session *session;
3341 struct GNUNET_TIME_Relative delay;
3342 uint16_t type;
3343
3344 type = ntohs (message->type);
3345 if ( (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
3346 (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type) )
3347 {
3348 /* We don't want to propagate WELCOME and NAT Probe messages up! */
3349 GNUNET_SERVER_receive_done (client,
3350 GNUNET_OK);
3351 return;
3352 }
3353 session = lookup_session_by_client (plugin, client);
3354 if (NULL == session)
3355 {
3356 /* No inbound session found */
3357 void *vaddr = NULL;
3358 size_t alen;
3359
3360 GNUNET_assert (GNUNET_OK ==
3361 GNUNET_SERVER_client_get_address (client,
3362 &vaddr,
3363 &alen));
3364 LOG (GNUNET_ERROR_TYPE_ERROR,
3365 "Received unexpected %u bytes of type %u from `%s'\n",
3366 (unsigned int) ntohs (message->size),
3367 (unsigned int) ntohs (message->type),
3368 GNUNET_a2s (vaddr,
3369 alen));
3370 GNUNET_break_op(0);
3371 GNUNET_SERVER_receive_done (client,
3372 GNUNET_SYSERR);
3373 GNUNET_free_non_null (vaddr);
3374 return;
3375 }
3376 if (GNUNET_YES == session->expecting_welcome)
3377 {
3378 /* Session is expecting WELCOME message */
3379 void *vaddr = NULL;
3380 size_t alen;
3381
3382 GNUNET_SERVER_client_get_address (client,
3383 &vaddr,
3384 &alen);
3385 LOG (GNUNET_ERROR_TYPE_ERROR,
3386 "Received unexpected %u bytes of type %u from `%s'\n",
3387 (unsigned int) ntohs (message->size),
3388 (unsigned int) ntohs (message->type),
3389 GNUNET_a2s (vaddr, alen));
3390 GNUNET_break_op(0);
3391 GNUNET_SERVER_receive_done (client,
3392 GNUNET_SYSERR);
3393 GNUNET_free_non_null (vaddr);
3394 return;
3395 }
3396
3397 session->last_activity = GNUNET_TIME_absolute_get ();
3398 {
3399 void *vaddr = NULL;
3400 size_t alen;
3401
3402 GNUNET_SERVER_client_get_address (client,
3403 &vaddr,
3404 &alen);
3405 LOG (GNUNET_ERROR_TYPE_DEBUG,
3406 "Passing %u bytes of type %u from `%s' at %s to transport service.\n",
3407 (unsigned int) ntohs (message->size),
3408 (unsigned int) ntohs (message->type),
3409 GNUNET_i2s (&session->target),
3410 GNUNET_a2s (vaddr, alen));
3411 GNUNET_free_non_null (vaddr);
3412 }
3413
3414 GNUNET_STATISTICS_update (plugin->env->stats,
3415 gettext_noop ("# bytes received via TCP"),
3416 ntohs (message->size),
3417 GNUNET_NO);
3418
3419 GNUNET_assert (GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessionmap,
3420 &session->target,
3421 session));
3422 delay = plugin->env->receive (plugin->env->cls,
3423 session->address,
3424 session,
3425 message);
3426 reschedule_session_timeout (session);
3427 if (0 == delay.rel_value_us)
3428 {
3429 GNUNET_SERVER_receive_done (client,
3430 GNUNET_OK);
3431 }
3432 else
3433 {
3434 LOG (GNUNET_ERROR_TYPE_DEBUG,
3435 "Throttling receiving from `%s' for %s\n",
3436 GNUNET_i2s (&session->target),
3437 GNUNET_STRINGS_relative_time_to_string (delay,
3438 GNUNET_YES));
3439 GNUNET_SERVER_disable_receive_done_warning (client);
3440 GNUNET_assert (NULL == session->receive_delay_task);
3441 session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
3442 &delayed_done,
3443 session);
3444 }
3445}
3446
3447
3448/**
3449 * Function called whenever a peer is connected on the "SERVER" level.
3450 * Increments number of active connections and suspends server if we
3451 * have reached the limit.
3452 *
3453 * @param cls closure
3454 * @param client identification of the client
3455 */
3456static void
3457connect_notify (void *cls,
3458 struct GNUNET_SERVER_Client *client)
3459{
3460 struct Plugin *plugin = cls;
3461
3462 if (NULL == client)
3463 return;
3464 plugin->cur_connections++;
3465 GNUNET_STATISTICS_set (plugin->env->stats,
3466 gettext_noop ("# TCP server connections active"),
3467 plugin->cur_connections,
3468 GNUNET_NO);
3469 GNUNET_STATISTICS_update (plugin->env->stats,
3470 gettext_noop ("# TCP server connect events"),
3471 1,
3472 GNUNET_NO);
3473 if (plugin->cur_connections != plugin->max_connections)
3474 return;
3475 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3476 _("TCP connection limit reached, suspending server\n"));
3477 GNUNET_STATISTICS_update (plugin->env->stats,
3478 gettext_noop ("# TCP service suspended"),
3479 1,
3480 GNUNET_NO);
3481 GNUNET_SERVER_suspend (plugin->server); /* Maximum number of connections rechead */
3482}
3483
3484
3485/**
3486 * Function called whenever a peer is disconnected on the "SERVER"
3487 * level. Cleans up the connection, decrements number of active
3488 * connections and if applicable resumes listening.
3489 *
3490 * @param cls closure
3491 * @param client identification of the client
3492 */
3493static void
3494disconnect_notify (void *cls,
3495 struct GNUNET_SERVER_Client *client)
3496{
3497 struct Plugin *plugin = cls;
3498 struct GNUNET_ATS_Session *session;
3499
3500 if (NULL == client)
3501 return;
3502 GNUNET_assert (plugin->cur_connections >= 1);
3503 plugin->cur_connections--;
3504 session = lookup_session_by_client (plugin,
3505 client);
3506 if (NULL == session)
3507 return; /* unknown, nothing to do */
3508 LOG (GNUNET_ERROR_TYPE_DEBUG,
3509 "Destroying session of `%s' with %s due to network-level disconnect.\n",
3510 GNUNET_i2s (&session->target),
3511 tcp_plugin_address_to_string (session->plugin,
3512 session->address->address,
3513 session->address->address_length));
3514
3515 if (plugin->cur_connections == plugin->max_connections)
3516 {
3517 GNUNET_STATISTICS_update (session->plugin->env->stats,
3518 gettext_noop ("# TCP service resumed"),
3519 1,
3520 GNUNET_NO);
3521 GNUNET_SERVER_resume (plugin->server); /* Resume server */
3522 }
3523 GNUNET_STATISTICS_set (plugin->env->stats,
3524 gettext_noop ("# TCP server connections active"),
3525 plugin->cur_connections,
3526 GNUNET_NO);
3527 GNUNET_STATISTICS_update (session->plugin->env->stats,
3528 gettext_noop ("# network-level TCP disconnect events"),
3529 1,
3530 GNUNET_NO);
3531 tcp_plugin_disconnect_session (plugin,
3532 session);
3533}
3534
3535
3536/**
3537 * We can now send a probe message, copy into buffer to really send.
3538 *
3539 * @param cls closure, a `struct TCPProbeContext`
3540 * @param size max size to copy
3541 * @param buf buffer to copy message to
3542 * @return number of bytes copied into @a buf
3543 */
3544static size_t
3545notify_send_probe (void *cls,
3546 size_t size,
3547 void *buf)
3548{
3549 struct TCPProbeContext *tcp_probe_ctx = cls;
3550 struct Plugin *plugin = tcp_probe_ctx->plugin;
3551 size_t ret;
3552
3553 tcp_probe_ctx->transmit_handle = NULL;
3554 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
3555 plugin->probe_tail,
3556 tcp_probe_ctx);
3557 if (NULL == buf)
3558 {
3559 GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock);
3560 GNUNET_free(tcp_probe_ctx);
3561 return 0;
3562 }
3563 GNUNET_assert(size >= sizeof(tcp_probe_ctx->message));
3564 GNUNET_memcpy (buf,
3565 &tcp_probe_ctx->message,
3566 sizeof(tcp_probe_ctx->message));
3567 GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
3568 tcp_probe_ctx->sock);
3569 ret = sizeof(tcp_probe_ctx->message);
3570 GNUNET_free (tcp_probe_ctx);
3571 return ret;
3572}
3573
3574
3575/**
3576 * Function called by the NAT subsystem suggesting another peer wants
3577 * to connect to us via connection reversal. Try to connect back to the
3578 * given IP.
3579 *
3580 * @param cls closure
3581 * @param addr address to try
3582 * @param addrlen number of bytes in @a addr
3583 */
3584static void
3585try_connection_reversal (void *cls,
3586 const struct sockaddr *addr,
3587 socklen_t addrlen)
3588{
3589 struct Plugin *plugin = cls;
3590 struct GNUNET_CONNECTION_Handle *sock;
3591 struct TCPProbeContext *tcp_probe_ctx;
3592
3593 /**
3594 * We have received an ICMP response, ostensibly from a peer
3595 * that wants to connect to us! Send a message to establish a connection.
3596 */
3597 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
3598 addr,
3599 addrlen);
3600 if (NULL == sock)
3601 {
3602 /* failed for some odd reason (out of sockets?); ignore attempt */
3603 return;
3604 }
3605
3606 tcp_probe_ctx = GNUNET_new (struct TCPProbeContext);
3607 tcp_probe_ctx->message.header.size
3608 = htons (sizeof (struct TCP_NAT_ProbeMessage));
3609 tcp_probe_ctx->message.header.type
3610 = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3611 tcp_probe_ctx->message.clientIdentity
3612 = *plugin->env->my_identity;
3613 tcp_probe_ctx->plugin = plugin;
3614 tcp_probe_ctx->sock = sock;
3615 GNUNET_CONTAINER_DLL_insert (plugin->probe_head,
3616 plugin->probe_tail,
3617 tcp_probe_ctx);
3618 tcp_probe_ctx->transmit_handle
3619 = GNUNET_CONNECTION_notify_transmit_ready (sock,
3620 ntohs (tcp_probe_ctx->message.header.size),
3621 GNUNET_TIME_UNIT_FOREVER_REL,
3622 &notify_send_probe,
3623 tcp_probe_ctx);
3624}
3625
3626
3627/**
3628 * Function obtain the network type for a session
3629 *
3630 * @param cls closure (`struct Plugin *`)
3631 * @param session the session
3632 * @return the network type in HBO or #GNUNET_SYSERR
3633 */
3634static enum GNUNET_ATS_Network_Type
3635tcp_plugin_get_network (void *cls,
3636 struct GNUNET_ATS_Session *session)
3637{
3638 return session->scope;
3639}
3640
3641
3642/**
3643 * Function obtain the network type for an address.
3644 *
3645 * @param cls closure (`struct Plugin *`)
3646 * @param address the address
3647 * @return the network type
3648 */
3649static enum GNUNET_ATS_Network_Type
3650tcp_plugin_get_network_for_address (void *cls,
3651 const struct GNUNET_HELLO_Address *address)
3652{
3653 struct Plugin *plugin = cls;
3654 size_t addrlen;
3655 struct sockaddr_in a4;
3656 struct sockaddr_in6 a6;
3657 const struct IPv4TcpAddress *t4;
3658 const struct IPv6TcpAddress *t6;
3659 const void *sb;
3660 size_t sbs;
3661
3662 addrlen = address->address_length;
3663 if (addrlen == sizeof(struct IPv6TcpAddress))
3664 {
3665 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3666 t6 = address->address;
3667 memset (&a6, 0, sizeof(a6));
3668#if HAVE_SOCKADDR_IN_SIN_LEN
3669 a6.sin6_len = sizeof (a6);
3670#endif
3671 a6.sin6_family = AF_INET6;
3672 a6.sin6_port = t6->t6_port;
3673 GNUNET_memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof(struct in6_addr));
3674 sb = &a6;
3675 sbs = sizeof(a6);
3676 }
3677 else if (addrlen == sizeof(struct IPv4TcpAddress))
3678 {
3679 GNUNET_assert (NULL != address->address); /* make static analysis happy */
3680 t4 = address->address;
3681 memset (&a4, 0, sizeof(a4));
3682#if HAVE_SOCKADDR_IN_SIN_LEN
3683 a4.sin_len = sizeof (a4);
3684#endif
3685 a4.sin_family = AF_INET;
3686 a4.sin_port = t4->t4_port;
3687 a4.sin_addr.s_addr = t4->ipv4_addr;
3688 sb = &a4;
3689 sbs = sizeof(a4);
3690 }
3691 else
3692 {
3693 GNUNET_break (0);
3694 return GNUNET_ATS_NET_UNSPECIFIED;
3695 }
3696 return plugin->env->get_address_type (plugin->env->cls,
3697 sb,
3698 sbs);
3699}
3700
3701
3702/**
3703 * Return information about the given session to the
3704 * monitor callback.
3705 *
3706 * @param cls the `struct Plugin` with the monitor callback (`sic`)
3707 * @param peer peer we send information about
3708 * @param value our `struct GNUNET_ATS_Session` to send information about
3709 * @return #GNUNET_OK (continue to iterate)
3710 */
3711static int
3712send_session_info_iter (void *cls,
3713 const struct GNUNET_PeerIdentity *peer,
3714 void *value)
3715{
3716 struct Plugin *plugin = cls;
3717 struct GNUNET_ATS_Session *session = value;
3718
3719 notify_session_monitor (plugin,
3720 session,
3721 GNUNET_TRANSPORT_SS_INIT);
3722 /* FIXME: cannot tell if this is up or not from current
3723 session state... */
3724 notify_session_monitor (plugin,
3725 session,
3726 GNUNET_TRANSPORT_SS_UP);
3727 return GNUNET_OK;
3728}
3729
3730
3731/**
3732 * Begin monitoring sessions of a plugin. There can only
3733 * be one active monitor per plugin (i.e. if there are
3734 * multiple monitors, the transport service needs to
3735 * multiplex the generated events over all of them).
3736 *
3737 * @param cls closure of the plugin
3738 * @param sic callback to invoke, NULL to disable monitor;
3739 * plugin will being by iterating over all active
3740 * sessions immediately and then enter monitor mode
3741 * @param sic_cls closure for @a sic
3742 */
3743static void
3744tcp_plugin_setup_monitor (void *cls,
3745 GNUNET_TRANSPORT_SessionInfoCallback sic,
3746 void *sic_cls)
3747{
3748 struct Plugin *plugin = cls;
3749
3750 plugin->sic = sic;
3751 plugin->sic_cls = sic_cls;
3752 if (NULL != sic)
3753 {
3754 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
3755 &send_session_info_iter,
3756 plugin);
3757 /* signal end of first iteration */
3758 sic (sic_cls, NULL, NULL);
3759 }
3760}
3761
3762
3763/**
3764 * Entry point for the plugin.
3765 *
3766 * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
3767 * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
3768 */
3769void *
3770libgnunet_plugin_transport_xt_init (void *cls)
3771{
3772 static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
3773 { &handle_tcp_welcome, NULL,
3774 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
3775 sizeof(struct WelcomeMessage) },
3776 { &handle_tcp_nat_probe, NULL,
3777 GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
3778 sizeof(struct TCP_NAT_ProbeMessage) },
3779 { &handle_tcp_data, NULL,
3780 GNUNET_MESSAGE_TYPE_ALL, 0 },
3781 { NULL, NULL, 0, 0 }
3782 };
3783 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3784 struct GNUNET_TRANSPORT_PluginFunctions *api;
3785 struct Plugin *plugin;
3786 struct LEGACY_SERVICE_Context *service;
3787 unsigned long long aport;
3788 unsigned long long bport;
3789 unsigned long long max_connections;
3790 unsigned int i;
3791 struct GNUNET_TIME_Relative idle_timeout;
3792#ifdef TCP_STEALTH
3793 struct GNUNET_NETWORK_Handle *const*lsocks;
3794#endif
3795 int ret;
3796 int ret_s;
3797 struct sockaddr **addrs;
3798 socklen_t *addrlens;
3799
3800 if (NULL == env->receive)
3801 {
3802 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3803 initialze the plugin or the API */
3804 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3805 api->cls = NULL;
3806 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3807 api->address_to_string = &tcp_plugin_address_to_string;
3808 api->string_to_address = &tcp_plugin_string_to_address;
3809 return api;
3810 }
3811
3812 GNUNET_assert (NULL != env->cfg);
3813 if (GNUNET_OK !=
3814 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3815 "transport-xt",
3816 "MAX_CONNECTIONS",
3817 &max_connections))
3818 max_connections = 128;
3819
3820 aport = 0;
3821 if ((GNUNET_OK !=
3822 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3823 "transport-xt",
3824 "PORT", &bport)) ||
3825 (bport > 65535) ||
3826 ((GNUNET_OK ==
3827 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3828 "transport-xt",
3829 "ADVERTISED-PORT", &aport)) &&
3830 (aport > 65535) ))
3831 {
3832 LOG(GNUNET_ERROR_TYPE_ERROR,
3833 _("Require valid port number for service `%s' in configuration!\n"),
3834 "transport-xt");
3835 return NULL ;
3836 }
3837 if (0 == aport)
3838 aport = bport;
3839 if (0 == bport)
3840 aport = 0;
3841 if (0 != bport)
3842 {
3843 service = LEGACY_SERVICE_start ("transport-xt",
3844 env->cfg,
3845 LEGACY_SERVICE_OPTION_NONE);
3846 if (NULL == service)
3847 {
3848 LOG (GNUNET_ERROR_TYPE_WARNING,
3849 _("Failed to start service.\n"));
3850 return NULL;
3851 }
3852 }
3853 else
3854 service = NULL;
3855
3856 api = NULL;
3857 plugin = GNUNET_new (struct Plugin);
3858 plugin->sessionmap = GNUNET_CONTAINER_multipeermap_create (max_connections,
3859 GNUNET_YES);
3860 plugin->max_connections = max_connections;
3861 plugin->open_port = bport;
3862 plugin->adv_port = aport;
3863 plugin->env = env;
3864 plugin->my_welcome.header.size = htons (sizeof(struct WelcomeMessage));
3865 plugin->my_welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
3866 plugin->my_welcome.clientIdentity = *plugin->env->my_identity;
3867
3868 if ( (NULL != service) &&
3869 (GNUNET_YES ==
3870 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3871 "transport-xt",
3872 "TCP_STEALTH")) )
3873 {
3874#ifdef TCP_STEALTH
3875 plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
3876 lsocks = LEGACY_SERVICE_get_listen_sockets (service);
3877 if (NULL != lsocks)
3878 {
3879 uint32_t len = sizeof (struct WelcomeMessage);
3880
3881 for (i=0;NULL!=lsocks[i];i++)
3882 {
3883 if ( (GNUNET_OK !=
3884 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3885 IPPROTO_TCP,
3886 TCP_STEALTH,
3887 env->my_identity,
3888 sizeof (struct GNUNET_PeerIdentity))) ||
3889 (GNUNET_OK !=
3890 GNUNET_NETWORK_socket_setsockopt (lsocks[i],
3891 IPPROTO_TCP,
3892 TCP_STEALTH_INTEGRITY_LEN,
3893 &len,
3894 sizeof (len))) )
3895 {
3896 /* TCP STEALTH not supported by kernel */
3897 GNUNET_assert (0 == i);
3898 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3899 _("TCP_STEALTH not supported on this platform.\n"));
3900 goto die;
3901 }
3902 }
3903 }
3904#else
3905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3906 _("TCP_STEALTH not supported on this platform.\n"));
3907 goto die;
3908#endif
3909 }
3910
3911 if ( (NULL != service) &&
3912 (GNUNET_SYSERR !=
3913 (ret_s =
3914 get_server_addresses ("transport-xt",
3915 env->cfg,
3916 &addrs,
3917 &addrlens))))
3918 {
3919 for (ret = ret_s-1; ret >= 0; ret--)
3920 LOG (GNUNET_ERROR_TYPE_INFO,
3921 "Binding to address `%s'\n",
3922 GNUNET_a2s (addrs[ret], addrlens[ret]));
3923 plugin->nat
3924 = GNUNET_NAT_register (env->cfg,
3925 "transport-xt",
3926 IPPROTO_TCP,
3927 (unsigned int) ret_s,
3928 (const struct sockaddr **) addrs,
3929 addrlens,
3930 &tcp_nat_port_map_callback,
3931 &try_connection_reversal,
3932 plugin);
3933 for (ret = ret_s -1; ret >= 0; ret--)
3934 GNUNET_free (addrs[ret]);
3935 GNUNET_free_non_null (addrs);
3936 GNUNET_free_non_null (addrlens);
3937 }
3938 else
3939 {
3940 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
3941 "transport-xt",
3942 IPPROTO_TCP,
3943 0,
3944 NULL,
3945 NULL,
3946 NULL,
3947 &try_connection_reversal,
3948 plugin);
3949 }
3950 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
3951 api->cls = plugin;
3952 api->send = &tcp_plugin_send;
3953 api->get_session = &tcp_plugin_get_session;
3954 api->disconnect_session = &tcp_plugin_disconnect_session;
3955 api->query_keepalive_factor = &tcp_plugin_query_keepalive_factor;
3956 api->disconnect_peer = &tcp_plugin_disconnect;
3957 api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
3958 api->check_address = &tcp_plugin_check_address;
3959 api->address_to_string = &tcp_plugin_address_to_string;
3960 api->string_to_address = &tcp_plugin_string_to_address;
3961 api->get_network = &tcp_plugin_get_network;
3962 api->get_network_for_address = &tcp_plugin_get_network_for_address;
3963 api->update_session_timeout = &tcp_plugin_update_session_timeout;
3964 api->update_inbound_delay = &tcp_plugin_update_inbound_delay;
3965 api->setup_monitor = &tcp_plugin_setup_monitor;
3966 plugin->service = service;
3967 if (NULL != service)
3968 {
3969 plugin->server = LEGACY_SERVICE_get_server (service);
3970 }
3971 else
3972 {
3973 if (GNUNET_OK !=
3974 GNUNET_CONFIGURATION_get_value_time (env->cfg,
3975 "transport-xt",
3976 "TIMEOUT",
3977 &idle_timeout))
3978 {
3979 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3980 "transport-xt",
3981 "TIMEOUT");
3982 goto die;
3983 }
3984 plugin->server
3985 = GNUNET_SERVER_create_with_sockets (NULL,
3986 plugin,
3987 NULL,
3988 idle_timeout,
3989 GNUNET_YES);
3990 }
3991 plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
3992 GNUNET_memcpy (plugin->handlers,
3993 my_handlers,
3994 sizeof(my_handlers));
3995 for (i = 0;i < sizeof(my_handlers) / sizeof(struct GNUNET_SERVER_MessageHandler);i++)
3996 plugin->handlers[i].callback_cls = plugin;
3997
3998 GNUNET_SERVER_add_handlers (plugin->server,
3999 plugin->handlers);
4000 GNUNET_SERVER_connect_notify (plugin->server,
4001 &connect_notify,
4002 plugin);
4003 GNUNET_SERVER_disconnect_notify (plugin->server,
4004 &disconnect_notify,
4005 plugin);
4006 plugin->nat_wait_conns = GNUNET_CONTAINER_multipeermap_create (16,
4007 GNUNET_YES);
4008 if (0 != bport)
4009 LOG (GNUNET_ERROR_TYPE_INFO,
4010 _("XT transport listening on port %llu\n"),
4011 bport);
4012 else
4013 LOG (GNUNET_ERROR_TYPE_INFO,
4014 _("XT transport not listening on any port (client only)\n"));
4015 if ( (aport != bport) &&
4016 (0 != bport) )
4017 LOG (GNUNET_ERROR_TYPE_INFO,
4018 _("XT transport advertises itself as being on port %llu\n"),
4019 aport);
4020 /* Initially set connections to 0 */
4021 GNUNET_STATISTICS_set (plugin->env->stats,
4022 gettext_noop ("# XT sessions active"),
4023 0,
4024 GNUNET_NO);
4025 return api;
4026
4027 die:
4028 if (NULL != plugin->nat)
4029 GNUNET_NAT_unregister (plugin->nat);
4030 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4031 if (NULL != service)
4032 LEGACY_SERVICE_stop (service);
4033 GNUNET_free (plugin);
4034 GNUNET_free_non_null (api);
4035 return NULL;
4036}
4037
4038
4039/**
4040 * Exit point from the plugin.
4041 *
4042 * @param cls the `struct GNUNET_TRANSPORT_PluginFunctions`
4043 * @return NULL
4044 */
4045void *
4046libgnunet_plugin_transport_xt_done (void *cls)
4047{
4048 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
4049 struct Plugin *plugin = api->cls;
4050 struct TCPProbeContext *tcp_probe;
4051 struct PrettyPrinterContext *cur;
4052 struct PrettyPrinterContext *next;
4053
4054 if (NULL == plugin)
4055 {
4056 GNUNET_free(api);
4057 return NULL ;
4058 }
4059 LOG (GNUNET_ERROR_TYPE_DEBUG,
4060 "Shutting down XT plugin\n");
4061
4062 /* Removing leftover sessions */
4063 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessionmap,
4064 &session_disconnect_it,
4065 plugin);
4066 /* Removing leftover NAT sessions */
4067 GNUNET_CONTAINER_multipeermap_iterate (plugin->nat_wait_conns,
4068 &session_disconnect_it,
4069 plugin);
4070
4071 for (cur = plugin->ppc_dll_head; NULL != cur; cur = next)
4072 {
4073 next = cur->next;
4074 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
4075 plugin->ppc_dll_tail,
4076 cur);
4077 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
4078 cur->asc (cur->asc_cls,
4079 NULL,
4080 GNUNET_OK);
4081 GNUNET_free (cur);
4082 }
4083
4084 if (NULL != plugin->service)
4085 LEGACY_SERVICE_stop (plugin->service);
4086 else
4087 GNUNET_SERVER_destroy (plugin->server);
4088 GNUNET_free (plugin->handlers);
4089 if (NULL != plugin->nat)
4090 GNUNET_NAT_unregister (plugin->nat);
4091 while (NULL != (tcp_probe = plugin->probe_head))
4092 {
4093 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
4094 plugin->probe_tail,
4095 tcp_probe);
4096 GNUNET_CONNECTION_destroy (tcp_probe->sock);
4097 GNUNET_free (tcp_probe);
4098 }
4099 GNUNET_CONTAINER_multipeermap_destroy (plugin->nat_wait_conns);
4100 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
4101 GNUNET_break (0 == plugin->cur_connections);
4102 GNUNET_free (plugin);
4103 GNUNET_free (api);
4104 return NULL;
4105}
4106
4107/* end of plugin_transport_xt.c */
diff --git a/src/transport/plugin_transport_xu.c b/src/transport/plugin_transport_xu.c
new file mode 100644
index 000000000..ea0d3f065
--- /dev/null
+++ b/src/transport/plugin_transport_xu.c
@@ -0,0 +1,2492 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @file transport/plugin_transport_xu.c
23 * @brief Implementation of the XU transport protocol
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Matthias Wachs
27 */
28#include "platform.h"
29#include "plugin_transport_xu.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_fragmentation_lib.h"
33#include "gnunet_nat_service.h"
34#include "gnunet_protocols.h"
35#include "gnunet_resolver_service.h"
36#include "gnunet_signatures.h"
37#include "gnunet_constants.h"
38#include "gnunet_statistics_service.h"
39#include "gnunet_transport_service.h"
40#include "gnunet_transport_plugin.h"
41#include "transport.h"
42
43#define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__)
44
45/**
46 * After how much inactivity should a XU session time out?
47 */
48#define XU_SESSION_TIME_OUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
49
50
51/**
52 * XU Message-Packet header (after defragmentation).
53 */
54struct XUMessage
55{
56 /**
57 * Message header.
58 */
59 struct GNUNET_MessageHeader header;
60
61 /**
62 * Always zero for now.
63 */
64 uint32_t reserved;
65
66 /**
67 * What is the identity of the sender
68 */
69 struct GNUNET_PeerIdentity sender;
70
71};
72
73
74/**
75 * Closure for #append_port().
76 */
77struct PrettyPrinterContext
78{
79 /**
80 * DLL
81 */
82 struct PrettyPrinterContext *next;
83
84 /**
85 * DLL
86 */
87 struct PrettyPrinterContext *prev;
88
89 /**
90 * Our plugin.
91 */
92 struct Plugin *plugin;
93
94 /**
95 * Resolver handle
96 */
97 struct GNUNET_RESOLVER_RequestHandle *resolver_handle;
98
99 /**
100 * Function to call with the result.
101 */
102 GNUNET_TRANSPORT_AddressStringCallback asc;
103
104 /**
105 * Clsoure for @e asc.
106 */
107 void *asc_cls;
108
109 /**
110 * Timeout task
111 */
112 struct GNUNET_SCHEDULER_Task *timeout_task;
113
114 /**
115 * Is this an IPv6 address?
116 */
117 int ipv6;
118
119 /**
120 * Options
121 */
122 uint32_t options;
123
124 /**
125 * Port to add after the IP address.
126 */
127 uint16_t port;
128
129};
130
131
132/**
133 * Session with another peer.
134 */
135struct GNUNET_ATS_Session
136{
137 /**
138 * Which peer is this session for?
139 */
140 struct GNUNET_PeerIdentity target;
141
142 /**
143 * Tokenizer for inbound messages.
144 */
145 struct GNUNET_MessageStreamTokenizer *mst;
146
147 /**
148 * Plugin this session belongs to.
149 */
150 struct Plugin *plugin;
151
152 /**
153 * Session timeout task
154 */
155 struct GNUNET_SCHEDULER_Task *timeout_task;
156
157 /**
158 * When does this session time out?
159 */
160 struct GNUNET_TIME_Absolute timeout;
161
162 /**
163 * What time did we last transmit?
164 */
165 struct GNUNET_TIME_Absolute last_transmit_time;
166
167 /**
168 * expected delay for ACKs
169 */
170 struct GNUNET_TIME_Relative last_expected_ack_delay;
171
172 /**
173 * desired delay between XU messages
174 */
175 struct GNUNET_TIME_Relative last_expected_msg_delay;
176
177 /**
178 */
179 struct GNUNET_TIME_Relative flow_delay_for_other_peer;
180 struct GNUNET_TIME_Relative flow_delay_from_other_peer;
181
182 /**
183 * Our own address.
184 */
185 struct GNUNET_HELLO_Address *address;
186
187 /**
188 * Number of bytes waiting for transmission to this peer.
189 */
190 unsigned long long bytes_in_queue;
191
192 /**
193 * Number of messages waiting for transmission to this peer.
194 */
195 unsigned int msgs_in_queue;
196
197 /**
198 * Reference counter to indicate that this session is
199 * currently being used and must not be destroyed;
200 * setting @e in_destroy will destroy it as soon as
201 * possible.
202 */
203 unsigned int rc;
204
205 /**
206 * Network type of the address.
207 */
208 enum GNUNET_ATS_Network_Type scope;
209
210 /**
211 * Is this session about to be destroyed (sometimes we cannot
212 * destroy a session immediately as below us on the stack
213 * there might be code that still uses it; in this case,
214 * @e rc is non-zero).
215 */
216 int in_destroy;
217};
218
219
220
221/**
222 * If a session monitor is attached, notify it about the new
223 * session state.
224 *
225 * @param plugin our plugin
226 * @param session session that changed state
227 * @param state new state of the session
228 */
229static void
230notify_session_monitor (struct Plugin *plugin,
231 struct GNUNET_ATS_Session *session,
232 enum GNUNET_TRANSPORT_SessionState state)
233{
234 struct GNUNET_TRANSPORT_SessionInfo info;
235
236 if (NULL == plugin->sic)
237 return;
238 if (GNUNET_YES == session->in_destroy)
239 return; /* already destroyed, just RC>0 left-over actions */
240 memset (&info,
241 0,
242 sizeof (info));
243 info.state = state;
244 info.is_inbound = GNUNET_SYSERR; /* hard to say */
245 info.num_msg_pending = session->msgs_in_queue;
246 info.num_bytes_pending = session->bytes_in_queue;
247 /* info.receive_delay remains zero as this is not supported by XU
248 (cannot selectively not receive from 'some' peer while continuing
249 to receive from others) */
250 info.session_timeout = session->timeout;
251 info.address = session->address;
252 plugin->sic (plugin->sic_cls,
253 session,
254 &info);
255}
256
257
258/**
259 * Return information about the given session to the monitor callback.
260 *
261 * @param cls the `struct Plugin` with the monitor callback (`sic`)
262 * @param peer peer we send information about
263 * @param value our `struct GNUNET_ATS_Session` to send information about
264 * @return #GNUNET_OK (continue to iterate)
265 */
266static int
267send_session_info_iter (void *cls,
268 const struct GNUNET_PeerIdentity *peer,
269 void *value)
270{
271 struct Plugin *plugin = cls;
272 struct GNUNET_ATS_Session *session = value;
273
274 (void) peer;
275 notify_session_monitor (plugin,
276 session,
277 GNUNET_TRANSPORT_SS_INIT);
278 notify_session_monitor (plugin,
279 session,
280 GNUNET_TRANSPORT_SS_UP);
281 return GNUNET_OK;
282}
283
284
285/**
286 * Begin monitoring sessions of a plugin. There can only
287 * be one active monitor per plugin (i.e. if there are
288 * multiple monitors, the transport service needs to
289 * multiplex the generated events over all of them).
290 *
291 * @param cls closure of the plugin
292 * @param sic callback to invoke, NULL to disable monitor;
293 * plugin will being by iterating over all active
294 * sessions immediately and then enter monitor mode
295 * @param sic_cls closure for @a sic
296 */
297static void
298xu_plugin_setup_monitor (void *cls,
299 GNUNET_TRANSPORT_SessionInfoCallback sic,
300 void *sic_cls)
301{
302 struct Plugin *plugin = cls;
303
304 plugin->sic = sic;
305 plugin->sic_cls = sic_cls;
306 if (NULL != sic)
307 {
308 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
309 &send_session_info_iter,
310 plugin);
311 /* signal end of first iteration */
312 sic (sic_cls,
313 NULL,
314 NULL);
315 }
316}
317
318
319/* ****************** Little Helpers ****************** */
320
321
322/**
323 * Function to free last resources associated with a session.
324 *
325 * @param s session to free
326 */
327static void
328free_session (struct GNUNET_ATS_Session *s)
329{
330 if (NULL != s->address)
331 {
332 GNUNET_HELLO_address_free (s->address);
333 s->address = NULL;
334 }
335 if (NULL != s->mst)
336 {
337 GNUNET_MST_destroy (s->mst);
338 s->mst = NULL;
339 }
340 GNUNET_free (s);
341}
342
343
344/**
345 * Function that is called to get the keepalive factor.
346 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
347 * calculate the interval between keepalive packets.
348 *
349 * @param cls closure with the `struct Plugin`
350 * @return keepalive factor
351 */
352static unsigned int
353xu_query_keepalive_factor (void *cls)
354{
355 (void) cls;
356 return 15;
357}
358
359
360/**
361 * Function obtain the network type for a session
362 *
363 * @param cls closure (`struct Plugin *`)
364 * @param session the session
365 * @return the network type
366 */
367static enum GNUNET_ATS_Network_Type
368xu_plugin_get_network (void *cls,
369 struct GNUNET_ATS_Session *session)
370{
371 (void) cls;
372 return session->scope;
373}
374
375
376/**
377 * Function obtain the network type for an address.
378 *
379 * @param cls closure (`struct Plugin *`)
380 * @param address the address
381 * @return the network type
382 */
383static enum GNUNET_ATS_Network_Type
384xu_plugin_get_network_for_address (void *cls,
385 const struct GNUNET_HELLO_Address *address)
386{
387 struct Plugin *plugin = cls;
388 size_t addrlen;
389 struct sockaddr_in a4;
390 struct sockaddr_in6 a6;
391 const struct IPv4XuAddress *u4;
392 const struct IPv6XuAddress *u6;
393 const void *sb;
394 size_t sbs;
395
396 addrlen = address->address_length;
397 if (addrlen == sizeof(struct IPv6XuAddress))
398 {
399 GNUNET_assert (NULL != address->address); /* make static analysis happy */
400 u6 = address->address;
401 memset (&a6, 0, sizeof(a6));
402#if HAVE_SOCKADDR_IN_SIN_LEN
403 a6.sin6_len = sizeof (a6);
404#endif
405 a6.sin6_family = AF_INET6;
406 a6.sin6_port = u6->u6_port;
407 GNUNET_memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof(struct in6_addr));
408 sb = &a6;
409 sbs = sizeof(a6);
410 }
411 else if (addrlen == sizeof(struct IPv4XuAddress))
412 {
413 GNUNET_assert (NULL != address->address); /* make static analysis happy */
414 u4 = address->address;
415 memset (&a4, 0, sizeof(a4));
416#if HAVE_SOCKADDR_IN_SIN_LEN
417 a4.sin_len = sizeof (a4);
418#endif
419 a4.sin_family = AF_INET;
420 a4.sin_port = u4->u4_port;
421 a4.sin_addr.s_addr = u4->ipv4_addr;
422 sb = &a4;
423 sbs = sizeof(a4);
424 }
425 else
426 {
427 GNUNET_break (0);
428 return GNUNET_ATS_NET_UNSPECIFIED;
429 }
430 return plugin->env->get_address_type (plugin->env->cls,
431 sb,
432 sbs);
433}
434
435
436/* ******************* Event loop ******************** */
437
438/**
439 * We have been notified that our readset has something to read. We don't
440 * know which socket needs to be read, so we have to check each one
441 * Then reschedule this function to be called again once more is available.
442 *
443 * @param cls the plugin handle
444 */
445static void
446xu_plugin_select_v4 (void *cls);
447
448
449/**
450 * We have been notified that our readset has something to read. We don't
451 * know which socket needs to be read, so we have to check each one
452 * Then reschedule this function to be called again once more is available.
453 *
454 * @param cls the plugin handle
455 */
456static void
457xu_plugin_select_v6 (void *cls);
458
459
460/**
461 * (re)schedule IPv4-select tasks for this plugin.
462 *
463 * @param plugin plugin to reschedule
464 */
465static void
466schedule_select_v4 (struct Plugin *plugin)
467{
468 if ( (GNUNET_YES != plugin->enable_ipv4) ||
469 (NULL == plugin->sockv4) )
470 return;
471 if (NULL != plugin->select_task_v4)
472 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
473 plugin->select_task_v4
474 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
475 plugin->sockv4,
476 &xu_plugin_select_v4,
477 plugin);
478}
479
480
481/**
482 * (re)schedule IPv6-select tasks for this plugin.
483 *
484 * @param plugin plugin to reschedule
485 */
486static void
487schedule_select_v6 (struct Plugin *plugin)
488{
489 if ( (GNUNET_YES != plugin->enable_ipv6) ||
490 (NULL == plugin->sockv6) )
491 return;
492 if (NULL != plugin->select_task_v6)
493 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
494 plugin->select_task_v6
495 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
496 plugin->sockv6,
497 &xu_plugin_select_v6,
498 plugin);
499}
500
501
502/* ******************* Address to string and back ***************** */
503
504
505/**
506 * Function called for a quick conversion of the binary address to
507 * a numeric address. Note that the caller must not free the
508 * address and that the next call to this function is allowed
509 * to override the address again.
510 *
511 * @param cls closure
512 * @param addr binary address (a `union XuAddress`)
513 * @param addrlen length of the @a addr
514 * @return string representing the same address
515 */
516const char *
517xu_address_to_string (void *cls,
518 const void *addr,
519 size_t addrlen)
520{
521 static char rbuf[INET6_ADDRSTRLEN + 10];
522 char buf[INET6_ADDRSTRLEN];
523 const void *sb;
524 struct in_addr a4;
525 struct in6_addr a6;
526 const struct IPv4XuAddress *t4;
527 const struct IPv6XuAddress *t6;
528 int af;
529 uint16_t port;
530 uint32_t options;
531
532 (void) cls;
533 if (NULL == addr)
534 {
535 GNUNET_break_op (0);
536 return NULL;
537 }
538
539 if (addrlen == sizeof(struct IPv6XuAddress))
540 {
541 t6 = addr;
542 af = AF_INET6;
543 options = ntohl (t6->options);
544 port = ntohs (t6->u6_port);
545 a6 = t6->ipv6_addr;
546 sb = &a6;
547 }
548 else if (addrlen == sizeof(struct IPv4XuAddress))
549 {
550 t4 = addr;
551 af = AF_INET;
552 options = ntohl (t4->options);
553 port = ntohs (t4->u4_port);
554 a4.s_addr = t4->ipv4_addr;
555 sb = &a4;
556 }
557 else
558 {
559 GNUNET_break_op (0);
560 return NULL;
561 }
562 inet_ntop (af,
563 sb,
564 buf,
565 INET6_ADDRSTRLEN);
566 GNUNET_snprintf (rbuf,
567 sizeof(rbuf),
568 (af == AF_INET6)
569 ? "%s.%u.[%s]:%u"
570 : "%s.%u.%s:%u",
571 PLUGIN_NAME,
572 options,
573 buf,
574 port);
575 return rbuf;
576}
577
578
579/**
580 * Function called to convert a string address to a binary address.
581 *
582 * @param cls closure (`struct Plugin *`)
583 * @param addr string address
584 * @param addrlen length of the address
585 * @param buf location to store the buffer
586 * @param added location to store the number of bytes in the buffer.
587 * If the function returns #GNUNET_SYSERR, its contents are undefined.
588 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
589 */
590static int
591xu_string_to_address (void *cls,
592 const char *addr,
593 uint16_t addrlen,
594 void **buf,
595 size_t *added)
596{
597 struct sockaddr_storage socket_address;
598 char *address;
599 char *plugin;
600 char *optionstr;
601 uint32_t options;
602
603 (void) cls;
604 /* Format tcp.options.address:port */
605 address = NULL;
606 plugin = NULL;
607 optionstr = NULL;
608
609 if ((NULL == addr) || (0 == addrlen))
610 {
611 GNUNET_break (0);
612 return GNUNET_SYSERR;
613 }
614 if ('\0' != addr[addrlen - 1])
615 {
616 GNUNET_break (0);
617 return GNUNET_SYSERR;
618 }
619 if (strlen (addr) + 1 != (size_t) addrlen)
620 {
621 GNUNET_break (0);
622 return GNUNET_SYSERR;
623 }
624 plugin = GNUNET_strdup (addr);
625 optionstr = strchr (plugin, '.');
626 if (NULL == optionstr)
627 {
628 GNUNET_break (0);
629 GNUNET_free (plugin);
630 return GNUNET_SYSERR;
631 }
632 optionstr[0] = '\0';
633 optionstr++;
634 options = atol (optionstr);
635 address = strchr (optionstr, '.');
636 if (NULL == address)
637 {
638 GNUNET_break (0);
639 GNUNET_free (plugin);
640 return GNUNET_SYSERR;
641 }
642 address[0] = '\0';
643 address++;
644
645 if (GNUNET_OK !=
646 GNUNET_STRINGS_to_address_ip (address,
647 strlen (address),
648 &socket_address))
649 {
650 GNUNET_break (0);
651 GNUNET_free (plugin);
652 return GNUNET_SYSERR;
653 }
654 GNUNET_free(plugin);
655
656 switch (socket_address.ss_family)
657 {
658 case AF_INET:
659 {
660 struct IPv4XuAddress *u4;
661 const struct sockaddr_in *in4 = (const struct sockaddr_in *) &socket_address;
662
663 u4 = GNUNET_new (struct IPv4XuAddress);
664 u4->options = htonl (options);
665 u4->ipv4_addr = in4->sin_addr.s_addr;
666 u4->u4_port = in4->sin_port;
667 *buf = u4;
668 *added = sizeof (struct IPv4XuAddress);
669 return GNUNET_OK;
670 }
671 case AF_INET6:
672 {
673 struct IPv6XuAddress *u6;
674 const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) &socket_address;
675
676 u6 = GNUNET_new (struct IPv6XuAddress);
677 u6->options = htonl (options);
678 u6->ipv6_addr = in6->sin6_addr;
679 u6->u6_port = in6->sin6_port;
680 *buf = u6;
681 *added = sizeof (struct IPv6XuAddress);
682 return GNUNET_OK;
683 }
684 default:
685 GNUNET_break (0);
686 return GNUNET_SYSERR;
687 }
688}
689
690
691/**
692 * Append our port and forward the result.
693 *
694 * @param cls a `struct PrettyPrinterContext *`
695 * @param hostname result from DNS resolver
696 */
697static void
698append_port (void *cls,
699 const char *hostname)
700{
701 struct PrettyPrinterContext *ppc = cls;
702 struct Plugin *plugin = ppc->plugin;
703 char *ret;
704
705 if (NULL == hostname)
706 {
707 /* Final call, done */
708 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
709 plugin->ppc_dll_tail,
710 ppc);
711 ppc->resolver_handle = NULL;
712 ppc->asc (ppc->asc_cls,
713 NULL,
714 GNUNET_OK);
715 GNUNET_free (ppc);
716 return;
717 }
718 if (GNUNET_YES == ppc->ipv6)
719 GNUNET_asprintf (&ret,
720 "%s.%u.[%s]:%d",
721 PLUGIN_NAME,
722 ppc->options,
723 hostname,
724 ppc->port);
725 else
726 GNUNET_asprintf (&ret,
727 "%s.%u.%s:%d",
728 PLUGIN_NAME,
729 ppc->options,
730 hostname,
731 ppc->port);
732 ppc->asc (ppc->asc_cls,
733 ret,
734 GNUNET_OK);
735 GNUNET_free (ret);
736}
737
738
739/**
740 * Convert the transports address to a nice, human-readable format.
741 *
742 * @param cls closure with the `struct Plugin *`
743 * @param type name of the transport that generated the address
744 * @param addr one of the addresses of the host, NULL for the last address
745 * the specific address format depends on the transport;
746 * a `union XuAddress`
747 * @param addrlen length of the address
748 * @param numeric should (IP) addresses be displayed in numeric form?
749 * @param timeout after how long should we give up?
750 * @param asc function to call on each string
751 * @param asc_cls closure for @a asc
752 */
753static void
754xu_plugin_address_pretty_printer (void *cls,
755 const char *type,
756 const void *addr,
757 size_t addrlen,
758 int numeric,
759 struct GNUNET_TIME_Relative timeout,
760 GNUNET_TRANSPORT_AddressStringCallback asc,
761 void *asc_cls)
762{
763 struct Plugin *plugin = cls;
764 struct PrettyPrinterContext *ppc;
765 const struct sockaddr *sb;
766 size_t sbs;
767 struct sockaddr_in a4;
768 struct sockaddr_in6 a6;
769 const struct IPv4XuAddress *u4;
770 const struct IPv6XuAddress *u6;
771 uint16_t port;
772 uint32_t options;
773
774 (void) type;
775 if (addrlen == sizeof(struct IPv6XuAddress))
776 {
777 u6 = addr;
778 memset (&a6,
779 0,
780 sizeof (a6));
781 a6.sin6_family = AF_INET6;
782#if HAVE_SOCKADDR_IN_SIN_LEN
783 a6.sin6_len = sizeof (a6);
784#endif
785 a6.sin6_port = u6->u6_port;
786 a6.sin6_addr = u6->ipv6_addr;
787 port = ntohs (u6->u6_port);
788 options = ntohl (u6->options);
789 sb = (const struct sockaddr *) &a6;
790 sbs = sizeof (a6);
791 }
792 else if (addrlen == sizeof (struct IPv4XuAddress))
793 {
794 u4 = addr;
795 memset (&a4,
796 0,
797 sizeof(a4));
798 a4.sin_family = AF_INET;
799#if HAVE_SOCKADDR_IN_SIN_LEN
800 a4.sin_len = sizeof (a4);
801#endif
802 a4.sin_port = u4->u4_port;
803 a4.sin_addr.s_addr = u4->ipv4_addr;
804 port = ntohs (u4->u4_port);
805 options = ntohl (u4->options);
806 sb = (const struct sockaddr *) &a4;
807 sbs = sizeof(a4);
808 }
809 else
810 {
811 /* invalid address */
812 GNUNET_break_op (0);
813 asc (asc_cls,
814 NULL,
815 GNUNET_SYSERR);
816 asc (asc_cls,
817 NULL,
818 GNUNET_OK);
819 return;
820 }
821 ppc = GNUNET_new (struct PrettyPrinterContext);
822 ppc->plugin = plugin;
823 ppc->asc = asc;
824 ppc->asc_cls = asc_cls;
825 ppc->port = port;
826 ppc->options = options;
827 if (addrlen == sizeof (struct IPv6XuAddress))
828 ppc->ipv6 = GNUNET_YES;
829 else
830 ppc->ipv6 = GNUNET_NO;
831 GNUNET_CONTAINER_DLL_insert (plugin->ppc_dll_head,
832 plugin->ppc_dll_tail,
833 ppc);
834 ppc->resolver_handle
835 = GNUNET_RESOLVER_hostname_get (sb,
836 sbs,
837 ! numeric,
838 timeout,
839 &append_port,
840 ppc);
841}
842
843
844/**
845 * Check if the given port is plausible (must be either our listen
846 * port or our advertised port). If it is neither, we return
847 * #GNUNET_SYSERR.
848 *
849 * @param plugin global variables
850 * @param in_port port number to check
851 * @return #GNUNET_OK if port is either our open or advertised port
852 */
853static int
854check_port (const struct Plugin *plugin,
855 uint16_t in_port)
856{
857 if ( (plugin->port == in_port) ||
858 (plugin->aport == in_port) )
859 return GNUNET_OK;
860 return GNUNET_SYSERR;
861}
862
863
864/**
865 * Function that will be called to check if a binary address for this
866 * plugin is well-formed and corresponds to an address for THIS peer
867 * (as per our configuration). Naturally, if absolutely necessary,
868 * plugins can be a bit conservative in their answer, but in general
869 * plugins should make sure that the address does not redirect
870 * traffic to a 3rd party that might try to man-in-the-middle our
871 * traffic.
872 *
873 * @param cls closure, should be our handle to the Plugin
874 * @param addr pointer to a `union XuAddress`
875 * @param addrlen length of @a addr
876 * @return #GNUNET_OK if this is a plausible address for this peer
877 * and transport, #GNUNET_SYSERR if not
878 */
879static int
880xu_plugin_check_address (void *cls,
881 const void *addr,
882 size_t addrlen)
883{
884 struct Plugin *plugin = cls;
885 const struct IPv4XuAddress *v4;
886 const struct IPv6XuAddress *v6;
887
888 if (sizeof(struct IPv4XuAddress) == addrlen)
889 {
890 struct sockaddr_in s4;
891
892 v4 = (const struct IPv4XuAddress *) addr;
893 if (GNUNET_OK != check_port (plugin,
894 ntohs (v4->u4_port)))
895 return GNUNET_SYSERR;
896 memset (&s4, 0, sizeof (s4));
897 s4.sin_family = AF_INET;
898#if HAVE_SOCKADDR_IN_SIN_LEN
899 s4.sin_len = sizeof (s4);
900#endif
901 s4.sin_port = v4->u4_port;
902 s4.sin_addr.s_addr = v4->ipv4_addr;
903
904 if (GNUNET_OK !=
905 GNUNET_NAT_test_address (plugin->nat,
906 &s4,
907 sizeof (struct sockaddr_in)))
908 return GNUNET_SYSERR;
909 }
910 else if (sizeof(struct IPv6XuAddress) == addrlen)
911 {
912 struct sockaddr_in6 s6;
913
914 v6 = (const struct IPv6XuAddress *) addr;
915 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
916 return GNUNET_OK; /* plausible, if unlikely... */
917 memset (&s6, 0, sizeof (s6));
918 s6.sin6_family = AF_INET6;
919#if HAVE_SOCKADDR_IN_SIN_LEN
920 s6.sin6_len = sizeof (s6);
921#endif
922 s6.sin6_port = v6->u6_port;
923 s6.sin6_addr = v6->ipv6_addr;
924
925 if (GNUNET_OK !=
926 GNUNET_NAT_test_address (plugin->nat,
927 &s6,
928 sizeof(struct sockaddr_in6)))
929 return GNUNET_SYSERR;
930 }
931 else
932 {
933 GNUNET_break_op (0);
934 return GNUNET_SYSERR;
935 }
936 return GNUNET_OK;
937}
938
939
940/**
941 * Our external IP address/port mapping has changed.
942 *
943 * @param cls closure, the `struct Plugin`
944 * @param add_remove #GNUNET_YES to mean the new public IP address,
945 * #GNUNET_NO to mean the previous (now invalid) one
946 * @param ac address class the address belongs to
947 * @param addr either the previous or the new public IP address
948 * @param addrlen actual length of the @a addr
949 */
950static void
951xu_nat_port_map_callback (void *cls,
952 int add_remove,
953 enum GNUNET_NAT_AddressClass ac,
954 const struct sockaddr *addr,
955 socklen_t addrlen)
956{
957 struct Plugin *plugin = cls;
958 struct GNUNET_HELLO_Address *address;
959 struct IPv4XuAddress u4;
960 struct IPv6XuAddress u6;
961 void *arg;
962 size_t args;
963
964 if (GNUNET_NAT_AC_LOOPBACK == ac)
965 return;
966 if (GNUNET_NAT_AC_LAN == ac)
967 return;
968 if (GNUNET_NAT_AC_LAN_PRIVATE == ac)
969 return;
970 LOG (GNUNET_ERROR_TYPE_DEBUG,
971 (GNUNET_YES == add_remove)
972 ? "NAT notification to add address `%s'\n"
973 : "NAT notification to remove address `%s'\n",
974 GNUNET_a2s (addr,
975 addrlen));
976 /* convert 'address' to our internal format */
977 switch (addr->sa_family)
978 {
979 case AF_INET:
980 {
981 const struct sockaddr_in *i4;
982
983 GNUNET_assert (sizeof(struct sockaddr_in) == addrlen);
984 i4 = (const struct sockaddr_in *) addr;
985 if (0 == ntohs (i4->sin_port))
986 return; /* Port = 0 means unmapped, ignore these for XU. */
987 memset (&u4,
988 0,
989 sizeof(u4));
990 u4.options = htonl (plugin->myoptions);
991 u4.ipv4_addr = i4->sin_addr.s_addr;
992 u4.u4_port = i4->sin_port;
993 arg = &u4;
994 args = sizeof (struct IPv4XuAddress);
995 break;
996 }
997 case AF_INET6:
998 {
999 const struct sockaddr_in6 *i6;
1000
1001 GNUNET_assert (sizeof(struct sockaddr_in6) == addrlen);
1002 i6 = (const struct sockaddr_in6 *) addr;
1003 if (0 == ntohs (i6->sin6_port))
1004 return; /* Port = 0 means unmapped, ignore these for XU. */
1005 memset (&u6,
1006 0,
1007 sizeof(u6));
1008 u6.options = htonl (plugin->myoptions);
1009 u6.ipv6_addr = i6->sin6_addr;
1010 u6.u6_port = i6->sin6_port;
1011 arg = &u6;
1012 args = sizeof (struct IPv6XuAddress);
1013 break;
1014 }
1015 default:
1016 GNUNET_break (0);
1017 return;
1018 }
1019 /* modify our published address list */
1020 /* TODO: use 'ac' here in the future... */
1021 address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1022 PLUGIN_NAME,
1023 arg,
1024 args,
1025 GNUNET_HELLO_ADDRESS_INFO_NONE);
1026 plugin->env->notify_address (plugin->env->cls,
1027 add_remove,
1028 address);
1029 GNUNET_HELLO_address_free (address);
1030}
1031
1032
1033/* ********************* Finding sessions ******************* */
1034
1035
1036/**
1037 * Closure for #session_cmp_it().
1038 */
1039struct GNUNET_ATS_SessionCompareContext
1040{
1041 /**
1042 * Set to session matching the address.
1043 */
1044 struct GNUNET_ATS_Session *res;
1045
1046 /**
1047 * Address we are looking for.
1048 */
1049 const struct GNUNET_HELLO_Address *address;
1050};
1051
1052
1053/**
1054 * Find a session with a matching address.
1055 *
1056 * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
1057 * @param key peer identity (unused)
1058 * @param value the `struct GNUNET_ATS_Session *`
1059 * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
1060 */
1061static int
1062session_cmp_it (void *cls,
1063 const struct GNUNET_PeerIdentity *key,
1064 void *value)
1065{
1066 struct GNUNET_ATS_SessionCompareContext *cctx = cls;
1067 struct GNUNET_ATS_Session *s = value;
1068
1069 (void) key;
1070 if (0 == GNUNET_HELLO_address_cmp (s->address,
1071 cctx->address))
1072 {
1073 GNUNET_assert (GNUNET_NO == s->in_destroy);
1074 cctx->res = s;
1075 return GNUNET_NO;
1076 }
1077 return GNUNET_OK;
1078}
1079
1080
1081/**
1082 * Locate an existing session the transport service is using to
1083 * send data to another peer. Performs some basic sanity checks
1084 * on the address and then tries to locate a matching session.
1085 *
1086 * @param cls the plugin
1087 * @param address the address we should locate the session by
1088 * @return the session if it exists, or NULL if it is not found
1089 */
1090static struct GNUNET_ATS_Session *
1091xu_plugin_lookup_session (void *cls,
1092 const struct GNUNET_HELLO_Address *address)
1093{
1094 struct Plugin *plugin = cls;
1095 const struct IPv6XuAddress *xu_a6;
1096 const struct IPv4XuAddress *xu_a4;
1097 struct GNUNET_ATS_SessionCompareContext cctx;
1098
1099 if (NULL == address->address)
1100 {
1101 GNUNET_break (0);
1102 return NULL;
1103 }
1104 if (sizeof(struct IPv4XuAddress) == address->address_length)
1105 {
1106 if (NULL == plugin->sockv4)
1107 return NULL;
1108 xu_a4 = (const struct IPv4XuAddress *) address->address;
1109 if (0 == xu_a4->u4_port)
1110 {
1111 GNUNET_break (0);
1112 return NULL;
1113 }
1114 }
1115 else if (sizeof(struct IPv6XuAddress) == address->address_length)
1116 {
1117 if (NULL == plugin->sockv6)
1118 return NULL;
1119 xu_a6 = (const struct IPv6XuAddress *) address->address;
1120 if (0 == xu_a6->u6_port)
1121 {
1122 GNUNET_break (0);
1123 return NULL;
1124 }
1125 }
1126 else
1127 {
1128 GNUNET_break (0);
1129 return NULL;
1130 }
1131
1132 /* check if session already exists */
1133 cctx.address = address;
1134 cctx.res = NULL;
1135 LOG (GNUNET_ERROR_TYPE_DEBUG,
1136 "Looking for existing session for peer `%s' with address `%s'\n",
1137 GNUNET_i2s (&address->peer),
1138 xu_address_to_string (plugin,
1139 address->address,
1140 address->address_length));
1141 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1142 &address->peer,
1143 &session_cmp_it,
1144 &cctx);
1145 if (NULL == cctx.res)
1146 return NULL;
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Found existing session %p\n",
1149 cctx.res);
1150 return cctx.res;
1151}
1152
1153
1154/* ********************** Timeout ****************** */
1155
1156
1157/**
1158 * Increment session timeout due to activity.
1159 *
1160 * @param s session to reschedule timeout activity for
1161 */
1162static void
1163reschedule_session_timeout (struct GNUNET_ATS_Session *s)
1164{
1165 if (GNUNET_YES == s->in_destroy)
1166 return;
1167 GNUNET_assert (NULL != s->timeout_task);
1168 s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1169}
1170
1171
1172
1173/**
1174 * Function that will be called whenever the transport service wants to
1175 * notify the plugin that a session is still active and in use and
1176 * therefore the session timeout for this session has to be updated
1177 *
1178 * @param cls closure with the `struct Plugin`
1179 * @param peer which peer was the session for
1180 * @param session which session is being updated
1181 */
1182static void
1183xu_plugin_update_session_timeout (void *cls,
1184 const struct GNUNET_PeerIdentity *peer,
1185 struct GNUNET_ATS_Session *session)
1186{
1187 struct Plugin *plugin = cls;
1188
1189 if (GNUNET_YES !=
1190 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1191 peer,
1192 session))
1193 {
1194 GNUNET_break (0);
1195 return;
1196 }
1197 /* Reschedule session timeout */
1198 reschedule_session_timeout (session);
1199}
1200
1201
1202/* ************************* Sending ************************ */
1203
1204
1205/**
1206 * We failed to transmit a message via XU. Generate
1207 * a descriptive error message.
1208 *
1209 * @param plugin our plugin
1210 * @param sa target address we were trying to reach
1211 * @param slen number of bytes in @a sa
1212 * @param error the errno value returned from the sendto() call
1213 */
1214static void
1215analyze_send_error (struct Plugin *plugin,
1216 const struct sockaddr *sa,
1217 socklen_t slen,
1218 int error)
1219{
1220 enum GNUNET_ATS_Network_Type type;
1221
1222 type = plugin->env->get_address_type (plugin->env->cls,
1223 sa,
1224 slen);
1225 if ( ( (GNUNET_ATS_NET_LAN == type) ||
1226 (GNUNET_ATS_NET_WAN == type) ) &&
1227 ( (ENETUNREACH == errno) ||
1228 (ENETDOWN == errno) ) )
1229 {
1230 if (slen == sizeof (struct sockaddr_in))
1231 {
1232 /* IPv4: "Network unreachable" or "Network down"
1233 *
1234 * This indicates we do not have connectivity
1235 */
1236 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1237 _("XU could not transmit message to `%s': "
1238 "Network seems down, please check your network configuration\n"),
1239 GNUNET_a2s (sa,
1240 slen));
1241 }
1242 if (slen == sizeof (struct sockaddr_in6))
1243 {
1244 /* IPv6: "Network unreachable" or "Network down"
1245 *
1246 * This indicates that this system is IPv6 enabled, but does not
1247 * have a valid global IPv6 address assigned or we do not have
1248 * connectivity
1249 */
1250 LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1251 _("XU could not transmit IPv6 message! "
1252 "Please check your network configuration and disable IPv6 if your "
1253 "connection does not have a global IPv6 address\n"));
1254 }
1255 }
1256 else
1257 {
1258 LOG (GNUNET_ERROR_TYPE_WARNING,
1259 "XU could not transmit message to `%s': `%s'\n",
1260 GNUNET_a2s (sa,
1261 slen),
1262 STRERROR (error));
1263 }
1264}
1265
1266
1267
1268
1269/**
1270 * Function that can be used by the transport service to transmit a
1271 * message using the plugin. Note that in the case of a peer
1272 * disconnecting, the continuation MUST be called prior to the
1273 * disconnect notification itself. This function will be called with
1274 * this peer's HELLO message to initiate a fresh connection to another
1275 * peer.
1276 *
1277 * @param cls closure
1278 * @param s which session must be used
1279 * @param msgbuf the message to transmit
1280 * @param msgbuf_size number of bytes in @a msgbuf
1281 * @param priority how important is the message (most plugins will
1282 * ignore message priority and just FIFO)
1283 * @param to how long to wait at most for the transmission (does not
1284 * require plugins to discard the message after the timeout,
1285 * just advisory for the desired delay; most plugins will ignore
1286 * this as well)
1287 * @param cont continuation to call once the message has
1288 * been transmitted (or if the transport is ready
1289 * for the next transmission call; or if the
1290 * peer disconnected...); can be NULL
1291 * @param cont_cls closure for @a cont
1292 * @return number of bytes used (on the physical network, with overheads);
1293 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1294 * and does NOT mean that the message was not transmitted (DV)
1295 */
1296static ssize_t
1297xu_plugin_send (void *cls,
1298 struct GNUNET_ATS_Session *s,
1299 const char *msgbuf,
1300 size_t msgbuf_size,
1301 unsigned int priority,
1302 struct GNUNET_TIME_Relative to,
1303 GNUNET_TRANSPORT_TransmitContinuation cont,
1304 void *cont_cls)
1305{
1306 struct Plugin *plugin = cls;
1307 size_t xumlen = msgbuf_size + sizeof(struct XUMessage);
1308 struct XUMessage *xu;
1309 char mbuf[xumlen] GNUNET_ALIGN;
1310 ssize_t sent;
1311 socklen_t slen;
1312 const struct sockaddr *a;
1313 const struct IPv4XuAddress *u4;
1314 struct sockaddr_in a4;
1315 const struct IPv6XuAddress *u6;
1316 struct sockaddr_in6 a6;
1317 struct GNUNET_NETWORK_Handle *sock;
1318
1319 (void) priority;
1320 (void) to;
1321 if ( (sizeof(struct IPv6XuAddress) == s->address->address_length) &&
1322 (NULL == plugin->sockv6) )
1323 return GNUNET_SYSERR;
1324 if ( (sizeof(struct IPv4XuAddress) == s->address->address_length) &&
1325 (NULL == plugin->sockv4) )
1326 return GNUNET_SYSERR;
1327 if (xumlen >= GNUNET_MAX_MESSAGE_SIZE)
1328 {
1329 GNUNET_break (0);
1330 return GNUNET_SYSERR;
1331 }
1332 if (GNUNET_YES !=
1333 GNUNET_CONTAINER_multipeermap_contains_value (plugin->sessions,
1334 &s->target,
1335 s))
1336 {
1337 GNUNET_break (0);
1338 return GNUNET_SYSERR;
1339 }
1340 LOG (GNUNET_ERROR_TYPE_DEBUG,
1341 "XU transmits %u-byte message to `%s' using address `%s'\n",
1342 xumlen,
1343 GNUNET_i2s (&s->target),
1344 xu_address_to_string (plugin,
1345 s->address->address,
1346 s->address->address_length));
1347 xu = (struct XUMessage *) mbuf;
1348 xu->header.size = htons (xumlen);
1349 xu->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE);
1350 xu->reserved = htonl (0);
1351 xu->sender = *plugin->env->my_identity;
1352 GNUNET_memcpy (&xu[1],
1353 msgbuf,
1354 msgbuf_size);
1355
1356 if (sizeof (struct IPv4XuAddress) == s->address->address_length)
1357 {
1358 u4 = s->address->address;
1359 memset (&a4,
1360 0,
1361 sizeof(a4));
1362 a4.sin_family = AF_INET;
1363#if HAVE_SOCKADDR_IN_SIN_LEN
1364 a4.sin_len = sizeof (a4);
1365#endif
1366 a4.sin_port = u4->u4_port;
1367 a4.sin_addr.s_addr = u4->ipv4_addr;
1368 a = (const struct sockaddr *) &a4;
1369 slen = sizeof (a4);
1370 sock = plugin->sockv4;
1371 }
1372 else if (sizeof (struct IPv6XuAddress) == s->address->address_length)
1373 {
1374 u6 = s->address->address;
1375 memset (&a6,
1376 0,
1377 sizeof(a6));
1378 a6.sin6_family = AF_INET6;
1379#if HAVE_SOCKADDR_IN_SIN_LEN
1380 a6.sin6_len = sizeof (a6);
1381#endif
1382 a6.sin6_port = u6->u6_port;
1383 a6.sin6_addr = u6->ipv6_addr;
1384 a = (const struct sockaddr *) &a6;
1385 slen = sizeof (a6);
1386 sock = plugin->sockv6;
1387 }
1388 else
1389 {
1390 GNUNET_break (0);
1391 return GNUNET_SYSERR;
1392 }
1393
1394 sent = GNUNET_NETWORK_socket_sendto (sock,
1395 mbuf,
1396 xumlen,
1397 a,
1398 slen);
1399 s->last_transmit_time
1400 = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
1401 s->last_transmit_time);
1402
1403 if (GNUNET_SYSERR == sent)
1404 {
1405 /* Failure */
1406 analyze_send_error (plugin,
1407 a,
1408 slen,
1409 errno);
1410 GNUNET_STATISTICS_update (plugin->env->stats,
1411 "# XU, total, bytes, sent, failure",
1412 sent,
1413 GNUNET_NO);
1414 GNUNET_STATISTICS_update (plugin->env->stats,
1415 "# XU, total, messages, sent, failure",
1416 1,
1417 GNUNET_NO);
1418 return GNUNET_SYSERR;
1419 }
1420 /* Success */
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "XU transmitted %u-byte message to `%s' `%s' (%d: %s)\n",
1423 (unsigned int) (msgbuf_size),
1424 GNUNET_i2s (&s->target),
1425 GNUNET_a2s (a,
1426 slen),
1427 (int ) sent,
1428 (sent < 0) ? STRERROR (errno) : "ok");
1429 GNUNET_STATISTICS_update (plugin->env->stats,
1430 "# XU, total, bytes, sent, success",
1431 sent,
1432 GNUNET_NO);
1433 GNUNET_STATISTICS_update (plugin->env->stats,
1434 "# XU, total, messages, sent, success",
1435 1,
1436 GNUNET_NO);
1437 cont (cont_cls,
1438 &s->target,
1439 GNUNET_OK,
1440 msgbuf_size,
1441 xumlen);
1442 notify_session_monitor (s->plugin,
1443 s,
1444 GNUNET_TRANSPORT_SS_UPDATE);
1445 return xumlen;
1446}
1447
1448
1449/* ********************** Receiving ********************** */
1450
1451
1452/**
1453 * Functions with this signature are called whenever we need to close
1454 * a session due to a disconnect or failure to establish a connection.
1455 *
1456 * @param cls closure with the `struct Plugin`
1457 * @param s session to close down
1458 * @return #GNUNET_OK on success
1459 */
1460static int
1461xu_disconnect_session (void *cls,
1462 struct GNUNET_ATS_Session *s)
1463{
1464 struct Plugin *plugin = cls;
1465
1466 GNUNET_assert (GNUNET_YES != s->in_destroy);
1467 LOG (GNUNET_ERROR_TYPE_DEBUG,
1468 "Session %p to peer `%s' at address %s ended\n",
1469 s,
1470 GNUNET_i2s (&s->target),
1471 xu_address_to_string (plugin,
1472 s->address->address,
1473 s->address->address_length));
1474 if (NULL != s->timeout_task)
1475 {
1476 GNUNET_SCHEDULER_cancel (s->timeout_task);
1477 s->timeout_task = NULL;
1478 }
1479 GNUNET_assert (GNUNET_YES ==
1480 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
1481 &s->target,
1482 s));
1483 s->in_destroy = GNUNET_YES;
1484 notify_session_monitor (s->plugin,
1485 s,
1486 GNUNET_TRANSPORT_SS_DONE);
1487 plugin->env->session_end (plugin->env->cls,
1488 s->address,
1489 s);
1490 GNUNET_STATISTICS_set (plugin->env->stats,
1491 "# XU sessions active",
1492 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1493 GNUNET_NO);
1494 if (0 == s->rc)
1495 free_session (s);
1496 return GNUNET_OK;
1497}
1498
1499
1500/**
1501 * Message tokenizer has broken up an incomming message. Pass it on
1502 * to the service.
1503 *
1504 * @param cls the `struct GNUNET_ATS_Session *`
1505 * @param hdr the actual message
1506 * @return #GNUNET_OK (always)
1507 */
1508static int
1509process_inbound_tokenized_messages (void *cls,
1510 const struct GNUNET_MessageHeader *hdr)
1511{
1512 struct GNUNET_ATS_Session *session = cls;
1513 struct Plugin *plugin = session->plugin;
1514
1515 if (GNUNET_YES == session->in_destroy)
1516 return GNUNET_OK;
1517 reschedule_session_timeout (session);
1518 session->flow_delay_for_other_peer
1519 = plugin->env->receive (plugin->env->cls,
1520 session->address,
1521 session,
1522 hdr);
1523 return GNUNET_OK;
1524}
1525
1526
1527/**
1528 * Destroy a session, plugin is being unloaded.
1529 *
1530 * @param cls the `struct Plugin`
1531 * @param key hash of public key of target peer
1532 * @param value a `struct PeerSession *` to clean up
1533 * @return #GNUNET_OK (continue to iterate)
1534 */
1535static int
1536disconnect_and_free_it (void *cls,
1537 const struct GNUNET_PeerIdentity *key,
1538 void *value)
1539{
1540 struct Plugin *plugin = cls;
1541
1542 (void) key;
1543 xu_disconnect_session (plugin,
1544 value);
1545 return GNUNET_OK;
1546}
1547
1548
1549/**
1550 * Disconnect from a remote node. Clean up session if we have one for
1551 * this peer.
1552 *
1553 * @param cls closure for this call (should be handle to Plugin)
1554 * @param target the peeridentity of the peer to disconnect
1555 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
1556 */
1557static void
1558xu_disconnect (void *cls,
1559 const struct GNUNET_PeerIdentity *target)
1560{
1561 struct Plugin *plugin = cls;
1562
1563 LOG (GNUNET_ERROR_TYPE_DEBUG,
1564 "Disconnecting from peer `%s'\n",
1565 GNUNET_i2s (target));
1566 GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
1567 target,
1568 &disconnect_and_free_it,
1569 plugin);
1570}
1571
1572
1573/**
1574 * Session was idle, so disconnect it.
1575 *
1576 * @param cls the `struct GNUNET_ATS_Session` to time out
1577 */
1578static void
1579session_timeout (void *cls)
1580{
1581 struct GNUNET_ATS_Session *s = cls;
1582 struct Plugin *plugin = s->plugin;
1583 struct GNUNET_TIME_Relative left;
1584
1585 s->timeout_task = NULL;
1586 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1587 if (left.rel_value_us > 0)
1588 {
1589 /* not actually our turn yet, but let's at least update
1590 the monitor, it may think we're about to die ... */
1591 notify_session_monitor (s->plugin,
1592 s,
1593 GNUNET_TRANSPORT_SS_UPDATE);
1594 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1595 &session_timeout,
1596 s);
1597 return;
1598 }
1599 LOG (GNUNET_ERROR_TYPE_DEBUG,
1600 "Session %p was idle for %s, disconnecting\n",
1601 s,
1602 GNUNET_STRINGS_relative_time_to_string (XU_SESSION_TIME_OUT,
1603 GNUNET_YES));
1604 /* call session destroy function */
1605 xu_disconnect_session (plugin,
1606 s);
1607}
1608
1609
1610/**
1611 * Allocate a new session for the given endpoint address.
1612 * Note that this function does not inform the service
1613 * of the new session, this is the responsibility of the
1614 * caller (if needed).
1615 *
1616 * @param cls the `struct Plugin`
1617 * @param address address of the other peer to use
1618 * @param network_type network type the address belongs to
1619 * @return NULL on error, otherwise session handle
1620 */
1621static struct GNUNET_ATS_Session *
1622xu_plugin_create_session (void *cls,
1623 const struct GNUNET_HELLO_Address *address,
1624 enum GNUNET_ATS_Network_Type network_type)
1625{
1626 struct Plugin *plugin = cls;
1627 struct GNUNET_ATS_Session *s;
1628
1629 s = GNUNET_new (struct GNUNET_ATS_Session);
1630 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
1631 s);
1632 s->plugin = plugin;
1633 s->address = GNUNET_HELLO_address_copy (address);
1634 s->target = address->peer;
1635 s->last_transmit_time = GNUNET_TIME_absolute_get ();
1636 s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1637 250);
1638 s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1639 s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
1640 s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
1641 s->timeout = GNUNET_TIME_relative_to_absolute (XU_SESSION_TIME_OUT);
1642 s->timeout_task = GNUNET_SCHEDULER_add_delayed (XU_SESSION_TIME_OUT,
1643 &session_timeout,
1644 s);
1645 s->scope = network_type;
1646
1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1648 "Creating new session %p for peer `%s' address `%s'\n",
1649 s,
1650 GNUNET_i2s (&address->peer),
1651 xu_address_to_string (plugin,
1652 address->address,
1653 address->address_length));
1654 GNUNET_assert (GNUNET_OK ==
1655 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1656 &s->target,
1657 s,
1658 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1659 GNUNET_STATISTICS_set (plugin->env->stats,
1660 "# XU sessions active",
1661 GNUNET_CONTAINER_multipeermap_size (plugin->sessions),
1662 GNUNET_NO);
1663 notify_session_monitor (plugin,
1664 s,
1665 GNUNET_TRANSPORT_SS_INIT);
1666 return s;
1667}
1668
1669
1670/**
1671 * Creates a new outbound session the transport service will use to
1672 * send data to the peer.
1673 *
1674 * @param cls the `struct Plugin *`
1675 * @param address the address
1676 * @return the session or NULL of max connections exceeded
1677 */
1678static struct GNUNET_ATS_Session *
1679xu_plugin_get_session (void *cls,
1680 const struct GNUNET_HELLO_Address *address)
1681{
1682 struct Plugin *plugin = cls;
1683 struct GNUNET_ATS_Session *s;
1684 enum GNUNET_ATS_Network_Type network_type = GNUNET_ATS_NET_UNSPECIFIED;
1685 const struct IPv4XuAddress *xu_v4;
1686 const struct IPv6XuAddress *xu_v6;
1687
1688 if (NULL == address)
1689 {
1690 GNUNET_break (0);
1691 return NULL;
1692 }
1693 if ( (address->address_length != sizeof(struct IPv4XuAddress)) &&
1694 (address->address_length != sizeof(struct IPv6XuAddress)) )
1695 {
1696 GNUNET_break_op (0);
1697 return NULL;
1698 }
1699 if (NULL != (s = xu_plugin_lookup_session (cls,
1700 address)))
1701 return s;
1702
1703 /* need to create new session */
1704 if (sizeof (struct IPv4XuAddress) == address->address_length)
1705 {
1706 struct sockaddr_in v4;
1707
1708 xu_v4 = (const struct IPv4XuAddress *) address->address;
1709 memset (&v4, '\0', sizeof (v4));
1710 v4.sin_family = AF_INET;
1711#if HAVE_SOCKADDR_IN_SIN_LEN
1712 v4.sin_len = sizeof (struct sockaddr_in);
1713#endif
1714 v4.sin_port = xu_v4->u4_port;
1715 v4.sin_addr.s_addr = xu_v4->ipv4_addr;
1716 network_type = plugin->env->get_address_type (plugin->env->cls,
1717 (const struct sockaddr *) &v4,
1718 sizeof (v4));
1719 }
1720 if (sizeof (struct IPv6XuAddress) == address->address_length)
1721 {
1722 struct sockaddr_in6 v6;
1723
1724 xu_v6 = (const struct IPv6XuAddress *) address->address;
1725 memset (&v6, '\0', sizeof (v6));
1726 v6.sin6_family = AF_INET6;
1727#if HAVE_SOCKADDR_IN_SIN_LEN
1728 v6.sin6_len = sizeof (struct sockaddr_in6);
1729#endif
1730 v6.sin6_port = xu_v6->u6_port;
1731 v6.sin6_addr = xu_v6->ipv6_addr;
1732 network_type = plugin->env->get_address_type (plugin->env->cls,
1733 (const struct sockaddr *) &v6,
1734 sizeof (v6));
1735 }
1736 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
1737 return xu_plugin_create_session (cls,
1738 address,
1739 network_type);
1740}
1741
1742
1743/**
1744 * We've received a XU Message. Process it (pass contents to main service).
1745 *
1746 * @param plugin plugin context
1747 * @param msg the message
1748 * @param xu_addr sender address
1749 * @param xu_addr_len number of bytes in @a xu_addr
1750 * @param network_type network type the address belongs to
1751 */
1752static void
1753process_xu_message (struct Plugin *plugin,
1754 const struct XUMessage *msg,
1755 const union XuAddress *xu_addr,
1756 size_t xu_addr_len,
1757 enum GNUNET_ATS_Network_Type network_type)
1758{
1759 struct GNUNET_ATS_Session *s;
1760 struct GNUNET_HELLO_Address *address;
1761
1762 GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
1763 if (0 != ntohl (msg->reserved))
1764 {
1765 GNUNET_break_op(0);
1766 return;
1767 }
1768 if (ntohs (msg->header.size)
1769 < sizeof(struct GNUNET_MessageHeader) + sizeof(struct XUMessage))
1770 {
1771 GNUNET_break_op(0);
1772 return;
1773 }
1774
1775 address = GNUNET_HELLO_address_allocate (&msg->sender,
1776 PLUGIN_NAME,
1777 xu_addr,
1778 xu_addr_len,
1779 GNUNET_HELLO_ADDRESS_INFO_NONE);
1780 if (NULL ==
1781 (s = xu_plugin_lookup_session (plugin,
1782 address)))
1783 {
1784 s = xu_plugin_create_session (plugin,
1785 address,
1786 network_type);
1787 plugin->env->session_start (plugin->env->cls,
1788 address,
1789 s,
1790 s->scope);
1791 notify_session_monitor (plugin,
1792 s,
1793 GNUNET_TRANSPORT_SS_UP);
1794 }
1795 GNUNET_free (address);
1796
1797 s->rc++;
1798 GNUNET_MST_from_buffer (s->mst,
1799 (const char *) &msg[1],
1800 ntohs (msg->header.size) - sizeof(struct XUMessage),
1801 GNUNET_YES,
1802 GNUNET_NO);
1803 s->rc--;
1804 if ( (0 == s->rc) &&
1805 (GNUNET_YES == s->in_destroy) )
1806 free_session (s);
1807}
1808
1809
1810/**
1811 * Read and process a message from the given socket.
1812 *
1813 * @param plugin the overall plugin
1814 * @param rsock socket to read from
1815 */
1816static void
1817xu_select_read (struct Plugin *plugin,
1818 struct GNUNET_NETWORK_Handle *rsock)
1819{
1820 socklen_t fromlen;
1821 struct sockaddr_storage addr;
1822 char buf[65536] GNUNET_ALIGN;
1823 ssize_t size;
1824 const struct GNUNET_MessageHeader *msg;
1825 struct IPv4XuAddress v4;
1826 struct IPv6XuAddress v6;
1827 const struct sockaddr *sa;
1828 const struct sockaddr_in *sa4;
1829 const struct sockaddr_in6 *sa6;
1830 const union XuAddress *int_addr;
1831 size_t int_addr_len;
1832 enum GNUNET_ATS_Network_Type network_type;
1833
1834 fromlen = sizeof (addr);
1835 memset (&addr,
1836 0,
1837 sizeof(addr));
1838 size = GNUNET_NETWORK_socket_recvfrom (rsock,
1839 buf,
1840 sizeof (buf),
1841 (struct sockaddr *) &addr,
1842 &fromlen);
1843 sa = (const struct sockaddr *) &addr;
1844#if MINGW
1845 /* On SOCK_DGRAM XU sockets recvfrom might fail with a
1846 * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!)
1847 * on this socket has failed.
1848 * Quote from MSDN:
1849 * WSAECONNRESET - The virtual circuit was reset by the remote side
1850 * executing a hard or abortive close. The application should close
1851 * the socket; it is no longer usable. On a XU-datagram socket this
1852 * error indicates a previous send operation resulted in an ICMP Port
1853 * Unreachable message.
1854 */
1855 if ( (-1 == size) &&
1856 (ECONNRESET == errno) )
1857 return;
1858#endif
1859 if (-1 == size)
1860 {
1861 LOG (GNUNET_ERROR_TYPE_DEBUG,
1862 "XU failed to receive data: %s\n",
1863 STRERROR (errno));
1864 /* Connection failure or something. Not a protocol violation. */
1865 return;
1866 }
1867
1868 /* Check if this is a STUN packet */
1869 if (GNUNET_NO !=
1870 GNUNET_NAT_stun_handle_packet (plugin->nat,
1871 (const struct sockaddr *) &addr,
1872 fromlen,
1873 buf,
1874 size))
1875 return; /* was STUN, do not process further */
1876
1877 if (((size_t) size) < sizeof(struct GNUNET_MessageHeader))
1878 {
1879 LOG (GNUNET_ERROR_TYPE_WARNING,
1880 "XU got %u bytes from %s, which is not enough for a GNUnet message header\n",
1881 (unsigned int ) size,
1882 GNUNET_a2s (sa,
1883 fromlen));
1884 /* _MAY_ be a connection failure (got partial message) */
1885 /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
1886 GNUNET_break_op (0);
1887 return;
1888 }
1889
1890 msg = (const struct GNUNET_MessageHeader *) buf;
1891 LOG (GNUNET_ERROR_TYPE_DEBUG,
1892 "XU received %u-byte message from `%s' type %u\n",
1893 (unsigned int) size,
1894 GNUNET_a2s (sa,
1895 fromlen),
1896 ntohs (msg->type));
1897 if (size != ntohs (msg->size))
1898 {
1899 LOG (GNUNET_ERROR_TYPE_WARNING,
1900 "XU malformed message (size %u) header from %s\n",
1901 (unsigned int) size,
1902 GNUNET_a2s (sa,
1903 fromlen));
1904 GNUNET_break_op (0);
1905 return;
1906 }
1907 GNUNET_STATISTICS_update (plugin->env->stats,
1908 "# XU, total bytes received",
1909 size,
1910 GNUNET_NO);
1911 network_type = plugin->env->get_address_type (plugin->env->cls,
1912 sa,
1913 fromlen);
1914 switch (sa->sa_family)
1915 {
1916 case AF_INET:
1917 sa4 = (const struct sockaddr_in *) &addr;
1918 v4.options = 0;
1919 v4.ipv4_addr = sa4->sin_addr.s_addr;
1920 v4.u4_port = sa4->sin_port;
1921 int_addr = (union XuAddress *) &v4;
1922 int_addr_len = sizeof (v4);
1923 break;
1924 case AF_INET6:
1925 sa6 = (const struct sockaddr_in6 *) &addr;
1926 v6.options = 0;
1927 v6.ipv6_addr = sa6->sin6_addr;
1928 v6.u6_port = sa6->sin6_port;
1929 int_addr = (union XuAddress *) &v6;
1930 int_addr_len = sizeof (v6);
1931 break;
1932 default:
1933 GNUNET_break (0);
1934 return;
1935 }
1936
1937 switch (ntohs (msg->type))
1938 {
1939 case GNUNET_MESSAGE_TYPE_TRANSPORT_XU_MESSAGE:
1940 if (ntohs (msg->size) < sizeof(struct XUMessage))
1941 {
1942 GNUNET_break_op(0);
1943 return;
1944 }
1945 process_xu_message (plugin,
1946 (const struct XUMessage *) msg,
1947 int_addr,
1948 int_addr_len,
1949 network_type);
1950 return;
1951 default:
1952 GNUNET_break_op(0);
1953 return;
1954 }
1955}
1956
1957
1958/* ***************** Event loop (part 2) *************** */
1959
1960
1961/**
1962 * We have been notified that our readset has something to read. We don't
1963 * know which socket needs to be read, so we have to check each one
1964 * Then reschedule this function to be called again once more is available.
1965 *
1966 * @param cls the plugin handle
1967 */
1968static void
1969xu_plugin_select_v4 (void *cls)
1970{
1971 struct Plugin *plugin = cls;
1972 const struct GNUNET_SCHEDULER_TaskContext *tc;
1973
1974 plugin->select_task_v4 = NULL;
1975 if (NULL == plugin->sockv4)
1976 return;
1977 tc = GNUNET_SCHEDULER_get_task_context ();
1978 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
1979 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
1980 plugin->sockv4)) )
1981 xu_select_read (plugin,
1982 plugin->sockv4);
1983 schedule_select_v4 (plugin);
1984}
1985
1986
1987/**
1988 * We have been notified that our readset has something to read. We don't
1989 * know which socket needs to be read, so we have to check each one
1990 * Then reschedule this function to be called again once more is available.
1991 *
1992 * @param cls the plugin handle
1993 */
1994static void
1995xu_plugin_select_v6 (void *cls)
1996{
1997 struct Plugin *plugin = cls;
1998 const struct GNUNET_SCHEDULER_TaskContext *tc;
1999
2000 plugin->select_task_v6 = NULL;
2001 if (NULL == plugin->sockv6)
2002 return;
2003 tc = GNUNET_SCHEDULER_get_task_context ();
2004 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
2005 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
2006 plugin->sockv6)) )
2007 xu_select_read (plugin,
2008 plugin->sockv6);
2009 schedule_select_v6 (plugin);
2010}
2011
2012
2013/* ******************* Initialization *************** */
2014
2015
2016/**
2017 * Setup the XU sockets (for IPv4 and IPv6) for the plugin.
2018 *
2019 * @param plugin the plugin to initialize
2020 * @param bind_v6 IPv6 address to bind to (can be NULL, for 'any')
2021 * @param bind_v4 IPv4 address to bind to (can be NULL, for 'any')
2022 * @return number of sockets that were successfully bound
2023 */
2024static unsigned int
2025setup_sockets (struct Plugin *plugin,
2026 const struct sockaddr_in6 *bind_v6,
2027 const struct sockaddr_in *bind_v4)
2028{
2029 int tries;
2030 unsigned int sockets_created = 0;
2031 struct sockaddr_in6 server_addrv6;
2032 struct sockaddr_in server_addrv4;
2033 const struct sockaddr *server_addr;
2034 const struct sockaddr *addrs[2];
2035 socklen_t addrlens[2];
2036 socklen_t addrlen;
2037 int eno;
2038
2039 /* Create IPv6 socket */
2040 eno = EINVAL;
2041 if (GNUNET_YES == plugin->enable_ipv6)
2042 {
2043 plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6,
2044 SOCK_DGRAM,
2045 0);
2046 if (NULL == plugin->sockv6)
2047 {
2048 LOG (GNUNET_ERROR_TYPE_INFO,
2049 _("Disabling IPv6 since it is not supported on this system!\n"));
2050 plugin->enable_ipv6 = GNUNET_NO;
2051 }
2052 else
2053 {
2054 memset (&server_addrv6,
2055 0,
2056 sizeof(struct sockaddr_in6));
2057#if HAVE_SOCKADDR_IN_SIN_LEN
2058 server_addrv6.sin6_len = sizeof (struct sockaddr_in6);
2059#endif
2060 server_addrv6.sin6_family = AF_INET6;
2061 if (NULL != bind_v6)
2062 server_addrv6.sin6_addr = bind_v6->sin6_addr;
2063 else
2064 server_addrv6.sin6_addr = in6addr_any;
2065
2066 if (0 == plugin->port) /* autodetect */
2067 server_addrv6.sin6_port
2068 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2069 33537)
2070 + 32000);
2071 else
2072 server_addrv6.sin6_port = htons (plugin->port);
2073 addrlen = sizeof (struct sockaddr_in6);
2074 server_addr = (const struct sockaddr *) &server_addrv6;
2075
2076 tries = 0;
2077 while (tries < 10)
2078 {
2079 LOG(GNUNET_ERROR_TYPE_DEBUG,
2080 "Binding to IPv6 `%s'\n",
2081 GNUNET_a2s (server_addr,
2082 addrlen));
2083 /* binding */
2084 if (GNUNET_OK ==
2085 GNUNET_NETWORK_socket_bind (plugin->sockv6,
2086 server_addr,
2087 addrlen))
2088 break;
2089 eno = errno;
2090 if (0 != plugin->port)
2091 {
2092 tries = 10; /* fail immediately */
2093 break; /* bind failed on specific port */
2094 }
2095 /* autodetect */
2096 server_addrv6.sin6_port
2097 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2098 33537)
2099 + 32000);
2100 tries++;
2101 }
2102 if (tries >= 10)
2103 {
2104 GNUNET_NETWORK_socket_close (plugin->sockv6);
2105 plugin->enable_ipv6 = GNUNET_NO;
2106 plugin->sockv6 = NULL;
2107 }
2108 else
2109 {
2110 plugin->port = ntohs (server_addrv6.sin6_port);
2111 }
2112 if (NULL != plugin->sockv6)
2113 {
2114 LOG (GNUNET_ERROR_TYPE_DEBUG,
2115 "IPv6 XU socket created listinging at %s\n",
2116 GNUNET_a2s (server_addr,
2117 addrlen));
2118 addrs[sockets_created] = server_addr;
2119 addrlens[sockets_created] = addrlen;
2120 sockets_created++;
2121 }
2122 else
2123 {
2124 LOG (GNUNET_ERROR_TYPE_WARNING,
2125 _("Failed to bind XU socket to %s: %s\n"),
2126 GNUNET_a2s (server_addr,
2127 addrlen),
2128 STRERROR (eno));
2129 }
2130 }
2131 }
2132
2133 /* Create IPv4 socket */
2134 eno = EINVAL;
2135 plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET,
2136 SOCK_DGRAM,
2137 0);
2138 if (NULL == plugin->sockv4)
2139 {
2140 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
2141 "socket");
2142 LOG (GNUNET_ERROR_TYPE_INFO,
2143 _("Disabling IPv4 since it is not supported on this system!\n"));
2144 plugin->enable_ipv4 = GNUNET_NO;
2145 }
2146 else
2147 {
2148 memset (&server_addrv4,
2149 0,
2150 sizeof(struct sockaddr_in));
2151#if HAVE_SOCKADDR_IN_SIN_LEN
2152 server_addrv4.sin_len = sizeof (struct sockaddr_in);
2153#endif
2154 server_addrv4.sin_family = AF_INET;
2155 if (NULL != bind_v4)
2156 server_addrv4.sin_addr = bind_v4->sin_addr;
2157 else
2158 server_addrv4.sin_addr.s_addr = INADDR_ANY;
2159
2160 if (0 == plugin->port)
2161 /* autodetect */
2162 server_addrv4.sin_port
2163 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2164 33537)
2165 + 32000);
2166 else
2167 server_addrv4.sin_port = htons (plugin->port);
2168
2169 addrlen = sizeof (struct sockaddr_in);
2170 server_addr = (const struct sockaddr *) &server_addrv4;
2171
2172 tries = 0;
2173 while (tries < 10)
2174 {
2175 LOG (GNUNET_ERROR_TYPE_DEBUG,
2176 "Binding to IPv4 `%s'\n",
2177 GNUNET_a2s (server_addr,
2178 addrlen));
2179
2180 /* binding */
2181 if (GNUNET_OK ==
2182 GNUNET_NETWORK_socket_bind (plugin->sockv4,
2183 server_addr,
2184 addrlen))
2185 break;
2186 eno = errno;
2187 if (0 != plugin->port)
2188 {
2189 tries = 10; /* fail */
2190 break; /* bind failed on specific port */
2191 }
2192
2193 /* autodetect */
2194 server_addrv4.sin_port
2195 = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
2196 33537)
2197 + 32000);
2198 tries++;
2199 }
2200 if (tries >= 10)
2201 {
2202 GNUNET_NETWORK_socket_close (plugin->sockv4);
2203 plugin->enable_ipv4 = GNUNET_NO;
2204 plugin->sockv4 = NULL;
2205 }
2206 else
2207 {
2208 plugin->port = ntohs (server_addrv4.sin_port);
2209 }
2210
2211 if (NULL != plugin->sockv4)
2212 {
2213 LOG (GNUNET_ERROR_TYPE_DEBUG,
2214 "IPv4 socket created on port %s\n",
2215 GNUNET_a2s (server_addr,
2216 addrlen));
2217 addrs[sockets_created] = server_addr;
2218 addrlens[sockets_created] = addrlen;
2219 sockets_created++;
2220 }
2221 else
2222 {
2223 LOG (GNUNET_ERROR_TYPE_ERROR,
2224 _("Failed to bind XU socket to %s: %s\n"),
2225 GNUNET_a2s (server_addr,
2226 addrlen),
2227 STRERROR (eno));
2228 }
2229 }
2230
2231 if (0 == sockets_created)
2232 {
2233 LOG (GNUNET_ERROR_TYPE_WARNING,
2234 _("Failed to open XU sockets\n"));
2235 return 0; /* No sockets created, return */
2236 }
2237 schedule_select_v4 (plugin);
2238 schedule_select_v6 (plugin);
2239 plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
2240 "transport-xu",
2241 IPPROTO_UDP,
2242 sockets_created,
2243 addrs,
2244 addrlens,
2245 &xu_nat_port_map_callback,
2246 NULL,
2247 plugin);
2248 return sockets_created;
2249}
2250
2251
2252/**
2253 * The exported method. Makes the core api available via a global and
2254 * returns the xu transport API.
2255 *
2256 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2257 * @return our `struct GNUNET_TRANSPORT_PluginFunctions`
2258 */
2259void *
2260libgnunet_plugin_transport_xu_init (void *cls)
2261{
2262 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2263 struct GNUNET_TRANSPORT_PluginFunctions *api;
2264 struct Plugin *p;
2265 unsigned long long port;
2266 unsigned long long aport;
2267 int enable_v6;
2268 char *bind4_address;
2269 char *bind6_address;
2270 struct sockaddr_in server_addrv4;
2271 struct sockaddr_in6 server_addrv6;
2272 unsigned int res;
2273 int have_bind4;
2274 int have_bind6;
2275
2276 if (NULL == env->receive)
2277 {
2278 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2279 initialze the plugin or the API */
2280 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2281 api->cls = NULL;
2282 api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2283 api->address_to_string = &xu_address_to_string;
2284 api->string_to_address = &xu_string_to_address;
2285 return api;
2286 }
2287
2288 /* Get port number: port == 0 : autodetect a port,
2289 * > 0 : use this port, not given : 2086 default */
2290 if (GNUNET_OK !=
2291 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2292 "transport-xu",
2293 "PORT",
2294 &port))
2295 port = 2086;
2296 if (port > 65535)
2297 {
2298 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2299 "transport-xu",
2300 "PORT",
2301 _("must be in [0,65535]"));
2302 return NULL;
2303 }
2304 if (GNUNET_OK !=
2305 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2306 "transport-xu",
2307 "ADVERTISED_PORT",
2308 &aport))
2309 aport = port;
2310 if (aport > 65535)
2311 {
2312 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2313 "transport-xu",
2314 "ADVERTISED_PORT",
2315 _("must be in [0,65535]"));
2316 return NULL;
2317 }
2318
2319 if (GNUNET_YES ==
2320 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2321 "nat",
2322 "DISABLEV6"))
2323 enable_v6 = GNUNET_NO;
2324 else
2325 enable_v6 = GNUNET_YES;
2326
2327 have_bind4 = GNUNET_NO;
2328 memset (&server_addrv4,
2329 0,
2330 sizeof (server_addrv4));
2331 if (GNUNET_YES ==
2332 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2333 "transport-xu",
2334 "BINDTO",
2335 &bind4_address))
2336 {
2337 LOG (GNUNET_ERROR_TYPE_DEBUG,
2338 "Binding XU plugin to specific address: `%s'\n",
2339 bind4_address);
2340 if (1 != inet_pton (AF_INET,
2341 bind4_address,
2342 &server_addrv4.sin_addr))
2343 {
2344 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2345 "transport-xu",
2346 "BINDTO",
2347 _("must be valid IPv4 address"));
2348 GNUNET_free (bind4_address);
2349 return NULL;
2350 }
2351 have_bind4 = GNUNET_YES;
2352 }
2353 GNUNET_free_non_null (bind4_address);
2354 have_bind6 = GNUNET_NO;
2355 memset (&server_addrv6,
2356 0,
2357 sizeof (server_addrv6));
2358 if (GNUNET_YES ==
2359 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2360 "transport-xu",
2361 "BINDTO6",
2362 &bind6_address))
2363 {
2364 LOG (GNUNET_ERROR_TYPE_DEBUG,
2365 "Binding xu plugin to specific address: `%s'\n",
2366 bind6_address);
2367 if (1 != inet_pton (AF_INET6,
2368 bind6_address,
2369 &server_addrv6.sin6_addr))
2370 {
2371 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2372 "transport-xu",
2373 "BINDTO6",
2374 _("must be valid IPv6 address"));
2375 GNUNET_free (bind6_address);
2376 return NULL;
2377 }
2378 have_bind6 = GNUNET_YES;
2379 }
2380 GNUNET_free_non_null (bind6_address);
2381
2382 p = GNUNET_new (struct Plugin);
2383 p->port = port;
2384 p->aport = aport;
2385 p->enable_ipv6 = enable_v6;
2386 p->enable_ipv4 = GNUNET_YES; /* default */
2387 p->env = env;
2388 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
2389 GNUNET_NO);
2390 res = setup_sockets (p,
2391 (GNUNET_YES == have_bind6) ? &server_addrv6 : NULL,
2392 (GNUNET_YES == have_bind4) ? &server_addrv4 : NULL);
2393 if ( (0 == res) ||
2394 ( (NULL == p->sockv4) &&
2395 (NULL == p->sockv6) ) )
2396 {
2397 LOG (GNUNET_ERROR_TYPE_ERROR,
2398 _("Failed to create XU network sockets\n"));
2399 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
2400 if (NULL != p->nat)
2401 GNUNET_NAT_unregister (p->nat);
2402 GNUNET_free (p);
2403 return NULL;
2404 }
2405
2406 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2407 api->cls = p;
2408 api->disconnect_session = &xu_disconnect_session;
2409 api->query_keepalive_factor = &xu_query_keepalive_factor;
2410 api->disconnect_peer = &xu_disconnect;
2411 api->address_pretty_printer = &xu_plugin_address_pretty_printer;
2412 api->address_to_string = &xu_address_to_string;
2413 api->string_to_address = &xu_string_to_address;
2414 api->check_address = &xu_plugin_check_address;
2415 api->get_session = &xu_plugin_get_session;
2416 api->send = &xu_plugin_send;
2417 api->get_network = &xu_plugin_get_network;
2418 api->get_network_for_address = &xu_plugin_get_network_for_address;
2419 api->update_session_timeout = &xu_plugin_update_session_timeout;
2420 api->setup_monitor = &xu_plugin_setup_monitor;
2421 return api;
2422}
2423
2424
2425/**
2426 * The exported method. Makes the core api available via a global and
2427 * returns the xu transport API.
2428 *
2429 * @param cls our `struct GNUNET_TRANSPORT_PluginEnvironment`
2430 * @return NULL
2431 */
2432void *
2433libgnunet_plugin_transport_xu_done (void *cls)
2434{
2435 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2436 struct Plugin *plugin = api->cls;
2437 struct PrettyPrinterContext *cur;
2438
2439 if (NULL == plugin)
2440 {
2441 GNUNET_free (api);
2442 return NULL;
2443 }
2444 if (NULL != plugin->select_task_v4)
2445 {
2446 GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
2447 plugin->select_task_v4 = NULL;
2448 }
2449 if (NULL != plugin->select_task_v6)
2450 {
2451 GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
2452 plugin->select_task_v6 = NULL;
2453 }
2454 if (NULL != plugin->sockv4)
2455 {
2456 GNUNET_break (GNUNET_OK ==
2457 GNUNET_NETWORK_socket_close (plugin->sockv4));
2458 plugin->sockv4 = NULL;
2459 }
2460 if (NULL != plugin->sockv6)
2461 {
2462 GNUNET_break (GNUNET_OK ==
2463 GNUNET_NETWORK_socket_close (plugin->sockv6));
2464 plugin->sockv6 = NULL;
2465 }
2466 if (NULL != plugin->nat)
2467 {
2468 GNUNET_NAT_unregister (plugin->nat);
2469 plugin->nat = NULL;
2470 }
2471 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2472
2473 while (NULL != (cur = plugin->ppc_dll_head))
2474 {
2475 GNUNET_break (0);
2476 GNUNET_CONTAINER_DLL_remove (plugin->ppc_dll_head,
2477 plugin->ppc_dll_tail,
2478 cur);
2479 GNUNET_RESOLVER_request_cancel (cur->resolver_handle);
2480 if (NULL != cur->timeout_task)
2481 {
2482 GNUNET_SCHEDULER_cancel (cur->timeout_task);
2483 cur->timeout_task = NULL;
2484 }
2485 GNUNET_free (cur);
2486 }
2487 GNUNET_free (plugin);
2488 GNUNET_free (api);
2489 return NULL;
2490}
2491
2492/* end of plugin_transport_xu.c */
diff --git a/src/transport/plugin_transport_xu.h b/src/transport/plugin_transport_xu.h
new file mode 100644
index 000000000..1884f92e8
--- /dev/null
+++ b/src/transport/plugin_transport_xu.h
@@ -0,0 +1,273 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file transport/plugin_transport_xu.h
23 * @brief Implementation of the XU transport protocol
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 * @author Matthias Wachs
27 */
28#ifndef PLUGIN_TRANSPORT_XU_H
29#define PLUGIN_TRANSPORT_XU_H
30
31#include "platform.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_fragmentation_lib.h"
35#include "gnunet_protocols.h"
36#include "gnunet_resolver_service.h"
37#include "gnunet_signatures.h"
38#include "gnunet_constants.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet_transport_service.h"
41#include "gnunet_transport_plugin.h"
42#include "transport.h"
43
44#define LOG(kind,...) GNUNET_log_from (kind, "transport-xu", __VA_ARGS__)
45
46#define PLUGIN_NAME "xu"
47
48#define DEBUG_XU GNUNET_NO
49
50#define DEBUG_XU_BROADCASTING GNUNET_NO
51
52/**
53 * MTU for fragmentation subsystem. Should be conservative since
54 * all communicating peers MUST work with this MTU.
55 */
56#define XU_MTU 1400
57
58
59GNUNET_NETWORK_STRUCT_BEGIN
60/**
61 * Network format for IPv4 addresses.
62 */
63struct IPv4XuAddress
64{
65 /**
66 * Optional options and flags for this address
67 */
68 uint32_t options GNUNET_PACKED;
69
70 /**
71 * IPv4 address, in network byte order.
72 */
73 uint32_t ipv4_addr GNUNET_PACKED;
74
75 /**
76 * Port number, in network byte order.
77 */
78 uint16_t u4_port GNUNET_PACKED;
79};
80
81
82/**
83 * Network format for IPv6 addresses.
84 */
85struct IPv6XuAddress
86{
87 /**
88 * Optional options and flags for this address
89 */
90 uint32_t options GNUNET_PACKED;
91
92 /**
93 * IPv6 address.
94 */
95 struct in6_addr ipv6_addr GNUNET_PACKED;
96
97 /**
98 * Port number, in network byte order.
99 */
100 uint16_t u6_port GNUNET_PACKED;
101};
102GNUNET_NETWORK_STRUCT_END
103
104/**
105 * Either an IPv4 or IPv6 XU address. Note that without a "length",
106 * one cannot tell which one of the two types this address represents.
107 */
108union XuAddress
109{
110 /**
111 * IPv4 case.
112 */
113 struct IPv4XuAddress v4;
114
115 /**
116 * IPv6 case.
117 */
118 struct IPv6XuAddress v6;
119};
120
121
122/**
123 * Information we track for each message in the queue.
124 */
125struct XU_MessageWrapper;
126
127
128/**
129 * Closure for #append_port().
130 */
131struct PrettyPrinterContext;
132
133
134/**
135 * Encapsulation of all of the state of the plugin.
136 */
137struct Plugin
138{
139
140 /**
141 * Our environment.
142 */
143 struct GNUNET_TRANSPORT_PluginEnvironment *env;
144
145 /**
146 * Session of peers with whom we are currently connected,
147 * map of peer identity to `struct GNUNET_ATS_Session *`.
148 */
149 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
150
151 /**
152 * ID of select task for IPv4
153 */
154 struct GNUNET_SCHEDULER_Task *select_task_v4;
155
156 /**
157 * ID of select task for IPv6
158 */
159 struct GNUNET_SCHEDULER_Task *select_task_v6;
160
161 /**
162 * Address we were told to bind to exclusively (IPv4).
163 */
164 char *bind4_address;
165
166 /**
167 * Address we were told to bind to exclusively (IPv6).
168 */
169 char *bind6_address;
170
171 /**
172 * Handle to NAT traversal support.
173 */
174 struct GNUNET_NAT_Handle *nat;
175
176 /**
177 * Handle to NAT traversal support.
178 */
179 struct GNUNET_NAT_STUN_Handle *stun;
180
181 /**
182 * The read socket for IPv4
183 */
184 struct GNUNET_NETWORK_Handle *sockv4;
185
186 /**
187 * The read socket for IPv6
188 */
189 struct GNUNET_NETWORK_Handle *sockv6;
190
191 /**
192 * Running pretty printers: head
193 */
194 struct PrettyPrinterContext *ppc_dll_head;
195
196 /**
197 * Running pretty printers: tail
198 */
199 struct PrettyPrinterContext *ppc_dll_tail;
200
201 /**
202 * Function to call about session status changes.
203 */
204 GNUNET_TRANSPORT_SessionInfoCallback sic;
205
206 /**
207 * Closure for @e sic.
208 */
209 void *sic_cls;
210
211 /**
212 * IPv6 multicast address
213 */
214 struct sockaddr_in6 ipv6_multicast_address;
215
216 /**
217 * Broadcast interval
218 */
219 struct GNUNET_TIME_Relative broadcast_interval;
220
221 /**
222 * Bytes currently in buffer
223 */
224 int64_t bytes_in_buffer;
225
226 /**
227 * Address options
228 */
229 uint32_t myoptions;
230
231 /**
232 * Is IPv6 enabled: #GNUNET_YES or #GNUNET_NO
233 */
234 int enable_ipv6;
235
236 /**
237 * Is IPv4 enabled: #GNUNET_YES or #GNUNET_NO
238 */
239 int enable_ipv4;
240
241 /**
242 * Port we listen on.
243 */
244 uint16_t port;
245
246 /**
247 * Port we advertise on.
248 */
249 uint16_t aport;
250
251};
252
253
254/**
255 * Function called for a quick conversion of the binary address to
256 * a numeric address. Note that the caller must not free the
257 * address and that the next call to this function is allowed
258 * to override the address again.
259 *
260 * @param cls closure
261 * @param addr binary address (a `union XuAddress`)
262 * @param addrlen length of the @a addr
263 * @return string representing the same address
264 */
265const char *
266xu_address_to_string (void *cls,
267 const void *addr,
268 size_t addrlen);
269
270
271/*#ifndef PLUGIN_TRANSPORT_XU_H*/
272#endif
273/* end of plugin_transport_xu.h */
diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in
index 2c99af000..1f56a2fa7 100644
--- a/src/transport/transport.conf.in
+++ b/src/transport/transport.conf.in
@@ -68,6 +68,38 @@ MAX_CONNECTIONS = 128
68TCP_STEALTH = NO 68TCP_STEALTH = NO
69 69
70 70
71
72[transport-xt]
73# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
74PORT = 2087
75
76# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
77ADVERTISED_PORT = 2087
78
79# If we have a manually punched NAT, what is the external IP and port?
80# Can use DNS names for DynDNS-based detection of external IP.
81# Can use IPv6 addresses ([fefc::]:PORT).
82# Use "AUTO" for the hostname to automatically detect external IP.
83# Do not set if NAT is not manually punched.
84# HOLE_EXTERNAL = AUTO:2087
85
86TESTING_IGNORE_KEYS = ACCEPT_FROM;
87
88# Maximum number of open TCP connections allowed
89MAX_CONNECTIONS = 128
90
91TIMEOUT = 5 s
92# ACCEPT_FROM =
93# ACCEPT_FROM6 =
94# REJECT_FROM =
95# REJECT_FROM6 =
96# BINDTO =
97MAX_CONNECTIONS = 128
98
99# Enable TCP stealth?
100TCP_STEALTH = NO
101
102
71[transport-udp] 103[transport-udp]
72# Use PORT = 0 to autodetect a port available 104# Use PORT = 0 to autodetect a port available
73PORT = 2086 105PORT = 2086
@@ -90,6 +122,11 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM;
90# HOLE_EXTERNAL = AUTO:2086 122# HOLE_EXTERNAL = AUTO:2086
91 123
92 124
125[transport-xu]
126# Use PORT = 0 to autodetect a port available
127PORT = 2087
128
129
93[transport-http_client] 130[transport-http_client]
94MAX_CONNECTIONS = 128 131MAX_CONNECTIONS = 128
95TESTING_IGNORE_KEYS = ACCEPT_FROM; 132TESTING_IGNORE_KEYS = ACCEPT_FROM;
diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c
index c836c9055..f9341f528 100644
--- a/src/util/getopt_helpers.c
+++ b/src/util/getopt_helpers.c
@@ -793,6 +793,82 @@ GNUNET_GETOPT_option_uint (char shortName,
793} 793}
794 794
795 795
796
797/**
798 * Set an option of type 'uint16_t' from the command line.
799 * A pointer to this function should be passed as part of the
800 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
801 * of this type. It should be followed by a pointer to a value of
802 * type 'uint16_t'.
803 *
804 * @param ctx command line processing context
805 * @param scls additional closure (will point to the 'unsigned int')
806 * @param option name of the option
807 * @param value actual value of the option as a string.
808 * @return #GNUNET_OK if parsing the value worked
809 */
810static int
811set_uint16 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
812 void *scls,
813 const char *option,
814 const char *value)
815{
816 uint16_t *val = scls;
817 unsigned int v;
818
819 (void) ctx;
820 if (1 != SSCANF (value,
821 "%u",
822 v))
823 {
824 FPRINTF (stderr,
825 _("You must pass a number to the `%s' option.\n"),
826 option);
827 return GNUNET_SYSERR;
828 }
829 if (v > UINT16_MAX)
830 {
831 FPRINTF (stderr,
832 _("You must pass a number below %u to the `%s' option.\n"),
833 (unsigned int) UINT16_MAX,
834 option);
835 return GNUNET_SYSERR;
836 }
837 *val = (uint16_t) v;
838 return GNUNET_OK;
839}
840
841
842/**
843 * Allow user to specify an uint16_t.
844 *
845 * @param shortName short name of the option
846 * @param name long name of the option
847 * @param argumentHelp help text for the option argument
848 * @param description long help text for the option
849 * @param[out] val set to the value specified at the command line
850 */
851struct GNUNET_GETOPT_CommandLineOption
852GNUNET_GETOPT_option_uint16 (char shortName,
853 const char *name,
854 const char *argumentHelp,
855 const char *description,
856 uint16_t *val)
857{
858 struct GNUNET_GETOPT_CommandLineOption clo = {
859 .shortName = shortName,
860 .name = name,
861 .argumentHelp = argumentHelp,
862 .description = description,
863 .require_argument = 1,
864 .processor = &set_uint16,
865 .scls = (void *) val
866 };
867
868 return clo;
869}
870
871
796/** 872/**
797 * Closure for #set_base32(). 873 * Closure for #set_base32().
798 */ 874 */