aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_group.c
diff options
context:
space:
mode:
authorNathan S. Evans <evans@in.tum.de>2011-02-22 15:19:49 +0000
committerNathan S. Evans <evans@in.tum.de>2011-02-22 15:19:49 +0000
commit7c0698d2296e00d9544f48819f24ed4319e3fad8 (patch)
tree343507da792d950d8d24ed11648e433bcad304a9 /src/testing/testing_group.c
parentac5cf07b590f788946d4b05f8e11b2414493f4eb (diff)
downloadgnunet-7c0698d2296e00d9544f48819f24ed4319e3fad8.tar.gz
gnunet-7c0698d2296e00d9544f48819f24ed4319e3fad8.zip
Testing and core related changes.
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r--src/testing/testing_group.c690
1 files changed, 585 insertions, 105 deletions
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c
index fc527efe3..90aad3ca2 100644
--- a/src/testing/testing_group.c
+++ b/src/testing/testing_group.c
@@ -30,7 +30,7 @@
30#include "gnunet_testing_lib.h" 30#include "gnunet_testing_lib.h"
31#include "gnunet_core_service.h" 31#include "gnunet_core_service.h"
32 32
33#define VERBOSE_TESTING GNUNET_YES 33#define VERBOSE_TESTING GNUNET_NO
34 34
35#define VERBOSE_TOPOLOGY GNUNET_YES 35#define VERBOSE_TOPOLOGY GNUNET_YES
36 36
@@ -38,6 +38,8 @@
38 38
39#define OLD 1 39#define OLD 1
40 40
41#define USE_SEND_HELLOS GNUNET_NO
42
41/** 43/**
42 * Lowest port used for GNUnet testing. Should be high enough to not 44 * Lowest port used for GNUnet testing. Should be high enough to not
43 * conflict with other applications running on the hosts but be low 45 * conflict with other applications running on the hosts but be low
@@ -159,6 +161,40 @@ struct RestartContext
159}; 161};
160 162
161 163
164struct SendHelloContext
165{
166 /**
167 * Global handle to the peer group.
168 */
169 struct GNUNET_TESTING_PeerGroup *pg;
170
171 /**
172 * The data about this specific peer.
173 */
174 struct PeerData *peer;
175
176 /**
177 * The next HELLO that needs sent to this peer.
178 */
179 struct PeerConnection *peer_pos;
180
181 /**
182 * Are we connected to CORE yet?
183 */
184 unsigned int core_ready;
185
186 /**
187 * How many attempts should we make for failed connections?
188 */
189 unsigned int connect_attempts;
190
191 /**
192 * Task for scheduling core connect requests to be sent.
193 */
194 GNUNET_SCHEDULER_TaskIdentifier core_connect_task;
195};
196
197
162struct ShutdownContext 198struct ShutdownContext
163{ 199{
164 struct GNUNET_TESTING_PeerGroup *pg; 200 struct GNUNET_TESTING_PeerGroup *pg;
@@ -599,6 +635,46 @@ struct StatsCoreContext
599 struct GNUNET_STATISTICS_GetHandle *stats_get_handle; 635 struct GNUNET_STATISTICS_GetHandle *stats_get_handle;
600}; 636};
601 637
638
639struct ConnectTopologyContext
640{
641 /**
642 * How many connections are left to create.
643 */
644 unsigned int remaining_connections;
645
646 /**
647 * Handle to group of peers.
648 */
649 struct GNUNET_TESTING_PeerGroup *pg;
650
651 /**
652 * How long to try this connection before timing out.
653 */
654 struct GNUNET_TIME_Relative connect_timeout;
655
656 /**
657 * How many times to retry connecting the two peers.
658 */
659 unsigned int connect_attempts;
660
661 /**
662 * Temp value set for each iteration.
663 */
664 //struct PeerData *first;
665
666 /**
667 * Notification that all peers are connected.
668 */
669 GNUNET_TESTING_NotifyCompletion notify_connections_done;
670
671 /**
672 * Closure for notify.
673 */
674 void *notify_cls;
675};
676
677
602/** 678/**
603 * Handle to a group of GNUnet peers. 679 * Handle to a group of GNUnet peers.
604 */ 680 */
@@ -682,6 +758,11 @@ struct GNUNET_TESTING_PeerGroup
682 unsigned int outstanding_connects; 758 unsigned int outstanding_connects;
683 759
684 /** 760 /**
761 * Number of HELLOs we have yet to send.
762 */
763 unsigned int remaining_hellos;
764
765 /**
685 * How many connects have already been scheduled? 766 * How many connects have already been scheduled?
686 */ 767 */
687 unsigned int total_connects_scheduled; 768 unsigned int total_connects_scheduled;
@@ -707,72 +788,59 @@ struct GNUNET_TESTING_PeerGroup
707 * Stop scheduling peers connecting. 788 * Stop scheduling peers connecting.
708 */ 789 */
709 unsigned int stop_connects; 790 unsigned int stop_connects;
710};
711
712struct UpdateContext
713{
714 struct GNUNET_CONFIGURATION_Handle *ret;
715 const struct GNUNET_CONFIGURATION_Handle *orig;
716 const char *hostname;
717 unsigned int nport;
718 unsigned int upnum;
719 unsigned int fdnum;
720};
721
722struct ConnectTopologyContext
723{
724 /**
725 * How many connections are left to create.
726 */
727 unsigned int remaining_connections;
728 791
729 /** 792 /**
730 * How many more connections do we need to schedule? 793 * Connection context for peer group.
731 */ 794 */
732 unsigned int remaining_connects_to_schedule; 795 struct ConnectTopologyContext ct_ctx;
796};
733 797
798struct UpdateContext
799{
734 /** 800 /**
735 * Handle to group of peers. 801 * The altered configuration.
736 */ 802 */
737 struct GNUNET_TESTING_PeerGroup *pg; 803 struct GNUNET_CONFIGURATION_Handle *ret;
738 804
739 /** 805 /**
740 * How long to try this connection before timing out. 806 * The original configuration to alter.
741 */ 807 */
742 struct GNUNET_TIME_Relative connect_timeout; 808 const struct GNUNET_CONFIGURATION_Handle *orig;
743 809
744 /** 810 /**
745 * How many times to retry connecting the two peers. 811 * The hostname that this peer will run on.
746 */ 812 */
747 unsigned int connect_attempts; 813 const char *hostname;
748 814
749 /** 815 /**
750 * Temp value set for each iteration. 816 * The next possible port to assign.
751 */ 817 */
752 //struct PeerData *first; 818 unsigned int nport;
753 819
754 /** 820 /**
755 * Notification that all peers are connected. 821 * Unique number for unix domain sockets.
756 */ 822 */
757 GNUNET_TESTING_NotifyCompletion notify_connections_done; 823 unsigned int upnum;
758 824
759 /** 825 /**
760 * Closure for notify. 826 * Unique number for this peer/host to offset
827 * things that are grouped by host.
761 */ 828 */
762 void *notify_cls; 829 unsigned int fdnum;
763}; 830};
764 831
832
765struct ConnectContext 833struct ConnectContext
766{ 834{
767 /** 835 /**
768 * Peer to connect second to. 836 * Index of peer to connect second to.
769 */ 837 */
770 struct GNUNET_TESTING_Daemon *first; 838 uint32_t first_index;
771 839
772 /** 840 /**
773 * Peer to connect first to. 841 * Index of peer to connect first to.
774 */ 842 */
775 struct GNUNET_TESTING_Daemon *second; 843 uint32_t second_index;
776 844
777 /** 845 /**
778 * Higher level topology connection context. 846 * Higher level topology connection context.
@@ -915,6 +983,10 @@ uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid)
915} 983}
916#endif 984#endif
917 985
986#if USE_SEND_HELLOS
987static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} };
988#endif
989
918/** 990/**
919 * Get a topology from a string input. 991 * Get a topology from a string input.
920 * 992 *
@@ -1102,25 +1174,34 @@ update_config (void *cls,
1102 char *per_host_variable; 1174 char *per_host_variable;
1103 unsigned long long num_per_host; 1175 unsigned long long num_per_host;
1104 1176
1177 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
1178 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
1179
1105 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival))) 1180 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
1106 { 1181 {
1107 GNUNET_asprintf (&single_variable, "single_%s_per_host", section); 1182 if ((ival != 0) &&
1108 if ((ival != 0) 1183 (GNUNET_YES !=
1109 && (GNUNET_YES !=
1110 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", 1184 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
1111 single_variable))) 1185 single_variable)))
1112 { 1186 {
1113 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); 1187 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
1114 value = cval; 1188 value = cval;
1115 } 1189 }
1116 1190 else if ((ival != 0) &&
1117 GNUNET_free (single_variable); 1191 (GNUNET_YES ==
1192 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
1193 single_variable)) &&
1194 GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing",
1195 per_host_variable,
1196 &num_per_host))
1197 {
1198 GNUNET_snprintf (cval, sizeof (cval), "%u", ival + ctx->fdnum % num_per_host);
1199 value = cval;
1200 }
1118 } 1201 }
1119 1202
1120 if (0 == strcmp (option, "UNIXPATH")) 1203 if (0 == strcmp (option, "UNIXPATH"))
1121 { 1204 {
1122 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
1123 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
1124 if (GNUNET_YES != 1205 if (GNUNET_YES !=
1125 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", 1206 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
1126 single_variable)) 1207 single_variable))
@@ -1142,15 +1223,14 @@ update_config (void *cls,
1142 section, ctx->fdnum % num_per_host); 1223 section, ctx->fdnum % num_per_host);
1143 value = uval; 1224 value = uval;
1144 } 1225 }
1145 GNUNET_free (single_variable);
1146 GNUNET_free (per_host_variable);
1147 } 1226 }
1148 1227
1149 if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) 1228 if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
1150 { 1229 {
1151 value = ctx->hostname; 1230 value = ctx->hostname;
1152 } 1231 }
1153 1232 GNUNET_free (single_variable);
1233 GNUNET_free (per_host_variable);
1154 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); 1234 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
1155} 1235}
1156 1236
@@ -1176,13 +1256,13 @@ static struct GNUNET_CONFIGURATION_Handle *
1176make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, 1256make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
1177 uint32_t off, 1257 uint32_t off,
1178 uint16_t * port, 1258 uint16_t * port,
1179 uint32_t * upnum, const char *hostname, uint32_t * fdnum) 1259 uint32_t * upnum, const char *hostname,
1260 uint32_t * fdnum)
1180{ 1261{
1181 struct UpdateContext uc; 1262 struct UpdateContext uc;
1182 uint16_t orig; 1263 uint16_t orig;
1183 char *control_host; 1264 char *control_host;
1184 char *allowed_hosts; 1265 char *allowed_hosts;
1185 unsigned long long temp_port;
1186 1266
1187 orig = *port; 1267 orig = *port;
1188 uc.nport = *port; 1268 uc.nport = *port;
@@ -1223,16 +1303,6 @@ make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
1223 GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); 1303 GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", "");
1224 GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", ""); 1304 GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", "");
1225 1305
1226
1227 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(uc.orig, "statistics", "port", &temp_port) &&
1228 (temp_port != 0) &&
1229 (GNUNET_YES !=
1230 GNUNET_CONFIGURATION_get_value_yesno (uc.orig, "testing",
1231 "single_statistics_per_host")))
1232 {
1233 GNUNET_CONFIGURATION_set_value_number (uc.ret, "statistics", "port", temp_port + off);
1234 }
1235
1236 GNUNET_free_non_null (control_host); 1306 GNUNET_free_non_null (control_host);
1237 GNUNET_free (allowed_hosts); 1307 GNUNET_free (allowed_hosts);
1238 } 1308 }
@@ -1493,9 +1563,6 @@ add_connections (struct GNUNET_TESTING_PeerGroup *pg,
1493 new_first = GNUNET_malloc (sizeof (struct PeerConnection)); 1563 new_first = GNUNET_malloc (sizeof (struct PeerConnection));
1494 new_first->index = second; 1564 new_first->index = second;
1495 GNUNET_CONTAINER_DLL_insert(*first_list, *first_tail, new_first); 1565 GNUNET_CONTAINER_DLL_insert(*first_list, *first_tail, new_first);
1496 /*
1497 new_first->next = *first_list;
1498 *first_list = new_first;*/
1499#else 1566#else
1500 GNUNET_assert (GNUNET_OK == 1567 GNUNET_assert (GNUNET_OK ==
1501 GNUNET_CONTAINER_multihashmap_put (pg-> 1568 GNUNET_CONTAINER_multihashmap_put (pg->
@@ -1516,10 +1583,6 @@ add_connections (struct GNUNET_TESTING_PeerGroup *pg,
1516 new_second = GNUNET_malloc (sizeof (struct PeerConnection)); 1583 new_second = GNUNET_malloc (sizeof (struct PeerConnection));
1517 new_second->index = first; 1584 new_second->index = first;
1518 GNUNET_CONTAINER_DLL_insert(*second_list, *second_tail, new_second); 1585 GNUNET_CONTAINER_DLL_insert(*second_list, *second_tail, new_second);
1519 /*
1520 new_second->next = *second_list;
1521 *second_list = new_second;
1522 *second_list */
1523#else 1586#else
1524 GNUNET_assert (GNUNET_OK == 1587 GNUNET_assert (GNUNET_OK ==
1525 GNUNET_CONTAINER_multihashmap_put (pg-> 1588 GNUNET_CONTAINER_multihashmap_put (pg->
@@ -2606,7 +2669,8 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
2606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2607 _("Copying file with command cp %s %s\n"), mytemp, arg); 2670 _("Copying file with command cp %s %s\n"), mytemp, arg);
2608#endif 2671#endif
2609 2672 ret = GNUNET_OS_process_wait(procarr[pg_iter]); /* FIXME: schedule this, throttle! */
2673 GNUNET_OS_process_close (procarr[pg_iter]);
2610 GNUNET_free (arg); 2674 GNUNET_free (arg);
2611 } 2675 }
2612 else /* Remote, scp the file to the correct place */ 2676 else /* Remote, scp the file to the correct place */
@@ -2895,34 +2959,403 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
2895 * 2959 *
2896 * @param ct_ctx the overall connection context 2960 * @param ct_ctx the overall connection context
2897 */ 2961 */
2898static void preschedule_connect(struct ConnectTopologyContext *ct_ctx) 2962static void preschedule_connect(struct GNUNET_TESTING_PeerGroup *pg)
2899{ 2963{
2900 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; 2964 struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx;
2901 struct PeerConnection *connection_iter; 2965 struct PeerConnection *connection_iter;
2902 struct ConnectContext *connect_context; 2966 struct ConnectContext *connect_context;
2903 uint32_t random_peer; 2967 uint32_t random_peer;
2904 2968
2905 if (ct_ctx->remaining_connects_to_schedule == 0) 2969 if (ct_ctx->remaining_connections == 0)
2906 return; 2970 return;
2907 random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); 2971 random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total);
2908 while (pg->peers[random_peer].connect_peers_head == NULL) 2972 while (pg->peers[random_peer].connect_peers_head == NULL)
2909 random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); 2973 random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total);
2910 2974
2911 connection_iter = pg->peers[random_peer].connect_peers_head; 2975 connection_iter = pg->peers[random_peer].connect_peers_head;
2912#if DEBUG_TESTING
2913 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling connection between %d and %d\n", random_peer, connection_iter->index);
2914#endif
2915 connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); 2976 connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
2916 connect_context->first = pg->peers[random_peer].daemon; 2977 connect_context->first_index = random_peer;
2917 connect_context->second = pg->peers[connection_iter->index].daemon; 2978 connect_context->second_index = connection_iter->index;
2918 connect_context->ct_ctx = ct_ctx; 2979 connect_context->ct_ctx = ct_ctx;
2919 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); 2980 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
2920 GNUNET_CONTAINER_DLL_remove(pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter); 2981 GNUNET_CONTAINER_DLL_remove(pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter);
2921 ct_ctx->remaining_connects_to_schedule--; 2982 GNUNET_free(connection_iter);
2983 ct_ctx->remaining_connections--;
2984}
2985
2986#if USE_SEND_HELLOS
2987/* Forward declaration */
2988static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
2989
2990
2991/**
2992 * Close connections and free the hello context.
2993 *
2994 * @param cls the 'struct SendHelloContext *'
2995 * @param tc scheduler context
2996 */
2997static void
2998free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2999{
3000 struct SendHelloContext *send_hello_context = cls;
3001 if (send_hello_context->peer->daemon->server != NULL)
3002 {
3003 GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server);
3004 send_hello_context->peer->daemon->server = NULL;
3005 }
3006 if (send_hello_context->peer->daemon->th != NULL)
3007 {
3008 GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th);
3009 send_hello_context->peer->daemon->th = NULL;
3010 }
3011 if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK)
3012 {
3013 GNUNET_SCHEDULER_cancel(send_hello_context->core_connect_task);
3014 send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK;
3015 }
3016 send_hello_context->pg->outstanding_connects--;
3017 GNUNET_free(send_hello_context);
3018}
3019
3020/**
3021 * For peers that haven't yet connected, notify
3022 * the caller that they have failed (timeout).
3023 *
3024 * @param cls the 'struct SendHelloContext *'
3025 * @param tc scheduler context
3026 */
3027static void
3028notify_remaining_connections_failed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3029{
3030 struct SendHelloContext *send_hello_context = cls;
3031 struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
3032 struct PeerConnection *connection;
3033
3034 GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server);
3035 send_hello_context->peer->daemon->server = NULL;
3036
3037 connection = send_hello_context->peer->connect_peers_head;
3038
3039 while (connection != NULL)
3040 {
3041 if (pg->notify_connection != NULL)
3042 {
3043 pg->notify_connection(pg->notify_connection_cls,
3044 &send_hello_context->peer->daemon->id,
3045 &pg->peers[connection->index].daemon->id,
3046 0, /* FIXME */
3047 send_hello_context->peer->daemon->cfg,
3048 pg->peers[connection->index].daemon->cfg,
3049 send_hello_context->peer->daemon,
3050 pg->peers[connection->index].daemon,
3051 "Peers failed to connect (timeout)");
3052 }
3053 GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection);
3054 GNUNET_free(connection);
3055 connection = connection->next;
3056 }
3057 GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context);
3058#if BAD
3059 other_peer = &pg->peers[connection->index];
3060#endif
2922} 3061}
2923 3062
2924 3063
2925/** 3064/**
3065 * For peers that haven't yet connected, send
3066 * CORE connect requests.
3067 *
3068 * @param cls the 'struct SendHelloContext *'
3069 * @param tc scheduler context
3070 */
3071static void
3072send_core_connect_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3073{
3074 struct SendHelloContext *send_hello_context = cls;
3075 struct PeerConnection *conn;
3076 GNUNET_assert(send_hello_context->peer->daemon->server != NULL);
3077
3078 send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK;
3079
3080 send_hello_context->connect_attempts++;
3081 if (send_hello_context->connect_attempts < send_hello_context->pg->ct_ctx.connect_attempts)
3082 {
3083 conn = send_hello_context->peer->connect_peers_head;
3084 while (conn != NULL)
3085 {
3086 GNUNET_CORE_peer_request_connect(send_hello_context->peer->daemon->server,
3087 GNUNET_TIME_relative_get_forever(),
3088 &send_hello_context->pg->peers[conn->index].daemon->id,
3089 NULL,
3090 NULL);
3091 conn = conn->next;
3092 }
3093 send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts) ,
3094 &send_core_connect_requests,
3095 send_hello_context);
3096 }
3097 else
3098 {
3099 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Timeout before all connections created, marking rest as failed!\n");
3100 GNUNET_SCHEDULER_add_now(&notify_remaining_connections_failed, send_hello_context);
3101 }
3102
3103}
3104
3105
3106/**
3107 * Success, connection is up. Signal client our success.
3108 *
3109 * @param cls our "struct SendHelloContext"
3110 * @param peer identity of the peer that has connected
3111 * @param atsi performance information
3112 *
3113 * FIXME: remove peers from BOTH lists, call notify twice, should
3114 * double the speed of connections as long as the list iteration
3115 * doesn't take too long!
3116 */
3117static void
3118core_connect_notify (void *cls,
3119 const struct GNUNET_PeerIdentity *peer,
3120 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
3121{
3122 struct SendHelloContext *send_hello_context = cls;
3123 struct PeerConnection *connection;
3124 struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
3125#if BAD
3126 struct PeerData *other_peer;
3127#endif
3128#if DEBUG_TESTING
3129 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3130 "Connected peer %s to peer %s\n",
3131 ctx->d1->shortname, GNUNET_i2s(peer));
3132#endif
3133
3134 if (0 == memcmp(&send_hello_context->peer->daemon->id, peer, sizeof(struct GNUNET_PeerIdentity)))
3135 return;
3136
3137 connection = send_hello_context->peer->connect_peers_head;
3138#if BAD
3139 other_peer = NULL;
3140#endif
3141
3142 while ((connection != NULL) &&
3143 (0 != memcmp(&pg->peers[connection->index].daemon->id, peer, sizeof(struct GNUNET_PeerIdentity))))
3144 {
3145 connection = connection->next;
3146 }
3147
3148 if (connection == NULL)
3149 {
3150 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Connected peer %s to %s, not in list (no problem(?))\n", GNUNET_i2s(peer), send_hello_context->peer->daemon->shortname);
3151 }
3152 else
3153 {
3154#if BAD
3155 other_peer = &pg->peers[connection->index];
3156#endif
3157 if (pg->notify_connection != NULL)
3158 {
3159 pg->notify_connection(pg->notify_connection_cls,
3160 &send_hello_context->peer->daemon->id,
3161 peer,
3162 0, /* FIXME */
3163 send_hello_context->peer->daemon->cfg,
3164 pg->peers[connection->index].daemon->cfg,
3165 send_hello_context->peer->daemon,
3166 pg->peers[connection->index].daemon,
3167 NULL);
3168 }
3169 GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection);
3170 GNUNET_free(connection);
3171 }
3172
3173#if BAD
3174 /* Notify of reverse connection and remove from other peers list of outstanding */
3175 if (other_peer != NULL)
3176 {
3177 connection = other_peer->connect_peers_head;
3178 while ((connection != NULL) &&
3179 (0 != memcmp(&send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, sizeof(struct GNUNET_PeerIdentity))))
3180 {
3181 connection = connection->next;
3182 }
3183 if (connection != NULL)
3184 {
3185 if (pg->notify_connection != NULL)
3186 {
3187 pg->notify_connection(pg->notify_connection_cls,
3188 peer,
3189 &send_hello_context->peer->daemon->id,
3190 0, /* FIXME */
3191 pg->peers[connection->index].daemon->cfg,
3192 send_hello_context->peer->daemon->cfg,
3193 pg->peers[connection->index].daemon,
3194 send_hello_context->peer->daemon,
3195 NULL);
3196 }
3197
3198 GNUNET_CONTAINER_DLL_remove(other_peer->connect_peers_head, other_peer->connect_peers_tail, connection);
3199 GNUNET_free(connection);
3200 }
3201 }
3202#endif
3203
3204 if (send_hello_context->peer->connect_peers_head == NULL)
3205 {
3206 GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context);
3207 }
3208}
3209
3210/**
3211 * Notify of a successful connection to the core service.
3212 *
3213 * @param cls a struct SendHelloContext *
3214 * @param server handle to the core service
3215 * @param my_identity the peer identity of this peer
3216 * @param publicKey the public key of the peer
3217 */
3218void
3219core_init (void *cls,
3220 struct GNUNET_CORE_Handle * server,
3221 const struct GNUNET_PeerIdentity *
3222 my_identity,
3223 const struct
3224 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
3225 publicKey)
3226{
3227 struct SendHelloContext *send_hello_context = cls;
3228 send_hello_context->core_ready = GNUNET_YES;
3229}
3230
3231
3232/**
3233 * Function called once a hello has been sent
3234 * to the transport, move on to the next one
3235 * or go away forever.
3236 *
3237 * @param cls the 'struct SendHelloContext *'
3238 * @param tc scheduler context
3239 */
3240static void
3241hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3242{
3243 struct SendHelloContext *send_hello_context = cls;
3244 //unsigned int pg_iter;
3245 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3246 {
3247 GNUNET_free(send_hello_context);
3248 return;
3249 }
3250
3251 send_hello_context->pg->remaining_hellos--;
3252#if DEBUG_TESTING
3253 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sent HELLO, have %d remaining!\n", send_hello_context->pg->remaining_hellos);
3254#endif
3255 if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */
3256 {
3257#if DEBUG_TESTING
3258 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All hellos for this peer sent, disconnecting transport!\n");
3259#endif
3260 GNUNET_assert(send_hello_context->peer->daemon->th != NULL);
3261 GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th);
3262 send_hello_context->peer->daemon->th = NULL;
3263
3264 /*if (send_hello_context->pg->remaining_hellos == 0)
3265 {
3266 for (pg_iter = 0; pg_iter < send_hello_context->pg->max_outstanding_connections; pg_iter++)
3267 {
3268 preschedule_connect(&send_hello_context->pg->ct_ctx);
3269 }
3270 }
3271 */
3272 GNUNET_assert (send_hello_context->peer->daemon->server == NULL);
3273 send_hello_context->peer->daemon->server = GNUNET_CORE_connect(send_hello_context->peer->cfg,
3274 1,
3275 send_hello_context,
3276 &core_init,
3277 &core_connect_notify,
3278 NULL,
3279 NULL,
3280 NULL, GNUNET_NO,
3281 NULL, GNUNET_NO,
3282 no_handlers);
3283
3284 send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts),
3285 &send_core_connect_requests,
3286 send_hello_context);
3287 }
3288 else
3289 GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context);
3290}
3291
3292
3293/**
3294 * Connect to a peer, give it all the HELLO's of those peers
3295 * we will later ask it to connect to.
3296 *
3297 * @param ct_ctx the overall connection context
3298 */
3299static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3300{
3301 struct SendHelloContext *send_hello_context = cls;
3302 struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg;
3303
3304 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3305 {
3306 GNUNET_free(send_hello_context);
3307 return;
3308 }
3309
3310 GNUNET_assert(send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */
3311
3312 if (((send_hello_context->peer->daemon->th == NULL) &&
3313 (pg->outstanding_connects > pg->max_outstanding_connections)) ||
3314 (pg->stop_connects == GNUNET_YES))
3315 {
3316#if VERBOSE_TESTING > 2
3317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3318 _
3319 ("Delaying connect, we have too many outstanding connections!\n"));
3320#endif
3321 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3322 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
3323 &schedule_send_hellos, send_hello_context);
3324 }
3325 else
3326 {
3327#if VERBOSE_TESTING > 2
3328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3329 _("Creating connection, outstanding_connections is %d\n"),
3330 outstanding_connects);
3331#endif
3332 if (send_hello_context->peer->daemon->th == NULL)
3333 {
3334 pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */
3335 send_hello_context->peer->daemon->th = GNUNET_TRANSPORT_connect(send_hello_context->peer->cfg,
3336 NULL,
3337 send_hello_context,
3338 NULL,
3339 NULL,
3340 NULL);
3341 }
3342#if DEBUG_TESTING
3343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3344 _("Offering Hello of peer %s to peer %s\n"),
3345 send_hello_context->peer->daemon->shortname, pg->peers[send_hello_context->peer_pos->index].daemon->shortname);
3346#endif
3347 GNUNET_TRANSPORT_offer_hello(send_hello_context->peer->daemon->th,
3348 (const struct GNUNET_MessageHeader *)pg->peers[send_hello_context->peer_pos->index].daemon->hello,
3349 &hello_sent_callback,
3350 send_hello_context);
3351 send_hello_context->peer_pos = send_hello_context->peer_pos->next;
3352 GNUNET_assert(send_hello_context->peer->daemon->th != NULL);
3353 }
3354}
3355#endif
3356
3357
3358/**
2926 * Internal notification of a connection, kept so that we can ensure some connections 3359 * Internal notification of a connection, kept so that we can ensure some connections
2927 * happen instead of flooding all testing daemons with requests to connect. 3360 * happen instead of flooding all testing daemons with requests to connect.
2928 */ 3361 */
@@ -2937,23 +3370,54 @@ internal_connect_notify (void *cls,
2937 struct GNUNET_TESTING_Daemon *second_daemon, 3370 struct GNUNET_TESTING_Daemon *second_daemon,
2938 const char *emsg) 3371 const char *emsg)
2939{ 3372{
2940 struct ConnectTopologyContext *ct_ctx = cls; 3373 struct ConnectContext *connect_ctx = cls;
3374 struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx;
2941 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; 3375 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
3376 struct PeerConnection *connection;
2942 pg->outstanding_connects--; 3377 pg->outstanding_connects--;
2943 ct_ctx->remaining_connections--; 3378
3379 /*
3380 * Check whether the inverse connection has been scheduled yet,
3381 * if not, we can remove it from the other peers list and avoid
3382 * even trying to connect them again!
3383 */
3384 connection = pg->peers[connect_ctx->second_index].connect_peers_head;
3385#if BAD
3386 other_peer = NULL;
3387#endif
3388
3389 while ((connection != NULL) &&
3390 (0 != memcmp(first, &pg->peers[connection->index].daemon->id, sizeof(struct GNUNET_PeerIdentity))))
3391 {
3392 connection = connection->next;
3393 }
3394
3395 if (connection != NULL) /* Can safely remove! */
3396 {
3397 ct_ctx->remaining_connections--;
3398 if (pg->notify_connection != NULL) /* Notify of reverse connection */
3399 pg->notify_connection (pg->notify_connection_cls, second, first, distance,
3400 second_cfg, first_cfg, second_daemon, first_daemon,
3401 emsg);
3402
3403 GNUNET_CONTAINER_DLL_remove(pg->peers[connect_ctx->second_index].connect_peers_head, pg->peers[connect_ctx->second_index].connect_peers_tail, connection);
3404 GNUNET_free(connection);
3405 }
3406
2944 if (ct_ctx->remaining_connections == 0) 3407 if (ct_ctx->remaining_connections == 0)
2945 { 3408 {
2946 if (ct_ctx->notify_connections_done != NULL) 3409 if (ct_ctx->notify_connections_done != NULL)
2947 ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); 3410 ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL);
2948 GNUNET_free (ct_ctx);
2949 } 3411 }
2950 else 3412 else
2951 preschedule_connect(ct_ctx); 3413 preschedule_connect(pg);
2952 3414
2953 if (pg->notify_connection != NULL) 3415 if (pg->notify_connection != NULL)
2954 pg->notify_connection (pg->notify_connection_cls, first, second, distance, 3416 pg->notify_connection (pg->notify_connection_cls, first, second, distance,
2955 first_cfg, second_cfg, first_daemon, second_daemon, 3417 first_cfg, second_cfg, first_daemon, second_daemon,
2956 emsg); 3418 emsg);
3419
3420 GNUNET_free(connect_ctx);
2957} 3421}
2958 3422
2959 3423
@@ -2975,8 +3439,8 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2975 3439
2976 if ((pg->outstanding_connects > pg->max_outstanding_connections) || (pg->stop_connects == GNUNET_YES)) 3440 if ((pg->outstanding_connects > pg->max_outstanding_connections) || (pg->stop_connects == GNUNET_YES))
2977 { 3441 {
2978#if VERBOSE_TESTING > 2 3442#if VERBOSE_TESTING
2979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3443 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2980 _ 3444 _
2981 ("Delaying connect, we have too many outstanding connections!\n")); 3445 ("Delaying connect, we have too many outstanding connections!\n"));
2982#endif 3446#endif
@@ -2986,20 +3450,24 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2986 } 3450 }
2987 else 3451 else
2988 { 3452 {
2989#if VERBOSE_TESTING > 2 3453#if VERBOSE_TESTING
2990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3454 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2991 _("Creating connection, outstanding_connections is %d\n"), 3455 _("Creating connection, outstanding_connections is %d (max %d)\n"),
2992 outstanding_connects); 3456 pg->outstanding_connects, pg->max_outstanding_connections);
2993#endif 3457#endif
2994 pg->outstanding_connects++; 3458 pg->outstanding_connects++;
2995 pg->total_connects_scheduled++; 3459 pg->total_connects_scheduled++;
2996 GNUNET_TESTING_daemons_connect (connect_context->first, 3460 GNUNET_TESTING_daemons_connect (pg->peers[connect_context->first_index].daemon,
2997 connect_context->second, 3461 pg->peers[connect_context->second_index].daemon,
2998 connect_context->ct_ctx->connect_timeout, 3462 connect_context->ct_ctx->connect_timeout,
2999 connect_context->ct_ctx->connect_attempts, 3463 connect_context->ct_ctx->connect_attempts,
3464#if USE_SEND_HELLOS
3465 GNUNET_NO,
3466#else
3467 GNUNET_YES,
3468#endif
3000 &internal_connect_notify, 3469 &internal_connect_notify,
3001 connect_context->ct_ctx); 3470 connect_context); /* FIXME: free connect context! */
3002 GNUNET_free (connect_context);
3003 } 3471 }
3004} 3472}
3005 3473
@@ -3123,16 +3591,18 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3123{ 3591{
3124 unsigned int pg_iter; 3592 unsigned int pg_iter;
3125 unsigned int total; 3593 unsigned int total;
3126 struct ConnectTopologyContext *ct_ctx; 3594
3127#if OLD 3595#if OLD
3128 struct PeerConnection *connection_iter; 3596 struct PeerConnection *connection_iter;
3129#endif 3597#endif
3598#if USE_SEND_HELLOS
3599 struct SendHelloContext *send_hello_context
3600#endif
3130 3601
3131 total = 0; 3602 total = 0;
3132 ct_ctx = GNUNET_malloc (sizeof (struct ConnectTopologyContext)); 3603 pg->ct_ctx.notify_connections_done = notify_callback;
3133 ct_ctx->notify_connections_done = notify_callback; 3604 pg->ct_ctx.notify_cls = notify_cls;
3134 ct_ctx->notify_cls = notify_cls; 3605 pg->ct_ctx.pg = pg;
3135 ct_ctx->pg = pg;
3136 3606
3137 for (pg_iter = 0; pg_iter < pg->total; pg_iter++) 3607 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3138 { 3608 {
@@ -3150,19 +3620,29 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3150 } 3620 }
3151 3621
3152 if (total == 0) 3622 if (total == 0)
3623 return total;
3624
3625 pg->ct_ctx.connect_timeout = connect_timeout;
3626 pg->ct_ctx.connect_attempts = connect_attempts;
3627 pg->ct_ctx.remaining_connections = total;
3628
3629#if USE_SEND_HELLOS
3630 /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */
3631 pg->remaining_hellos = total;
3632 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3153 { 3633 {
3154 GNUNET_free (ct_ctx); 3634 send_hello_context = GNUNET_malloc(sizeof(struct SendHelloContext));
3155 return total; 3635 send_hello_context->peer = &pg->peers[pg_iter];
3636 send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head;
3637 send_hello_context->pg = pg;
3638 GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context);
3156 } 3639 }
3157 ct_ctx->connect_timeout = connect_timeout; 3640#else
3158 ct_ctx->connect_attempts = connect_attempts;
3159 ct_ctx->remaining_connections = total;
3160 ct_ctx->remaining_connects_to_schedule = total;
3161
3162 for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) 3641 for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++)
3163 { 3642 {
3164 preschedule_connect(ct_ctx); 3643 preschedule_connect(pg);
3165 } 3644 }
3645#endif
3166 return total; 3646 return total;
3167 3647
3168} 3648}