diff options
-rw-r--r-- | src/include/gnunet_crypto_lib.h | 12 | ||||
-rw-r--r-- | src/transport/gnunet-service-tng.c | 289 |
2 files changed, 228 insertions, 73 deletions
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h index 257fee48d..6822de2f1 100644 --- a/src/include/gnunet_crypto_lib.h +++ b/src/include/gnunet_crypto_lib.h | |||
@@ -1955,7 +1955,7 @@ GNUNET_CRYPTO_rsa_public_key_encode (const struct GNUNET_CRYPTO_RsaPublicKey *ke | |||
1955 | */ | 1955 | */ |
1956 | struct GNUNET_CRYPTO_RsaPublicKey * | 1956 | struct GNUNET_CRYPTO_RsaPublicKey * |
1957 | GNUNET_CRYPTO_rsa_public_key_decode (const char *buf, | 1957 | GNUNET_CRYPTO_rsa_public_key_decode (const char *buf, |
1958 | size_t len); | 1958 | size_t len); |
1959 | 1959 | ||
1960 | 1960 | ||
1961 | /** | 1961 | /** |
@@ -1977,7 +1977,7 @@ GNUNET_CRYPTO_rsa_public_key_dup (const struct GNUNET_CRYPTO_RsaPublicKey *key); | |||
1977 | */ | 1977 | */ |
1978 | int | 1978 | int |
1979 | GNUNET_CRYPTO_rsa_signature_cmp (struct GNUNET_CRYPTO_RsaSignature *s1, | 1979 | GNUNET_CRYPTO_rsa_signature_cmp (struct GNUNET_CRYPTO_RsaSignature *s1, |
1980 | struct GNUNET_CRYPTO_RsaSignature *s2); | 1980 | struct GNUNET_CRYPTO_RsaSignature *s2); |
1981 | 1981 | ||
1982 | /** | 1982 | /** |
1983 | * Compare the values of two private keys. | 1983 | * Compare the values of two private keys. |
@@ -1988,7 +1988,7 @@ GNUNET_CRYPTO_rsa_signature_cmp (struct GNUNET_CRYPTO_RsaSignature *s1, | |||
1988 | */ | 1988 | */ |
1989 | int | 1989 | int |
1990 | GNUNET_CRYPTO_rsa_private_key_cmp (struct GNUNET_CRYPTO_RsaPrivateKey *p1, | 1990 | GNUNET_CRYPTO_rsa_private_key_cmp (struct GNUNET_CRYPTO_RsaPrivateKey *p1, |
1991 | struct GNUNET_CRYPTO_RsaPrivateKey *p2); | 1991 | struct GNUNET_CRYPTO_RsaPrivateKey *p2); |
1992 | 1992 | ||
1993 | 1993 | ||
1994 | /** | 1994 | /** |
@@ -2000,7 +2000,7 @@ GNUNET_CRYPTO_rsa_private_key_cmp (struct GNUNET_CRYPTO_RsaPrivateKey *p1, | |||
2000 | */ | 2000 | */ |
2001 | int | 2001 | int |
2002 | GNUNET_CRYPTO_rsa_public_key_cmp (struct GNUNET_CRYPTO_RsaPublicKey *p1, | 2002 | GNUNET_CRYPTO_rsa_public_key_cmp (struct GNUNET_CRYPTO_RsaPublicKey *p1, |
2003 | struct GNUNET_CRYPTO_RsaPublicKey *p2); | 2003 | struct GNUNET_CRYPTO_RsaPublicKey *p2); |
2004 | 2004 | ||
2005 | 2005 | ||
2006 | /** | 2006 | /** |
@@ -2065,7 +2065,7 @@ GNUNET_CRYPTO_rsa_signature_free (struct GNUNET_CRYPTO_RsaSignature *sig); | |||
2065 | */ | 2065 | */ |
2066 | size_t | 2066 | size_t |
2067 | GNUNET_CRYPTO_rsa_signature_encode (const struct GNUNET_CRYPTO_RsaSignature *sig, | 2067 | GNUNET_CRYPTO_rsa_signature_encode (const struct GNUNET_CRYPTO_RsaSignature *sig, |
2068 | char **buffer); | 2068 | char **buffer); |
2069 | 2069 | ||
2070 | 2070 | ||
2071 | /** | 2071 | /** |
@@ -2078,7 +2078,7 @@ GNUNET_CRYPTO_rsa_signature_encode (const struct GNUNET_CRYPTO_RsaSignature *sig | |||
2078 | */ | 2078 | */ |
2079 | struct GNUNET_CRYPTO_RsaSignature * | 2079 | struct GNUNET_CRYPTO_RsaSignature * |
2080 | GNUNET_CRYPTO_rsa_signature_decode (const char *buf, | 2080 | GNUNET_CRYPTO_rsa_signature_decode (const char *buf, |
2081 | size_t len); | 2081 | size_t len); |
2082 | 2082 | ||
2083 | 2083 | ||
2084 | /** | 2084 | /** |
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c index e685e28a6..ecff6b6e1 100644 --- a/src/transport/gnunet-service-tng.c +++ b/src/transport/gnunet-service-tng.c | |||
@@ -138,6 +138,10 @@ | |||
138 | * When do we forget an invalid address for sure? | 138 | * When do we forget an invalid address for sure? |
139 | */ | 139 | */ |
140 | #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1) | 140 | #define MAX_ADDRESS_VALID_UNTIL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1) |
141 | /** | ||
142 | * How long do we consider an address valid if we just checked? | ||
143 | */ | ||
144 | #define ADDRESS_VALIDATION_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) | ||
141 | 145 | ||
142 | /** | 146 | /** |
143 | * What is the maximum frequency at which we do address validation? | 147 | * What is the maximum frequency at which we do address validation? |
@@ -148,6 +152,14 @@ | |||
148 | #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS | 152 | #define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS |
149 | 153 | ||
150 | /** | 154 | /** |
155 | * How many network RTTs before an address validation expires should we begin | ||
156 | * trying to revalidate? (Note that the RTT used here is the one that we | ||
157 | * experienced during the last validation, not necessarily the latest RTT | ||
158 | * observed). | ||
159 | */ | ||
160 | #define VALIDATION_RTT_BUFFER_FACTOR 3 | ||
161 | |||
162 | /** | ||
151 | * How many messages can we have pending for a given communicator | 163 | * How many messages can we have pending for a given communicator |
152 | * process before we start to throttle that communicator? | 164 | * process before we start to throttle that communicator? |
153 | * | 165 | * |
@@ -1597,8 +1609,8 @@ struct ValidationState | |||
1597 | * Next time we will send the @e challenge to the peer, if this time is past | 1609 | * Next time we will send the @e challenge to the peer, if this time is past |
1598 | * @e valid_until, this validation state is released at this time. If the | 1610 | * @e valid_until, this validation state is released at this time. If the |
1599 | * address is valid, @e next_challenge is set to @e validated_until MINUS @e | 1611 | * address is valid, @e next_challenge is set to @e validated_until MINUS @e |
1600 | * validation_delay * 3, such that we will try to re-validate before the | 1612 | * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try |
1601 | * validity actually expires. | 1613 | * to re-validate before the validity actually expires. |
1602 | */ | 1614 | */ |
1603 | struct GNUNET_TIME_Absolute next_challenge; | 1615 | struct GNUNET_TIME_Absolute next_challenge; |
1604 | 1616 | ||
@@ -3051,10 +3063,13 @@ store_pi (void *cls); | |||
3051 | 3063 | ||
3052 | /** | 3064 | /** |
3053 | * Function called when peerstore is done storing our address. | 3065 | * Function called when peerstore is done storing our address. |
3066 | * | ||
3067 | * @param cls a `struct AddressListEntry` | ||
3068 | * @param success #GNUNET_YES if peerstore was successful | ||
3054 | */ | 3069 | */ |
3055 | static void | 3070 | static void |
3056 | peerstore_store_cb (void *cls, | 3071 | peerstore_store_own_cb (void *cls, |
3057 | int success) | 3072 | int success) |
3058 | { | 3073 | { |
3059 | struct AddressListEntry *ale = cls; | 3074 | struct AddressListEntry *ale = cls; |
3060 | 3075 | ||
@@ -3081,29 +3096,20 @@ static void | |||
3081 | store_pi (void *cls) | 3096 | store_pi (void *cls) |
3082 | { | 3097 | { |
3083 | struct AddressListEntry *ale = cls; | 3098 | struct AddressListEntry *ale = cls; |
3084 | void *addr; | ||
3085 | size_t addr_len; | ||
3086 | struct GNUNET_TIME_Absolute expiration; | 3099 | struct GNUNET_TIME_Absolute expiration; |
3087 | 3100 | ||
3088 | ale->st = NULL; | 3101 | ale->st = NULL; |
3089 | expiration = GNUNET_TIME_relative_to_absolute (ale->expiration); | 3102 | expiration = GNUNET_TIME_relative_to_absolute (ale->expiration); |
3090 | GNUNET_HELLO_sign_address (ale->address, | ||
3091 | ale->nt, | ||
3092 | expiration, | ||
3093 | GST_my_private_key, | ||
3094 | &addr, | ||
3095 | &addr_len); | ||
3096 | ale->sc = GNUNET_PEERSTORE_store (peerstore, | 3103 | ale->sc = GNUNET_PEERSTORE_store (peerstore, |
3097 | "transport", | 3104 | "transport", |
3098 | &GST_my_identity, | 3105 | &GST_my_identity, |
3099 | GNUNET_HELLO_PEERSTORE_KEY, | 3106 | GNUNET_HELLO_PEERSTORE_KEY, |
3100 | addr, | 3107 | ale->address, |
3101 | addr_len, | 3108 | strlen (ale->address) + 1, |
3102 | expiration, | 3109 | expiration, |
3103 | GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, | 3110 | GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, |
3104 | &peerstore_store_cb, | 3111 | &peerstore_store_own_cb, |
3105 | ale); | 3112 | ale); |
3106 | GNUNET_free (addr); | ||
3107 | if (NULL == ale->sc) | 3113 | if (NULL == ale->sc) |
3108 | { | 3114 | { |
3109 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 3115 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
@@ -3847,6 +3853,120 @@ handle_validation_challenge (void *cls, | |||
3847 | 3853 | ||
3848 | 3854 | ||
3849 | /** | 3855 | /** |
3856 | * Closure for #check_known_challenge. | ||
3857 | */ | ||
3858 | struct CheckKnownChallengeContext | ||
3859 | { | ||
3860 | /** | ||
3861 | * Set to the challenge we are looking for. | ||
3862 | */ | ||
3863 | const struct GNUNET_ShortHashCode *challenge; | ||
3864 | |||
3865 | /** | ||
3866 | * Set to a matching validation state, if one was found. | ||
3867 | */ | ||
3868 | struct ValidationState *vs; | ||
3869 | }; | ||
3870 | |||
3871 | |||
3872 | /** | ||
3873 | * Test if the validation state in @a value matches the | ||
3874 | * challenge from @a cls. | ||
3875 | * | ||
3876 | * @param cls a `struct CheckKnownChallengeContext` | ||
3877 | * @param pid unused (must match though) | ||
3878 | * @param value a `struct ValidationState` | ||
3879 | * @return #GNUNET_OK if not matching, #GNUNET_NO if match found | ||
3880 | */ | ||
3881 | static int | ||
3882 | check_known_challenge (void *cls, | ||
3883 | const struct GNUNET_PeerIdentity *pid, | ||
3884 | void *value) | ||
3885 | { | ||
3886 | struct CheckKnownChallengeContext *ckac = cls; | ||
3887 | struct ValidationState *vs = value; | ||
3888 | |||
3889 | (void) pid; | ||
3890 | if (0 != GNUNET_memcmp (&vs->challenge, | ||
3891 | ckac->challenge)) | ||
3892 | return GNUNET_OK; | ||
3893 | ckac->vs = vs; | ||
3894 | return GNUNET_NO; | ||
3895 | } | ||
3896 | |||
3897 | |||
3898 | /** | ||
3899 | * Function called when peerstore is done storing a | ||
3900 | * validated address. | ||
3901 | * | ||
3902 | * @param cls a `struct ValidationState` | ||
3903 | * @param success #GNUNET_YES on success | ||
3904 | */ | ||
3905 | static void | ||
3906 | peerstore_store_validation_cb (void *cls, | ||
3907 | int success) | ||
3908 | { | ||
3909 | struct ValidationState *vs = cls; | ||
3910 | |||
3911 | vs->sc = NULL; | ||
3912 | if (GNUNET_YES == success) | ||
3913 | return; | ||
3914 | GNUNET_STATISTICS_update (GST_stats, | ||
3915 | "# Peerstore failed to store foreign address", | ||
3916 | 1, | ||
3917 | GNUNET_NO); | ||
3918 | } | ||
3919 | |||
3920 | |||
3921 | /** | ||
3922 | * Task run periodically to validate some address based on #validation_heap. | ||
3923 | * | ||
3924 | * @param cls NULL | ||
3925 | */ | ||
3926 | static void | ||
3927 | validation_start_cb (void *cls); | ||
3928 | |||
3929 | |||
3930 | /** | ||
3931 | * Set the time for next_challenge of @a vs to @a new_time. | ||
3932 | * Updates the heap and if necessary reschedules the job. | ||
3933 | * | ||
3934 | * @param vs validation state to update | ||
3935 | * @param new_time new time for revalidation | ||
3936 | */ | ||
3937 | static void | ||
3938 | update_next_challenge_time (struct ValidationState *vs, | ||
3939 | struct GNUNET_TIME_Absolute new_time) | ||
3940 | { | ||
3941 | struct GNUNET_TIME_Relative delta; | ||
3942 | |||
3943 | if (new_time.abs_value_us == vs->next_challenge.abs_value_us) | ||
3944 | return; /* be lazy */ | ||
3945 | vs->next_challenge = new_time; | ||
3946 | if (NULL == vs->hn) | ||
3947 | vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap, | ||
3948 | vs, | ||
3949 | new_time.abs_value_us); | ||
3950 | else | ||
3951 | GNUNET_CONTAINER_heap_update_cost (vs->hn, | ||
3952 | new_time.abs_value_us); | ||
3953 | if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) && | ||
3954 | (NULL != validation_task) ) | ||
3955 | return; | ||
3956 | if (NULL != validation_task) | ||
3957 | GNUNET_SCHEDULER_cancel (validation_task); | ||
3958 | /* randomize a bit */ | ||
3959 | delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
3960 | MIN_DELAY_ADDRESS_VALIDATION.rel_value_us); | ||
3961 | new_time = GNUNET_TIME_absolute_add (new_time, | ||
3962 | delta); | ||
3963 | validation_task = GNUNET_SCHEDULER_add_at (new_time, | ||
3964 | &validation_start_cb, | ||
3965 | NULL); | ||
3966 | } | ||
3967 | |||
3968 | |||
3969 | /** | ||
3850 | * Communicator gave us a transport address validation response. Process the request. | 3970 | * Communicator gave us a transport address validation response. Process the request. |
3851 | * | 3971 | * |
3852 | * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done) | 3972 | * @param cls a `struct CommunicatorMessageContext` (must call #finish_cmc_handling() when done) |
@@ -3857,9 +3977,92 @@ handle_validation_response (void *cls, | |||
3857 | const struct TransportValidationResponse *tvr) | 3977 | const struct TransportValidationResponse *tvr) |
3858 | { | 3978 | { |
3859 | struct CommunicatorMessageContext *cmc = cls; | 3979 | struct CommunicatorMessageContext *cmc = cls; |
3980 | struct ValidationState *vs; | ||
3981 | struct CheckKnownChallengeContext ckac = { | ||
3982 | .challenge = &tvr->challenge, | ||
3983 | .vs = NULL | ||
3984 | }; | ||
3985 | struct GNUNET_TIME_Absolute origin_time; | ||
3860 | 3986 | ||
3861 | // FIXME: check for matching pending challenge and mark address | 3987 | /* check this is one of our challenges */ |
3862 | // as valid if applicable (passing to PEERSTORE as well!) | 3988 | (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map, |
3989 | &cmc->im.sender, | ||
3990 | &check_known_challenge, | ||
3991 | &ckac); | ||
3992 | if (NULL == (vs = ckac.vs)) | ||
3993 | { | ||
3994 | /* This can happen simply if we 'forgot' the challenge by now, | ||
3995 | i.e. because we received the validation response twice */ | ||
3996 | GNUNET_STATISTICS_update (GST_stats, | ||
3997 | "# Validations dropped, challenge unknown", | ||
3998 | 1, | ||
3999 | GNUNET_NO); | ||
4000 | finish_cmc_handling (cmc); | ||
4001 | return; | ||
4002 | } | ||
4003 | |||
4004 | /* sanity check on origin time */ | ||
4005 | origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time); | ||
4006 | if ( (origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) || | ||
4007 | (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us) ) | ||
4008 | { | ||
4009 | GNUNET_break_op (0); | ||
4010 | finish_cmc_handling (cmc); | ||
4011 | return; | ||
4012 | } | ||
4013 | |||
4014 | { | ||
4015 | /* check signature */ | ||
4016 | struct TransportValidationPS tvp = { | ||
4017 | .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE), | ||
4018 | .purpose.size = htonl (sizeof (tvp)), | ||
4019 | .validity_duration = tvr->validity_duration, | ||
4020 | .challenge = tvr->challenge | ||
4021 | }; | ||
4022 | |||
4023 | if (GNUNET_OK != | ||
4024 | GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE, | ||
4025 | &tvp.purpose, | ||
4026 | &tvr->signature, | ||
4027 | &cmc->im.sender.public_key)) | ||
4028 | { | ||
4029 | GNUNET_break_op (0); | ||
4030 | finish_cmc_handling (cmc); | ||
4031 | return; | ||
4032 | } | ||
4033 | } | ||
4034 | |||
4035 | /* validity is capped by our willingness to keep track of the | ||
4036 | validation entry and the maximum the other peer allows */ | ||
4037 | vs->valid_until | ||
4038 | = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (tvr->validity_duration), | ||
4039 | MAX_ADDRESS_VALID_UNTIL)); | ||
4040 | vs->validated_until | ||
4041 | = GNUNET_TIME_absolute_min (vs->valid_until, | ||
4042 | GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME)); | ||
4043 | vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time); | ||
4044 | vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO; | ||
4045 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, | ||
4046 | &vs->challenge, | ||
4047 | sizeof (vs->challenge)); | ||
4048 | vs->first_challenge_use = GNUNET_TIME_absolute_subtract (vs->validated_until, | ||
4049 | GNUNET_TIME_relative_multiply (vs->validation_rtt, | ||
4050 | VALIDATION_RTT_BUFFER_FACTOR)); | ||
4051 | vs->last_challenge_use = GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */ | ||
4052 | update_next_challenge_time (vs, | ||
4053 | vs->first_challenge_use); | ||
4054 | vs->sc = GNUNET_PEERSTORE_store (peerstore, | ||
4055 | "transport", | ||
4056 | &cmc->im.sender, | ||
4057 | GNUNET_HELLO_PEERSTORE_KEY, | ||
4058 | vs->address, | ||
4059 | strlen (vs->address) + 1, | ||
4060 | vs->valid_until, | ||
4061 | GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, | ||
4062 | &peerstore_store_validation_cb, | ||
4063 | vs); | ||
4064 | // FIXME: now that we know that the address is *valid*, | ||
4065 | // do we need to trigger _using_ it for something? | ||
3863 | finish_cmc_handling (cmc); | 4066 | finish_cmc_handling (cmc); |
3864 | } | 4067 | } |
3865 | 4068 | ||
@@ -4708,54 +4911,6 @@ suggest_to_connect (const struct GNUNET_PeerIdentity *pid, | |||
4708 | 4911 | ||
4709 | 4912 | ||
4710 | /** | 4913 | /** |
4711 | * Task run periodically to validate some address based on #validation_heap. | ||
4712 | * | ||
4713 | * @param cls NULL | ||
4714 | */ | ||
4715 | static void | ||
4716 | validation_start_cb (void *cls); | ||
4717 | |||
4718 | |||
4719 | /** | ||
4720 | * Set the time for next_challenge of @a vs to @a new_time. | ||
4721 | * Updates the heap and if necessary reschedules the job. | ||
4722 | * | ||
4723 | * @param vs validation state to update | ||
4724 | * @param new_time new time for revalidation | ||
4725 | */ | ||
4726 | static void | ||
4727 | update_next_challenge_time (struct ValidationState *vs, | ||
4728 | struct GNUNET_TIME_Absolute new_time) | ||
4729 | { | ||
4730 | struct GNUNET_TIME_Relative delta; | ||
4731 | |||
4732 | if (new_time.abs_value_us == vs->next_challenge.abs_value_us) | ||
4733 | return; /* be lazy */ | ||
4734 | vs->next_challenge = new_time; | ||
4735 | if (NULL == vs->hn) | ||
4736 | vs->hn = GNUNET_CONTAINER_heap_insert (validation_heap, | ||
4737 | vs, | ||
4738 | new_time.abs_value_us); | ||
4739 | else | ||
4740 | GNUNET_CONTAINER_heap_update_cost (vs->hn, | ||
4741 | new_time.abs_value_us); | ||
4742 | if ( (vs != GNUNET_CONTAINER_heap_peek (validation_heap)) && | ||
4743 | (NULL != validation_task) ) | ||
4744 | return; | ||
4745 | if (NULL != validation_task) | ||
4746 | GNUNET_SCHEDULER_cancel (validation_task); | ||
4747 | /* randomize a bit */ | ||
4748 | delta.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
4749 | MIN_DELAY_ADDRESS_VALIDATION.rel_value_us); | ||
4750 | new_time = GNUNET_TIME_absolute_add (new_time, | ||
4751 | delta); | ||
4752 | validation_task = GNUNET_SCHEDULER_add_at (new_time, | ||
4753 | &validation_start_cb, | ||
4754 | NULL); | ||
4755 | } | ||
4756 | |||
4757 | |||
4758 | /** | ||
4759 | * The queue @a q (which matches the peer and address in @a vs) is | 4914 | * The queue @a q (which matches the peer and address in @a vs) is |
4760 | * ready for queueing. We should now queue the validation request. | 4915 | * ready for queueing. We should now queue the validation request. |
4761 | * | 4916 | * |
@@ -5468,7 +5623,7 @@ do_shutdown (void *cls) | |||
5468 | if (NULL != peerstore) | 5623 | if (NULL != peerstore) |
5469 | { | 5624 | { |
5470 | GNUNET_PEERSTORE_disconnect (peerstore, | 5625 | GNUNET_PEERSTORE_disconnect (peerstore, |
5471 | GNUNET_NO); | 5626 | GNUNET_NO); |
5472 | peerstore = NULL; | 5627 | peerstore = NULL; |
5473 | } | 5628 | } |
5474 | if (NULL != GST_stats) | 5629 | if (NULL != GST_stats) |