diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-04-30 14:50:06 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-04-30 14:50:06 +0000 |
commit | 5f9efe3ff20656b7900fc0b503f3e0cbe75eb20a (patch) | |
tree | a6f379dfd9dafc1db1fa95260ab7029f15a9b283 /src/dv/gnunet-service-dv.c | |
parent | e6b08db0728b172da76392967661c09e7bfdbb55 (diff) | |
download | gnunet-5f9efe3ff20656b7900fc0b503f3e0cbe75eb20a.tar.gz gnunet-5f9efe3ff20656b7900fc0b503f3e0cbe75eb20a.zip |
dv changes. add propagation of disconnect messages, dv updates on peer direct connections. Result of those two changes should be a much better learned topology for all peers. This was periodic gossip is really only to stop timeouts from removing peers. Also changed dv_api to wait for message queuing by dv service before calling transport transmit continuation, so that addresses that are no longer available can be caught by transport service. Perhaps some other stuff I have forgotten about. Should be kinda sorta working, need to make better testcases and do more debugging as errors inevitably pop up
Diffstat (limited to 'src/dv/gnunet-service-dv.c')
-rw-r--r-- | src/dv/gnunet-service-dv.c | 613 |
1 files changed, 536 insertions, 77 deletions
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c index f956e4cb0..dc92bfa37 100644 --- a/src/dv/gnunet-service-dv.c +++ b/src/dv/gnunet-service-dv.c | |||
@@ -73,12 +73,12 @@ static struct GNUNET_SCHEDULER_Handle *sched; | |||
73 | * How often do we check about sending out more peer information (if | 73 | * How often do we check about sending out more peer information (if |
74 | * we are connected to no peers previously). | 74 | * we are connected to no peers previously). |
75 | */ | 75 | */ |
76 | #define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500) | 76 | #define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50000) |
77 | 77 | ||
78 | /** | 78 | /** |
79 | * How long do we wait at most between sending out information? | 79 | * How long do we wait at most between sending out information? |
80 | */ | 80 | */ |
81 | #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500) | 81 | #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50000) |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * How long can we have not heard from a peer and | 84 | * How long can we have not heard from a peer and |
@@ -113,7 +113,23 @@ static struct GNUNET_SCHEDULER_Handle *sched; | |||
113 | #define DIRECT_NEIGHBOR_COST 1 | 113 | #define DIRECT_NEIGHBOR_COST 1 |
114 | 114 | ||
115 | /** | 115 | /** |
116 | * The client, should be the DV plugin connected to us. Hopefully | 116 | * The default number of direct connections to store in DV (max) |
117 | */ | ||
118 | #define DEFAULT_DIRECT_CONNECTIONS 50 | ||
119 | |||
120 | /** | ||
121 | * The default size of direct + extended peers in DV (max) | ||
122 | */ | ||
123 | #define DEFAULT_DV_SIZE 100 | ||
124 | |||
125 | /** | ||
126 | * The default fisheye depth, from how many hops away will | ||
127 | * we keep peers? | ||
128 | */ | ||
129 | #define DEFAULT_FISHEYE_DEPTH 4 | ||
130 | |||
131 | /** | ||
132 | * The client, the DV plugin connected to us. Hopefully | ||
117 | * this client will never change, although if the plugin dies | 133 | * this client will never change, although if the plugin dies |
118 | * and returns for some reason it may happen. | 134 | * and returns for some reason it may happen. |
119 | */ | 135 | */ |
@@ -134,10 +150,6 @@ GNUNET_SCHEDULER_TaskIdentifier gossip_task; | |||
134 | */ | 150 | */ |
135 | struct DistantNeighbor *referees; | 151 | struct DistantNeighbor *referees; |
136 | 152 | ||
137 | static struct GNUNET_TIME_Relative client_transmit_timeout; | ||
138 | |||
139 | static struct GNUNET_TIME_Relative default_dv_delay; | ||
140 | |||
141 | static size_t default_dv_priority = 0; | 153 | static size_t default_dv_priority = 0; |
142 | 154 | ||
143 | 155 | ||
@@ -156,6 +168,7 @@ struct PendingMessage | |||
156 | */ | 168 | */ |
157 | struct PendingMessage *prev; | 169 | struct PendingMessage *prev; |
158 | 170 | ||
171 | struct GNUNET_DV_SendResultMessage *send_result; | ||
159 | /** | 172 | /** |
160 | * Actual message to be sent; // avoid allocation | 173 | * Actual message to be sent; // avoid allocation |
161 | */ | 174 | */ |
@@ -199,6 +212,24 @@ struct PendingMessage *core_pending_head; | |||
199 | struct PendingMessage *core_pending_tail; | 212 | struct PendingMessage *core_pending_tail; |
200 | 213 | ||
201 | 214 | ||
215 | struct FastGossipNeighborList | ||
216 | { | ||
217 | /** | ||
218 | * Next element of DLL | ||
219 | */ | ||
220 | struct FastGossipNeighborList *next; | ||
221 | |||
222 | /** | ||
223 | * Prev element of DLL | ||
224 | */ | ||
225 | struct FastGossipNeighborList *prev; | ||
226 | |||
227 | /** | ||
228 | * The neighbor to gossip about | ||
229 | */ | ||
230 | struct DistantNeighbor *about; | ||
231 | }; | ||
232 | |||
202 | /** | 233 | /** |
203 | * Context created whenever a direct peer connects to us, | 234 | * Context created whenever a direct peer connects to us, |
204 | * used to gossip other peers to it. | 235 | * used to gossip other peers to it. |
@@ -211,14 +242,23 @@ struct NeighborSendContext | |||
211 | struct DirectNeighbor *toNeighbor; | 242 | struct DirectNeighbor *toNeighbor; |
212 | 243 | ||
213 | /** | 244 | /** |
214 | * The timeout for this task. | 245 | * The task associated with this context. |
215 | */ | 246 | */ |
216 | struct GNUNET_TIME_Relative timeout; | 247 | GNUNET_SCHEDULER_TaskIdentifier task; |
217 | 248 | ||
218 | /** | 249 | /** |
219 | * The task associated with this context. | 250 | * Head of DLL of peers to gossip about |
251 | * as fast as possible to this peer, for initial | ||
252 | * set up. | ||
220 | */ | 253 | */ |
221 | GNUNET_SCHEDULER_TaskIdentifier task; | 254 | struct FastGossipNeighborList *fast_gossip_list_head; |
255 | |||
256 | /** | ||
257 | * Tail of DLL of peers to gossip about | ||
258 | * as fast as possible to this peer, for initial | ||
259 | * set up. | ||
260 | */ | ||
261 | struct FastGossipNeighborList *fast_gossip_list_tail; | ||
222 | 262 | ||
223 | }; | 263 | }; |
224 | 264 | ||
@@ -415,6 +455,12 @@ struct DV_SendContext | |||
415 | struct GNUNET_MessageHeader *message; | 455 | struct GNUNET_MessageHeader *message; |
416 | 456 | ||
417 | /** | 457 | /** |
458 | * The pre-built send result message. Simply needs to be queued | ||
459 | * and freed once send has been called! | ||
460 | */ | ||
461 | struct GNUNET_DV_SendResultMessage *send_result; | ||
462 | |||
463 | /** | ||
418 | * The size of the message being sent, may be larger | 464 | * The size of the message being sent, may be larger |
419 | * than message->header.size because it's multiple | 465 | * than message->header.size because it's multiple |
420 | * messages packed into one! | 466 | * messages packed into one! |
@@ -482,6 +528,18 @@ struct FindDestinationContext | |||
482 | struct DistantNeighbor *dest; | 528 | struct DistantNeighbor *dest; |
483 | }; | 529 | }; |
484 | 530 | ||
531 | struct DisconnectContext | ||
532 | { | ||
533 | /** | ||
534 | * Distant neighbor to get pid from. | ||
535 | */ | ||
536 | struct DistantNeighbor *distant; | ||
537 | |||
538 | /** | ||
539 | * Direct neighbor that disconnected. | ||
540 | */ | ||
541 | struct DirectNeighbor *direct; | ||
542 | }; | ||
485 | 543 | ||
486 | /** | 544 | /** |
487 | * We've been given a target ID based on the random numbers that | 545 | * We've been given a target ID based on the random numbers that |
@@ -503,6 +561,28 @@ find_destination (void *cls, | |||
503 | } | 561 | } |
504 | 562 | ||
505 | /** | 563 | /** |
564 | * Find a distant peer whose referrer_id matches what we're | ||
565 | * looking for. For looking up a peer we've gossipped about | ||
566 | * but is now disconnected. Need to do this because we don't | ||
567 | * want to remove those that may be accessible via a different | ||
568 | * route. | ||
569 | */ | ||
570 | static int find_distant_peer (void *cls, | ||
571 | const GNUNET_HashCode * key, | ||
572 | void *value) | ||
573 | { | ||
574 | struct FindDestinationContext *fdc = cls; | ||
575 | struct DistantNeighbor *distant = value; | ||
576 | |||
577 | if (fdc->tid == distant->referrer_id) | ||
578 | { | ||
579 | fdc->dest = distant; | ||
580 | return GNUNET_NO; | ||
581 | } | ||
582 | return GNUNET_YES; | ||
583 | } | ||
584 | |||
585 | /** | ||
506 | * Function called to notify a client about the socket | 586 | * Function called to notify a client about the socket |
507 | * begin ready to queue more data. "buf" will be | 587 | * begin ready to queue more data. "buf" will be |
508 | * NULL and "size" zero if the socket was closed for | 588 | * NULL and "size" zero if the socket was closed for |
@@ -554,7 +634,16 @@ size_t transmit_to_plugin (void *cls, | |||
554 | return off; | 634 | return off; |
555 | } | 635 | } |
556 | 636 | ||
557 | 637 | /** | |
638 | * Send a message to the dv plugin. | ||
639 | * | ||
640 | * @param sender the direct sender of the message | ||
641 | * @param message the message to send to the plugin | ||
642 | * (may be an encapsulated type) | ||
643 | * @param message_size the size of the message to be sent | ||
644 | * @param distant_neighbor the original sender of the message | ||
645 | * @param cost the cost to the original sender of the message | ||
646 | */ | ||
558 | void send_to_plugin(const struct GNUNET_PeerIdentity * sender, | 647 | void send_to_plugin(const struct GNUNET_PeerIdentity * sender, |
559 | const struct GNUNET_MessageHeader *message, | 648 | const struct GNUNET_MessageHeader *message, |
560 | size_t message_size, | 649 | size_t message_size, |
@@ -643,7 +732,7 @@ void send_to_plugin(const struct GNUNET_PeerIdentity * sender, | |||
643 | 732 | ||
644 | /** | 733 | /** |
645 | * Function called to notify a client about the socket | 734 | * Function called to notify a client about the socket |
646 | * begin ready to queue more data. "buf" will be | 735 | * being ready to queue more data. "buf" will be |
647 | * NULL and "size" zero if the socket was closed for | 736 | * NULL and "size" zero if the socket was closed for |
648 | * writing in the meantime. | 737 | * writing in the meantime. |
649 | * | 738 | * |
@@ -657,6 +746,7 @@ size_t core_transmit_notify (void *cls, | |||
657 | { | 746 | { |
658 | char *cbuf = buf; | 747 | char *cbuf = buf; |
659 | struct PendingMessage *reply; | 748 | struct PendingMessage *reply; |
749 | struct PendingMessage *client_reply; | ||
660 | size_t off; | 750 | size_t off; |
661 | size_t msize; | 751 | size_t msize; |
662 | 752 | ||
@@ -680,6 +770,30 @@ size_t core_transmit_notify (void *cls, | |||
680 | GNUNET_CONTAINER_DLL_remove (core_pending_head, | 770 | GNUNET_CONTAINER_DLL_remove (core_pending_head, |
681 | core_pending_tail, | 771 | core_pending_tail, |
682 | reply); | 772 | reply); |
773 | if (reply->send_result != NULL) /* Will only be non-null if a real client asked for this send */ | ||
774 | { | ||
775 | client_reply = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(struct GNUNET_DV_SendResultMessage)); | ||
776 | client_reply->msg = (struct GNUNET_MessageHeader *)&client_reply[1]; | ||
777 | memcpy(&client_reply[1], reply->send_result, sizeof(struct GNUNET_DV_SendResultMessage)); | ||
778 | GNUNET_free(reply->send_result); | ||
779 | |||
780 | GNUNET_CONTAINER_DLL_insert_after(plugin_pending_head, plugin_pending_tail, plugin_pending_tail, client_reply); | ||
781 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Queued client send receipt success message!\n"); | ||
782 | if (client_handle != NULL) | ||
783 | { | ||
784 | if (plugin_transmit_handle == NULL) | ||
785 | { | ||
786 | plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, | ||
787 | sizeof(struct GNUNET_DV_SendResultMessage), | ||
788 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
789 | &transmit_to_plugin, NULL); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n"); | ||
794 | } | ||
795 | } | ||
796 | } | ||
683 | memcpy (&cbuf[off], reply->msg, msize); | 797 | memcpy (&cbuf[off], reply->msg, msize); |
684 | GNUNET_free (reply); | 798 | GNUNET_free (reply); |
685 | off += msize; | 799 | off += msize; |
@@ -742,6 +856,7 @@ send_message_via (const struct GNUNET_PeerIdentity * sender, | |||
742 | cost = specific_neighbor->cost; | 856 | cost = specific_neighbor->cost; |
743 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size); | 857 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size); |
744 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; | 858 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; |
859 | pending_message->send_result = send_context->send_result; | ||
745 | toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg; | 860 | toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg; |
746 | toSend->header.size = htons (msg_size); | 861 | toSend->header.size = htons (msg_size); |
747 | toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); | 862 | toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); |
@@ -829,6 +944,7 @@ send_message (const struct GNUNET_PeerIdentity * recipient, | |||
829 | cost = target->cost; | 944 | cost = target->cost; |
830 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size); | 945 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size); |
831 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; | 946 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; |
947 | pending_message->send_result = NULL; | ||
832 | toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg; | 948 | toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg; |
833 | toSend->header.size = htons (msg_size); | 949 | toSend->header.size = htons (msg_size); |
834 | toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); | 950 | toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); |
@@ -994,7 +1110,7 @@ static int handle_dv_data_message (void *cls, | |||
994 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1110 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
995 | "%s: Sends message size %d on!\n", "dv", packed_message_size); | 1111 | "%s: Sends message size %d on!\n", "dv", packed_message_size); |
996 | #endif | 1112 | #endif |
997 | ret = send_message(&destination, &original_sender, NULL, packed_message, packed_message_size, default_dv_priority, default_dv_delay); | 1113 | ret = send_message(&destination, &original_sender, NULL, packed_message, packed_message_size, default_dv_priority, GNUNET_TIME_relative_get_forever()); |
998 | 1114 | ||
999 | if (ret != GNUNET_SYSERR) | 1115 | if (ret != GNUNET_SYSERR) |
1000 | return GNUNET_OK; | 1116 | return GNUNET_OK; |
@@ -1012,15 +1128,13 @@ neighbor_send_task (void *cls, | |||
1012 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 1128 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
1013 | { | 1129 | { |
1014 | struct NeighborSendContext *send_context = cls; | 1130 | struct NeighborSendContext *send_context = cls; |
1015 | #if DEBUG_DV_GOSSIP | 1131 | #if DEBUG_DV_GOSSIP_SEND |
1016 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1017 | "%s: Entering neighbor_send_task...\n", | ||
1018 | GNUNET_i2s(&my_identity)); | ||
1019 | char * encPeerAbout; | 1132 | char * encPeerAbout; |
1020 | char * encPeerTo; | 1133 | char * encPeerTo; |
1021 | #endif | 1134 | #endif |
1022 | struct DistantNeighbor *about; | 1135 | struct DistantNeighbor *about; |
1023 | struct DirectNeighbor *to; | 1136 | struct DirectNeighbor *to; |
1137 | struct FastGossipNeighborList *about_list; | ||
1024 | 1138 | ||
1025 | p2p_dv_MESSAGE_NeighborInfo *message; | 1139 | p2p_dv_MESSAGE_NeighborInfo *message; |
1026 | struct PendingMessage *pending_message; | 1140 | struct PendingMessage *pending_message; |
@@ -1032,23 +1146,33 @@ neighbor_send_task (void *cls, | |||
1032 | "%s: Called with reason shutdown, shutting down!\n", | 1146 | "%s: Called with reason shutdown, shutting down!\n", |
1033 | GNUNET_i2s(&my_identity)); | 1147 | GNUNET_i2s(&my_identity)); |
1034 | #endif | 1148 | #endif |
1035 | send_context->toNeighbor->send_context = NULL; | 1149 | send_context->task = GNUNET_SCHEDULER_NO_TASK; |
1036 | GNUNET_free(send_context); | ||
1037 | return; | 1150 | return; |
1038 | } | 1151 | } |
1039 | 1152 | ||
1040 | 1153 | if (send_context->fast_gossip_list_head != NULL) | |
1041 | /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means | 1154 | { |
1042 | * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default | 1155 | about_list = send_context->fast_gossip_list_head; |
1043 | * values for all connected peers) there may be a serious bias as to which peers get gossiped about! | 1156 | about = send_context->fast_gossip_list_head->about; |
1044 | * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as | 1157 | GNUNET_CONTAINER_DLL_remove(send_context->fast_gossip_list_head, |
1045 | * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk | 1158 | send_context->fast_gossip_list_tail, |
1046 | * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap | 1159 | about_list); |
1047 | * once to get a list of peers to gossip about and gossip them over time... But then if one goes away | 1160 | GNUNET_free(about_list); |
1048 | * in the mean time that becomes nasty. For now we'll just assume that the walking is done | 1161 | } |
1049 | * asynchronously enough to avoid major problems (-; | 1162 | else |
1050 | */ | 1163 | { |
1051 | about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap); | 1164 | /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means |
1165 | * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default | ||
1166 | * values for all connected peers) there may be a serious bias as to which peers get gossiped about! | ||
1167 | * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as | ||
1168 | * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk | ||
1169 | * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap | ||
1170 | * once to get a list of peers to gossip about and gossip them over time... But then if one goes away | ||
1171 | * in the mean time that becomes nasty. For now we'll just assume that the walking is done | ||
1172 | * asynchronously enough to avoid major problems (-; | ||
1173 | */ | ||
1174 | about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap); | ||
1175 | } | ||
1052 | to = send_context->toNeighbor; | 1176 | to = send_context->toNeighbor; |
1053 | 1177 | ||
1054 | if ((about != NULL) && (to != about->referrer /* split horizon */ ) && | 1178 | if ((about != NULL) && (to != about->referrer /* split horizon */ ) && |
@@ -1060,10 +1184,10 @@ neighbor_send_task (void *cls, | |||
1060 | &to->identity, sizeof (struct GNUNET_PeerIdentity))) && | 1184 | &to->identity, sizeof (struct GNUNET_PeerIdentity))) && |
1061 | (about->pkey != NULL)) | 1185 | (about->pkey != NULL)) |
1062 | { | 1186 | { |
1063 | #if DEBUG_DV_GOSSIP | 1187 | #if DEBUG_DV_GOSSIP_SEND |
1064 | encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity)); | 1188 | encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity)); |
1065 | encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity)); | 1189 | encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity)); |
1066 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1190 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1067 | "%s: Sending info about peer %s to directly connected peer %s\n", | 1191 | "%s: Sending info about peer %s to directly connected peer %s\n", |
1068 | GNUNET_i2s(&my_identity), | 1192 | GNUNET_i2s(&my_identity), |
1069 | encPeerAbout, encPeerTo); | 1193 | encPeerAbout, encPeerTo); |
@@ -1088,11 +1212,21 @@ neighbor_send_task (void *cls, | |||
1088 | pending_message); | 1212 | pending_message); |
1089 | 1213 | ||
1090 | if (core_transmit_handle == NULL) | 1214 | if (core_transmit_handle == NULL) |
1091 | core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, send_context->timeout, &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); | 1215 | core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, GNUNET_TIME_relative_get_forever(), &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); |
1092 | 1216 | ||
1093 | } | 1217 | } |
1094 | 1218 | ||
1095 | send_context->task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_DV_DEFAULT_SEND_INTERVAL, &neighbor_send_task, send_context); | 1219 | if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */ |
1220 | { | ||
1221 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: still in fast send mode\n"); | ||
1222 | send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, send_context); | ||
1223 | } | ||
1224 | else | ||
1225 | { | ||
1226 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: entering slow send mode\n"); | ||
1227 | send_context->task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_DV_DEFAULT_SEND_INTERVAL, &neighbor_send_task, send_context); | ||
1228 | } | ||
1229 | |||
1096 | return; | 1230 | return; |
1097 | } | 1231 | } |
1098 | 1232 | ||
@@ -1158,10 +1292,12 @@ int send_iterator (void *cls, | |||
1158 | * @param message the actual message | 1292 | * @param message the actual message |
1159 | */ | 1293 | */ |
1160 | void handle_dv_send_message (void *cls, | 1294 | void handle_dv_send_message (void *cls, |
1161 | struct GNUNET_SERVER_Client * client, | 1295 | struct GNUNET_SERVER_Client * client, |
1162 | const struct GNUNET_MessageHeader * message) | 1296 | const struct GNUNET_MessageHeader * message) |
1163 | { | 1297 | { |
1164 | struct GNUNET_DV_SendMessage *send_msg; | 1298 | struct GNUNET_DV_SendMessage *send_msg; |
1299 | struct GNUNET_DV_SendResultMessage *send_result_msg; | ||
1300 | struct PendingMessage *pending_message; | ||
1165 | size_t address_len; | 1301 | size_t address_len; |
1166 | size_t message_size; | 1302 | size_t message_size; |
1167 | struct GNUNET_PeerIdentity *destination; | 1303 | struct GNUNET_PeerIdentity *destination; |
@@ -1193,8 +1329,8 @@ void handle_dv_send_message (void *cls, | |||
1193 | GNUNET_assert(address_len == sizeof(struct GNUNET_PeerIdentity) * 2); | 1329 | GNUNET_assert(address_len == sizeof(struct GNUNET_PeerIdentity) * 2); |
1194 | message_size = ntohl(send_msg->msgbuf_size); | 1330 | message_size = ntohl(send_msg->msgbuf_size); |
1195 | 1331 | ||
1196 | #if DEBUG_DV | 1332 | #if 1 |
1197 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1333 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1198 | "%s: Receives %s message size %u!\n\n\n", "dv", "SEND", message_size); | 1334 | "%s: Receives %s message size %u!\n\n\n", "dv", "SEND", message_size); |
1199 | #endif | 1335 | #endif |
1200 | GNUNET_assert(ntohs(message->size) == sizeof(struct GNUNET_DV_SendMessage) + address_len + message_size); | 1336 | GNUNET_assert(ntohs(message->size) == sizeof(struct GNUNET_DV_SendMessage) + address_len + message_size); |
@@ -1220,25 +1356,57 @@ void handle_dv_send_message (void *cls, | |||
1220 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: asked to send message to `%s', but address is for `%s'!", "DV SERVICE", GNUNET_i2s(&send_msg->target), (const char *)&dest_hash.encoding); | 1356 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: asked to send message to `%s', but address is for `%s'!", "DV SERVICE", GNUNET_i2s(&send_msg->target), (const char *)&dest_hash.encoding); |
1221 | } | 1357 | } |
1222 | 1358 | ||
1223 | #if DEBUG_DV | 1359 | #if 1 |
1224 | GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ | 1360 | GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ |
1225 | dest_hash.encoding[4] = '\0'; | 1361 | dest_hash.encoding[4] = '\0'; |
1226 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DV SEND called with message of size %d type %d, destination `%s' via `%s'\n", message_size, ntohs(message_buf->type), (const char *)&dest_hash.encoding, GNUNET_i2s(direct)); | 1362 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SEND called with message of size %d type %d, destination `%s' via `%s'\n", message_size, ntohs(message_buf->type), (const char *)&dest_hash.encoding, GNUNET_i2s(direct)); |
1227 | #endif | 1363 | #endif |
1228 | send_context = GNUNET_malloc(sizeof(struct DV_SendContext)); | 1364 | send_context = GNUNET_malloc(sizeof(struct DV_SendContext)); |
1229 | 1365 | ||
1366 | send_result_msg = GNUNET_malloc(sizeof(struct GNUNET_DV_SendResultMessage)); | ||
1367 | send_result_msg->header.size = htons(sizeof(struct GNUNET_DV_SendResultMessage)); | ||
1368 | send_result_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT); | ||
1369 | send_result_msg->uid = send_msg->uid; /* No need to ntohl->htonl this */ | ||
1370 | |||
1230 | send_context->importance = ntohl(send_msg->priority); | 1371 | send_context->importance = ntohl(send_msg->priority); |
1231 | send_context->timeout = send_msg->timeout; | 1372 | send_context->timeout = send_msg->timeout; |
1232 | send_context->direct_peer = direct; | 1373 | send_context->direct_peer = direct; |
1233 | send_context->distant_peer = destination; | 1374 | send_context->distant_peer = destination; |
1234 | send_context->message = message_buf; | 1375 | send_context->message = message_buf; |
1235 | send_context->message_size = message_size; | 1376 | send_context->message_size = message_size; |
1377 | send_context->send_result = send_result_msg; | ||
1236 | 1378 | ||
1237 | /* In bizarro world GNUNET_SYSERR indicates that we succeeded */ | 1379 | /* In bizarro world GNUNET_SYSERR indicates that we succeeded */ |
1238 | if (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors, &destination->hashPubKey, &send_iterator, send_context)) | 1380 | if (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors, &destination->hashPubKey, &send_iterator, send_context)) |
1239 | { | 1381 | { |
1382 | send_result_msg->result = htons(1); | ||
1383 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(struct GNUNET_DV_SendResultMessage)); | ||
1384 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; | ||
1385 | memcpy(&pending_message[1], send_result_msg, sizeof(struct GNUNET_DV_SendResultMessage)); | ||
1386 | GNUNET_free(send_result_msg); | ||
1387 | |||
1388 | GNUNET_CONTAINER_DLL_insert_after(plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message); | ||
1389 | |||
1390 | if (client_handle != NULL) | ||
1391 | { | ||
1392 | if (plugin_transmit_handle == NULL) | ||
1393 | { | ||
1394 | plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, | ||
1395 | sizeof(struct GNUNET_DV_SendResultMessage), | ||
1396 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1397 | &transmit_to_plugin, NULL); | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n"); | ||
1402 | } | ||
1403 | } | ||
1240 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SEND failed to send message to destination `%s' via `%s'\n", (const char *)&dest_hash.encoding, GNUNET_i2s(direct)); | 1404 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SEND failed to send message to destination `%s' via `%s'\n", (const char *)&dest_hash.encoding, GNUNET_i2s(direct)); |
1241 | } | 1405 | } |
1406 | else | ||
1407 | { | ||
1408 | |||
1409 | } | ||
1242 | 1410 | ||
1243 | GNUNET_free(message_buf); | 1411 | GNUNET_free(message_buf); |
1244 | GNUNET_free(send_context); | 1412 | GNUNET_free(send_context); |
@@ -1248,12 +1416,21 @@ void handle_dv_send_message (void *cls, | |||
1248 | GNUNET_SERVER_receive_done(client, GNUNET_OK); | 1416 | GNUNET_SERVER_receive_done(client, GNUNET_OK); |
1249 | } | 1417 | } |
1250 | 1418 | ||
1419 | /** Forward declarations **/ | ||
1251 | static int handle_dv_gossip_message (void *cls, | 1420 | static int handle_dv_gossip_message (void *cls, |
1252 | const struct GNUNET_PeerIdentity *peer, | 1421 | const struct GNUNET_PeerIdentity *peer, |
1253 | const struct GNUNET_MessageHeader *message, | 1422 | const struct GNUNET_MessageHeader *message, |
1254 | struct GNUNET_TIME_Relative latency, | 1423 | struct GNUNET_TIME_Relative latency, |
1255 | uint32_t distance); | 1424 | uint32_t distance); |
1256 | 1425 | ||
1426 | static int handle_dv_disconnect_message (void *cls, | ||
1427 | const struct GNUNET_PeerIdentity *peer, | ||
1428 | const struct GNUNET_MessageHeader *message, | ||
1429 | struct GNUNET_TIME_Relative latency, | ||
1430 | uint32_t distance); | ||
1431 | /** End forward declarations **/ | ||
1432 | |||
1433 | |||
1257 | /** | 1434 | /** |
1258 | * List of handlers for the messages understood by this | 1435 | * List of handlers for the messages understood by this |
1259 | * service. | 1436 | * service. |
@@ -1267,6 +1444,7 @@ static int handle_dv_gossip_message (void *cls, | |||
1267 | static struct GNUNET_CORE_MessageHandler core_handlers[] = { | 1444 | static struct GNUNET_CORE_MessageHandler core_handlers[] = { |
1268 | {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0}, | 1445 | {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0}, |
1269 | {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0}, | 1446 | {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0}, |
1447 | {&handle_dv_disconnect_message, GNUNET_MESSAGE_TYPE_DV_DISCONNECT, 0}, | ||
1270 | {NULL, 0, 0} | 1448 | {NULL, 0, 0} |
1271 | }; | 1449 | }; |
1272 | 1450 | ||
@@ -1276,6 +1454,133 @@ static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { | |||
1276 | {NULL, NULL, 0, 0} | 1454 | {NULL, NULL, 0, 0} |
1277 | }; | 1455 | }; |
1278 | 1456 | ||
1457 | /** | ||
1458 | * Free a DistantNeighbor node, including removing it | ||
1459 | * from the referer's list. | ||
1460 | */ | ||
1461 | static void | ||
1462 | distant_neighbor_free (struct DistantNeighbor *referee) | ||
1463 | { | ||
1464 | struct DirectNeighbor *referrer; | ||
1465 | |||
1466 | referrer = referee->referrer; | ||
1467 | if (referrer != NULL) | ||
1468 | { | ||
1469 | GNUNET_CONTAINER_DLL_remove (referrer->referee_head, | ||
1470 | referrer->referee_tail, referee); | ||
1471 | } | ||
1472 | GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc); | ||
1473 | GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc); | ||
1474 | GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors, | ||
1475 | &referee->identity.hashPubKey); | ||
1476 | GNUNET_free (referee->pkey); | ||
1477 | GNUNET_free (referee); | ||
1478 | } | ||
1479 | |||
1480 | /** | ||
1481 | * Free a DirectNeighbor node, including removing it | ||
1482 | * from the referer's list. | ||
1483 | */ | ||
1484 | static void | ||
1485 | direct_neighbor_free (struct DirectNeighbor *direct) | ||
1486 | { | ||
1487 | struct NeighborSendContext *send_context; | ||
1488 | struct FastGossipNeighborList *about_list; | ||
1489 | struct FastGossipNeighborList *prev_about; | ||
1490 | |||
1491 | send_context = direct->send_context; | ||
1492 | |||
1493 | if (send_context->task != GNUNET_SCHEDULER_NO_TASK) | ||
1494 | GNUNET_SCHEDULER_cancel(sched, send_context->task); | ||
1495 | |||
1496 | about_list = send_context->fast_gossip_list_head; | ||
1497 | while (about_list != NULL) | ||
1498 | { | ||
1499 | GNUNET_CONTAINER_DLL_remove(send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, about_list); | ||
1500 | prev_about = about_list; | ||
1501 | about_list = about_list->next; | ||
1502 | GNUNET_free(prev_about); | ||
1503 | } | ||
1504 | GNUNET_free(send_context); | ||
1505 | GNUNET_free(direct); | ||
1506 | } | ||
1507 | |||
1508 | /** | ||
1509 | * Multihashmap iterator for sending out disconnect messages | ||
1510 | * for a peer. | ||
1511 | * | ||
1512 | * @param cls the peer that was disconnected | ||
1513 | * @param key key value stored under | ||
1514 | * @param value the direct neighbor to send disconnect to | ||
1515 | * | ||
1516 | * @return GNUNET_YES to continue iteration, GNUNET_NO to stop | ||
1517 | */ | ||
1518 | static int schedule_disconnect_messages (void *cls, | ||
1519 | const GNUNET_HashCode * key, | ||
1520 | void *value) | ||
1521 | { | ||
1522 | struct DisconnectContext *disconnect_context = cls; | ||
1523 | struct DirectNeighbor *disconnected = disconnect_context->direct; | ||
1524 | struct DirectNeighbor *notify = value; | ||
1525 | struct PendingMessage *pending_message; | ||
1526 | p2p_dv_MESSAGE_Disconnect *disconnect_message; | ||
1527 | |||
1528 | if (memcmp(¬ify->identity, &disconnected->identity, sizeof(struct GNUNET_PeerIdentity)) == 0) | ||
1529 | return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */ | ||
1530 | |||
1531 | pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(p2p_dv_MESSAGE_Disconnect)); | ||
1532 | pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1]; | ||
1533 | disconnect_message = (p2p_dv_MESSAGE_Disconnect *)pending_message->msg; | ||
1534 | disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect)); | ||
1535 | disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT); | ||
1536 | disconnect_message->peer_id = htonl(disconnect_context->distant->our_id); | ||
1537 | |||
1538 | GNUNET_CONTAINER_DLL_insert_after (core_pending_head, | ||
1539 | core_pending_tail, | ||
1540 | core_pending_tail, | ||
1541 | pending_message); | ||
1542 | |||
1543 | if (core_transmit_handle == NULL) | ||
1544 | core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, GNUNET_TIME_relative_get_forever(), ¬ify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL); | ||
1545 | |||
1546 | return GNUNET_YES; | ||
1547 | } | ||
1548 | |||
1549 | /** | ||
1550 | * Multihashmap iterator for freeing extended neighbors. | ||
1551 | * | ||
1552 | * @param cls NULL | ||
1553 | * @param key key value stored under | ||
1554 | * @param value the distant neighbor to be freed | ||
1555 | * | ||
1556 | * @return GNUNET_YES to continue iteration, GNUNET_NO to stop | ||
1557 | */ | ||
1558 | static int free_extended_neighbors (void *cls, | ||
1559 | const GNUNET_HashCode * key, | ||
1560 | void *value) | ||
1561 | { | ||
1562 | struct DistantNeighbor *distant = value; | ||
1563 | distant_neighbor_free(distant); | ||
1564 | return GNUNET_YES; | ||
1565 | } | ||
1566 | |||
1567 | /** | ||
1568 | * Multihashmap iterator for freeing direct neighbors. | ||
1569 | * | ||
1570 | * @param cls NULL | ||
1571 | * @param key key value stored under | ||
1572 | * @param value the direct neighbor to be freed | ||
1573 | * | ||
1574 | * @return GNUNET_YES to continue iteration, GNUNET_NO to stop | ||
1575 | */ | ||
1576 | static int free_direct_neighbors (void *cls, | ||
1577 | const GNUNET_HashCode * key, | ||
1578 | void *value) | ||
1579 | { | ||
1580 | struct DirectNeighbor *direct = value; | ||
1581 | direct_neighbor_free(direct); | ||
1582 | return GNUNET_YES; | ||
1583 | } | ||
1279 | 1584 | ||
1280 | /** | 1585 | /** |
1281 | * Task run during shutdown. | 1586 | * Task run during shutdown. |
@@ -1290,6 +1595,14 @@ shutdown_task (void *cls, | |||
1290 | #if DEBUG_DV | 1595 | #if DEBUG_DV |
1291 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n"); | 1596 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n"); |
1292 | #endif | 1597 | #endif |
1598 | GNUNET_CONTAINER_multihashmap_iterate(ctx.extended_neighbors, &free_extended_neighbors, NULL); | ||
1599 | GNUNET_CONTAINER_multihashmap_destroy(ctx.extended_neighbors); | ||
1600 | GNUNET_CONTAINER_multihashmap_iterate(ctx.direct_neighbors, &free_direct_neighbors, NULL); | ||
1601 | GNUNET_CONTAINER_multihashmap_destroy(ctx.direct_neighbors); | ||
1602 | |||
1603 | GNUNET_CONTAINER_heap_destroy(ctx.neighbor_max_heap); | ||
1604 | GNUNET_CONTAINER_heap_destroy(ctx.neighbor_min_heap); | ||
1605 | |||
1293 | GNUNET_CORE_disconnect (coreAPI); | 1606 | GNUNET_CORE_disconnect (coreAPI); |
1294 | GNUNET_PEERINFO_disconnect(peerinfo_handle); | 1607 | GNUNET_PEERINFO_disconnect(peerinfo_handle); |
1295 | #if DEBUG_DV | 1608 | #if DEBUG_DV |
@@ -1379,29 +1692,6 @@ static int update_matching_neighbors (void *cls, | |||
1379 | } | 1692 | } |
1380 | 1693 | ||
1381 | 1694 | ||
1382 | /** | ||
1383 | * Free a DistantNeighbor node, including removing it | ||
1384 | * from the referer's list. | ||
1385 | */ | ||
1386 | static void | ||
1387 | distant_neighbor_free (struct DistantNeighbor *referee) | ||
1388 | { | ||
1389 | struct DirectNeighbor *referrer; | ||
1390 | |||
1391 | referrer = referee->referrer; | ||
1392 | if (referrer != NULL) | ||
1393 | { | ||
1394 | GNUNET_CONTAINER_DLL_remove (referrer->referee_head, | ||
1395 | referrer->referee_tail, referee); | ||
1396 | } | ||
1397 | GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc); | ||
1398 | GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc); | ||
1399 | GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors, | ||
1400 | &referee->identity.hashPubKey); | ||
1401 | GNUNET_free (referee); | ||
1402 | } | ||
1403 | |||
1404 | |||
1405 | #if DEBUG_DV_GOSSIP | 1695 | #if DEBUG_DV_GOSSIP |
1406 | /** | 1696 | /** |
1407 | * Iterator over hash map entries. | 1697 | * Iterator over hash map entries. |
@@ -1579,6 +1869,52 @@ generate_hello_address (void *cls, size_t max, void *buf) | |||
1579 | 1869 | ||
1580 | 1870 | ||
1581 | /** | 1871 | /** |
1872 | * Core handler for dv disconnect messages. These will be used | ||
1873 | * by us to tell transport via the dv plugin that a peer can | ||
1874 | * no longer be contacted by us via a certain address. We should | ||
1875 | * then propagate these messages on, given that the distance to | ||
1876 | * the peer indicates we would have gossiped about it to others. | ||
1877 | * | ||
1878 | * @param cls closure | ||
1879 | * @param peer peer which sent the message (immediate sender) | ||
1880 | * @param message the message | ||
1881 | * @param latency the latency of the connection we received the message from | ||
1882 | * @param distance the distance to the immediate peer | ||
1883 | */ | ||
1884 | static int handle_dv_disconnect_message (void *cls, | ||
1885 | const struct GNUNET_PeerIdentity *peer, | ||
1886 | const struct GNUNET_MessageHeader *message, | ||
1887 | struct GNUNET_TIME_Relative latency, | ||
1888 | uint32_t distance) | ||
1889 | { | ||
1890 | struct DirectNeighbor *referrer; | ||
1891 | struct DistantNeighbor *distant; | ||
1892 | p2p_dv_MESSAGE_Disconnect *enc_message = (p2p_dv_MESSAGE_Disconnect *)message; | ||
1893 | |||
1894 | if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect)) | ||
1895 | { | ||
1896 | return GNUNET_SYSERR; /* invalid message */ | ||
1897 | } | ||
1898 | |||
1899 | referrer = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, | ||
1900 | &peer->hashPubKey); | ||
1901 | if (referrer == NULL) | ||
1902 | return GNUNET_OK; | ||
1903 | |||
1904 | distant = referrer->referee_head; | ||
1905 | while (distant != NULL) | ||
1906 | { | ||
1907 | if (distant->referrer_id == ntohl(enc_message->peer_id)) | ||
1908 | { | ||
1909 | distant_neighbor_free(distant); | ||
1910 | } | ||
1911 | } | ||
1912 | |||
1913 | return GNUNET_OK; | ||
1914 | } | ||
1915 | |||
1916 | |||
1917 | /** | ||
1582 | * Core handler for dv gossip messages. These will be used | 1918 | * Core handler for dv gossip messages. These will be used |
1583 | * by us to create a HELLO message for the newly peer containing | 1919 | * by us to create a HELLO message for the newly peer containing |
1584 | * which direct peer we can connect through, and what the cost | 1920 | * which direct peer we can connect through, and what the cost |
@@ -1640,6 +1976,94 @@ static int handle_dv_gossip_message (void *cls, | |||
1640 | return GNUNET_OK; | 1976 | return GNUNET_OK; |
1641 | } | 1977 | } |
1642 | 1978 | ||
1979 | |||
1980 | /** | ||
1981 | * Iterate over all currently known peers, add them to the | ||
1982 | * fast gossip list for this peer so we get DV routing information | ||
1983 | * out as fast as possible! | ||
1984 | * | ||
1985 | * @param cls the direct neighbor we will gossip to | ||
1986 | * @param key the hashcode of the peer | ||
1987 | * @param value the distant neighbor we should add to the list | ||
1988 | * | ||
1989 | * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise | ||
1990 | */ | ||
1991 | static int add_all_extended_peers (void *cls, | ||
1992 | const GNUNET_HashCode * key, | ||
1993 | void *value) | ||
1994 | { | ||
1995 | struct NeighborSendContext *send_context = (struct NeighborSendContext *)cls; | ||
1996 | struct DistantNeighbor *distant = (struct DistantNeighbor *)value; | ||
1997 | struct FastGossipNeighborList *gossip_entry; | ||
1998 | |||
1999 | if (memcmp(&send_context->toNeighbor->identity, &distant->identity, sizeof(struct GNUNET_PeerIdentity)) == 0) | ||
2000 | return GNUNET_YES; /* Don't gossip to a peer about itself! */ | ||
2001 | |||
2002 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: adding extended neighbor to fast send list\n"); | ||
2003 | #if SUPPORT_HIDING | ||
2004 | if (distant->hidden == GNUNET_YES) | ||
2005 | return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ | ||
2006 | #endif | ||
2007 | gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList)); | ||
2008 | gossip_entry->about = distant; | ||
2009 | |||
2010 | GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head, | ||
2011 | send_context->fast_gossip_list_tail, | ||
2012 | send_context->fast_gossip_list_tail, | ||
2013 | gossip_entry); | ||
2014 | |||
2015 | return GNUNET_YES; | ||
2016 | } | ||
2017 | |||
2018 | |||
2019 | /** | ||
2020 | * Iterate over all current direct peers, add newly connected peer | ||
2021 | * to the fast gossip list for that peer so we get DV routing | ||
2022 | * information out as fast as possible! | ||
2023 | * | ||
2024 | * @param cls the newly connected neighbor we will gossip about | ||
2025 | * @param key the hashcode of the peer | ||
2026 | * @param value the direct neighbor we should gossip to | ||
2027 | * | ||
2028 | * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise | ||
2029 | */ | ||
2030 | static int add_all_direct_neighbors (void *cls, | ||
2031 | const GNUNET_HashCode * key, | ||
2032 | void *value) | ||
2033 | { | ||
2034 | struct DirectNeighbor *direct = (struct DirectNeighbor *)value; | ||
2035 | struct DirectNeighbor *to = (struct DirectNeighbor *)cls; | ||
2036 | struct DistantNeighbor *distant; | ||
2037 | struct NeighborSendContext *send_context = direct->send_context; | ||
2038 | struct FastGossipNeighborList *gossip_entry; | ||
2039 | |||
2040 | distant = GNUNET_CONTAINER_multihashmap_get(ctx.extended_neighbors, &to->identity.hashPubKey); | ||
2041 | if (distant == NULL) | ||
2042 | return GNUNET_YES; | ||
2043 | |||
2044 | if (memcmp(&direct->identity, &to->identity, sizeof(struct GNUNET_PeerIdentity)) == 0) | ||
2045 | return GNUNET_YES; /* Don't gossip to a peer about itself! */ | ||
2046 | |||
2047 | GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: adding new DISTANT neighbor to fast send list\n"); | ||
2048 | #if SUPPORT_HIDING | ||
2049 | if (distant->hidden == GNUNET_YES) | ||
2050 | return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ | ||
2051 | #endif | ||
2052 | gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList)); | ||
2053 | gossip_entry->about = distant; | ||
2054 | |||
2055 | GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head, | ||
2056 | send_context->fast_gossip_list_tail, | ||
2057 | send_context->fast_gossip_list_tail, | ||
2058 | gossip_entry); | ||
2059 | if (send_context->task != GNUNET_SCHEDULER_NO_TASK) | ||
2060 | GNUNET_SCHEDULER_cancel(sched, send_context->task); | ||
2061 | |||
2062 | send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, send_context); | ||
2063 | return GNUNET_YES; | ||
2064 | } | ||
2065 | |||
2066 | |||
1643 | static void | 2067 | static void |
1644 | process_peerinfo (void *cls, | 2068 | process_peerinfo (void *cls, |
1645 | const struct GNUNET_PeerIdentity *peer, | 2069 | const struct GNUNET_PeerIdentity *peer, |
@@ -1664,10 +2088,15 @@ process_peerinfo (void *cls, | |||
1664 | &peer->hashPubKey, | 2088 | &peer->hashPubKey, |
1665 | &add_pkey_to_extended, | 2089 | &add_pkey_to_extended, |
1666 | &neighbor->pkey); | 2090 | &neighbor->pkey); |
2091 | |||
2092 | GNUNET_CONTAINER_multihashmap_iterate (ctx.extended_neighbors, &add_all_extended_peers, neighbor->send_context); | ||
2093 | |||
2094 | GNUNET_CONTAINER_multihashmap_iterate (ctx.direct_neighbors, &add_all_direct_neighbors, neighbor); | ||
1667 | neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context); | 2095 | neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context); |
1668 | } | 2096 | } |
1669 | } | 2097 | } |
1670 | 2098 | ||
2099 | |||
1671 | /** | 2100 | /** |
1672 | * Method called whenever a peer connects. | 2101 | * Method called whenever a peer connects. |
1673 | * | 2102 | * |
@@ -1682,6 +2111,7 @@ void handle_core_connect (void *cls, | |||
1682 | uint32_t distance) | 2111 | uint32_t distance) |
1683 | { | 2112 | { |
1684 | struct DirectNeighbor *neighbor; | 2113 | struct DirectNeighbor *neighbor; |
2114 | struct DistantNeighbor *about; | ||
1685 | struct PeerIteratorContext *peerinfo_iterator; | 2115 | struct PeerIteratorContext *peerinfo_iterator; |
1686 | #if DEBUG_DV | 2116 | #if DEBUG_DV |
1687 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2117 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1694,9 +2124,8 @@ void handle_core_connect (void *cls, | |||
1694 | neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor)); | 2124 | neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor)); |
1695 | neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext)); | 2125 | neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext)); |
1696 | neighbor->send_context->toNeighbor = neighbor; | 2126 | neighbor->send_context->toNeighbor = neighbor; |
1697 | neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */ | ||
1698 | memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); | 2127 | memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); |
1699 | /*memcpy (&neighbor->pkey, ,sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));*/ | 2128 | |
1700 | GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors, | 2129 | GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors, |
1701 | &peer->hashPubKey, | 2130 | &peer->hashPubKey, |
1702 | neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | 2131 | neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); |
@@ -1708,6 +2137,7 @@ void handle_core_connect (void *cls, | |||
1708 | GNUNET_TIME_UNIT_FOREVER_REL, | 2137 | GNUNET_TIME_UNIT_FOREVER_REL, |
1709 | &process_peerinfo, | 2138 | &process_peerinfo, |
1710 | peerinfo_iterator); | 2139 | peerinfo_iterator); |
2140 | |||
1711 | /* Only add once we get the publicKey of this guy | 2141 | /* Only add once we get the publicKey of this guy |
1712 | * | 2142 | * |
1713 | * neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context); | 2143 | * neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context); |
@@ -1715,6 +2145,10 @@ void handle_core_connect (void *cls, | |||
1715 | } | 2145 | } |
1716 | else | 2146 | else |
1717 | { | 2147 | { |
2148 | about = GNUNET_CONTAINER_multihashmap_get(ctx.extended_neighbors, &peer->hashPubKey); | ||
2149 | if ((GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL) && (about != NULL)) | ||
2150 | GNUNET_CONTAINER_multihashmap_iterate(ctx.direct_neighbors, &add_all_direct_neighbors, about); | ||
2151 | |||
1718 | #if DEBUG_DV | 2152 | #if DEBUG_DV |
1719 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2153 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1720 | "%s: Distance (%d) greater than %d or already know about peer (%s), not re-adding!\n", "dv", distance, DIRECT_NEIGHBOR_COST, GNUNET_i2s(peer)); | 2154 | "%s: Distance (%d) greater than %d or already know about peer (%s), not re-adding!\n", "dv", distance, DIRECT_NEIGHBOR_COST, GNUNET_i2s(peer)); |
@@ -1734,7 +2168,8 @@ void handle_core_disconnect (void *cls, | |||
1734 | { | 2168 | { |
1735 | struct DirectNeighbor *neighbor; | 2169 | struct DirectNeighbor *neighbor; |
1736 | struct DistantNeighbor *referee; | 2170 | struct DistantNeighbor *referee; |
1737 | 2171 | struct FindDestinationContext fdc; | |
2172 | struct DisconnectContext disconnect_context; | ||
1738 | #if DEBUG_DV | 2173 | #if DEBUG_DV |
1739 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2174 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1740 | "%s: Receives core peer disconnect message!\n", "dv"); | 2175 | "%s: Receives core peer disconnect message!\n", "dv"); |
@@ -1748,9 +2183,22 @@ void handle_core_disconnect (void *cls, | |||
1748 | } | 2183 | } |
1749 | while (NULL != (referee = neighbor->referee_head)) | 2184 | while (NULL != (referee = neighbor->referee_head)) |
1750 | distant_neighbor_free (referee); | 2185 | distant_neighbor_free (referee); |
2186 | |||
2187 | fdc.dest = NULL; | ||
2188 | fdc.tid = 0; | ||
2189 | |||
2190 | GNUNET_CONTAINER_multihashmap_iterate (ctx.extended_neighbors, &find_distant_peer, &fdc); | ||
2191 | |||
2192 | if (fdc.dest != NULL) | ||
2193 | { | ||
2194 | disconnect_context.direct = neighbor; | ||
2195 | disconnect_context.distant = fdc.dest; | ||
2196 | GNUNET_CONTAINER_multihashmap_iterate (ctx.direct_neighbors, &schedule_disconnect_messages, &disconnect_context); | ||
2197 | } | ||
2198 | |||
1751 | GNUNET_assert (neighbor->referee_tail == NULL); | 2199 | GNUNET_assert (neighbor->referee_tail == NULL); |
1752 | GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors, | 2200 | GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors, |
1753 | &peer->hashPubKey, neighbor); | 2201 | &peer->hashPubKey, neighbor); |
1754 | if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK)) | 2202 | if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK)) |
1755 | GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task); | 2203 | GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task); |
1756 | GNUNET_free (neighbor); | 2204 | GNUNET_free (neighbor); |
@@ -1771,16 +2219,29 @@ run (void *cls, | |||
1771 | struct GNUNET_SERVER_Handle *server, | 2219 | struct GNUNET_SERVER_Handle *server, |
1772 | const struct GNUNET_CONFIGURATION_Handle *c) | 2220 | const struct GNUNET_CONFIGURATION_Handle *c) |
1773 | { | 2221 | { |
1774 | struct GNUNET_TIME_Relative timeout; | ||
1775 | unsigned long long max_hosts; | 2222 | unsigned long long max_hosts; |
1776 | timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5); | ||
1777 | sched = scheduler; | 2223 | sched = scheduler; |
1778 | cfg = c; | 2224 | cfg = c; |
1779 | 2225 | ||
1780 | /* FIXME: Read from config, or calculate, or something other than this! */ | 2226 | /* FIXME: Read from config, or calculate, or something other than this! */ |
1781 | max_hosts = 50; | 2227 | max_hosts = DEFAULT_DIRECT_CONNECTIONS; |
1782 | ctx.max_table_size = 100; | 2228 | ctx.max_table_size = DEFAULT_DV_SIZE; |
1783 | ctx.fisheye_depth = 3; | 2229 | ctx.fisheye_depth = DEFAULT_FISHEYE_DEPTH; |
2230 | |||
2231 | if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "max_direct_connections")) | ||
2232 | { | ||
2233 | GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "max_direct_connections", &max_hosts); | ||
2234 | } | ||
2235 | |||
2236 | if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "max_total_connections")) | ||
2237 | { | ||
2238 | GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "max_total_connections", &ctx.max_table_size); | ||
2239 | } | ||
2240 | |||
2241 | if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "fisheye_depth")) | ||
2242 | { | ||
2243 | GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "fisheye_depth", &ctx.fisheye_depth); | ||
2244 | } | ||
1784 | 2245 | ||
1785 | ctx.neighbor_min_heap = | 2246 | ctx.neighbor_min_heap = |
1786 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | 2247 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); |
@@ -1790,14 +2251,12 @@ run (void *cls, | |||
1790 | ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts); | 2251 | ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts); |
1791 | ctx.extended_neighbors = | 2252 | ctx.extended_neighbors = |
1792 | GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3); | 2253 | GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3); |
1793 | client_transmit_timeout = GNUNET_TIME_relative_get_forever(); /* Only timeout on disconnect */ | ||
1794 | default_dv_delay = GNUNET_TIME_relative_get_forever(); /* Only timeout on disconnect */ | ||
1795 | 2254 | ||
1796 | GNUNET_SERVER_add_handlers (server, plugin_handlers); | 2255 | GNUNET_SERVER_add_handlers (server, plugin_handlers); |
1797 | coreAPI = | 2256 | coreAPI = |
1798 | GNUNET_CORE_connect (sched, | 2257 | GNUNET_CORE_connect (sched, |
1799 | cfg, | 2258 | cfg, |
1800 | timeout, | 2259 | GNUNET_TIME_relative_get_forever(), |
1801 | NULL, /* FIXME: anything we want to pass around? */ | 2260 | NULL, /* FIXME: anything we want to pass around? */ |
1802 | &core_init, | 2261 | &core_init, |
1803 | &handle_core_connect, | 2262 | &handle_core_connect, |