aboutsummaryrefslogtreecommitdiff
path: root/src/dv/gnunet-service-dv.c
diff options
context:
space:
mode:
authorNathan S. Evans <evans@in.tum.de>2010-04-30 14:50:06 +0000
committerNathan S. Evans <evans@in.tum.de>2010-04-30 14:50:06 +0000
commit5f9efe3ff20656b7900fc0b503f3e0cbe75eb20a (patch)
treea6f379dfd9dafc1db1fa95260ab7029f15a9b283 /src/dv/gnunet-service-dv.c
parente6b08db0728b172da76392967661c09e7bfdbb55 (diff)
downloadgnunet-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.c613
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 */
135struct DistantNeighbor *referees; 151struct DistantNeighbor *referees;
136 152
137static struct GNUNET_TIME_Relative client_transmit_timeout;
138
139static struct GNUNET_TIME_Relative default_dv_delay;
140
141static size_t default_dv_priority = 0; 153static 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;
199struct PendingMessage *core_pending_tail; 212struct PendingMessage *core_pending_tail;
200 213
201 214
215struct 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
531struct 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 */
570static 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 */
558void send_to_plugin(const struct GNUNET_PeerIdentity * sender, 647void 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 */
1160void handle_dv_send_message (void *cls, 1294void 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 **/
1251static int handle_dv_gossip_message (void *cls, 1420static 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
1426static 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,
1267static struct GNUNET_CORE_MessageHandler core_handlers[] = { 1444static 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 */
1461static void
1462distant_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 */
1484static void
1485direct_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 */
1518static 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(&notify->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(), &notify->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 */
1558static 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 */
1576static 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 */
1386static void
1387distant_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 */
1884static 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 */
1991static 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 */
2030static 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
1643static void 2067static void
1644process_peerinfo (void *cls, 2068process_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,