aboutsummaryrefslogtreecommitdiff
path: root/src/dv
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-03-12 19:32:02 +0000
committerChristian Grothoff <christian@grothoff.org>2013-03-12 19:32:02 +0000
commite9a539d46298a5802384cb9d4379c5093816b01b (patch)
treed9e4dbe07859b735e5b722b6699f35ee47c61684 /src/dv
parentd3ab94d56ea6610532fb12156773aa8770198936 (diff)
downloadgnunet-e9a539d46298a5802384cb9d4379c5093816b01b.tar.gz
gnunet-e9a539d46298a5802384cb9d4379c5093816b01b.zip
-removing useless parts of old code, work on DHT API
Diffstat (limited to 'src/dv')
-rw-r--r--src/dv/dv_api.c830
-rw-r--r--src/dv/gnunet-service-dv.c1282
2 files changed, 268 insertions, 1844 deletions
diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c
index ca4334f2f..3f9f11423 100644
--- a/src/dv/dv_api.c
+++ b/src/dv/dv_api.c
@@ -39,18 +39,39 @@
39 */ 39 */
40struct GNUNET_DV_TransmitHandle 40struct GNUNET_DV_TransmitHandle
41{ 41{
42 /**
43 * Kept in a DLL.
44 */
42 struct GNUNET_DV_TransmitHandle *next; 45 struct GNUNET_DV_TransmitHandle *next;
43 46
47 /**
48 * Kept in a DLL.
49 */
44 struct GNUNET_DV_TransmitHandle *prev; 50 struct GNUNET_DV_TransmitHandle *prev;
45 51
52 /**
53 * Handle to the service.
54 */
46 struct GNUNET_DV_ServiceHandle *sh; 55 struct GNUNET_DV_ServiceHandle *sh;
47 56
57 /**
58 * Function to call upon completion.
59 */
48 GNUNET_DV_MessageSentCallback cb; 60 GNUNET_DV_MessageSentCallback cb;
49 61
62 /**
63 * Closure for 'cb'.
64 */
50 void *cb_cls; 65 void *cb_cls;
51 66
67 /**
68 * The actual message (allocated at the end of this struct).
69 */
52 const struct GNUNET_MessageHeader *msg; 70 const struct GNUNET_MessageHeader *msg;
53 71
72 /**
73 * Destination for the message.
74 */
54 struct GNUNET_PeerIdentity target; 75 struct GNUNET_PeerIdentity target;
55 76
56}; 77};
@@ -62,412 +83,131 @@ struct GNUNET_DV_TransmitHandle
62struct GNUNET_DV_ServiceHandle 83struct GNUNET_DV_ServiceHandle
63{ 84{
64 85
65 struct GNUNET_ClientHandle *client;
66
67 const struct GNUNET_CONFIGURATION_Handle *cfg;
68
69 void *cls;
70
71 GNUNET_DV_ConnectCallback connect_cb;
72
73 GNUNET_DV_DisconnectCallback disconnect_cb;
74
75 GNUNET_DV_MessageReceivedCallback message_cb;
76
77 struct GNUNET_DV_TransmitHandle *th_head;
78
79 struct GNUNET_DV_TransmitHandle *th_tail;
80
81};
82
83
84/**
85 * Connect to the DV service.
86 *
87 * @param cfg configuration
88 * @param cls closure for callbacks
89 * @param connect_cb function to call on connects
90 * @param disconnect_cb function to call on disconnects
91 * @param message_cb function to call if we receive messages
92 * @return handle to access the service
93 */
94struct GNUNET_DV_ServiceHandle *
95GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
96 void *cls,
97 GNUNET_DV_ConnectCallback connect_cb,
98 GNUNET_DV_DisconnectCallback disconnect_cb,
99 GNUNET_DV_MessageReceivedCallback message_cb)
100{
101 GNUNET_break (0);
102 return NULL;
103}
104
105
106/**
107 * Disconnect from DV service.
108 *
109 * @param sh service handle
110 */
111void
112GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh)
113{
114 GNUNET_break (0);
115}
116
117
118
119/**
120 * Send a message via DV service.
121 *
122 * @param sh service handle
123 * @param target intended recpient
124 * @param msg message payload
125 * @param cb function to invoke when done
126 * @param cb_cls closure for 'cb'
127 * @return handle to cancel the operation
128 */
129struct GNUNET_DV_TransmitHandle *
130GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
131 const struct GNUNET_PeerIdentity *target,
132 const struct GNUNET_MessageHeader *msg,
133 GNUNET_DV_MessageSentCallback cb,
134 void *cb_cls)
135{
136 GNUNET_break (0);
137 return NULL;
138}
139
140
141/**
142 * Abort send operation (naturally, the message may have
143 * already been transmitted; this only stops the 'cb'
144 * from being called again).
145 *
146 * @param th send operation to cancel
147 */
148void
149GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th)
150{
151 GNUNET_break (0);
152}
153
154
155
156#if 0
157
158
159
160
161
162
163
164
165
166
167
168
169/**
170 * Store ready to send messages
171 */
172struct PendingMessages
173{
174 /**
175 * Linked list of pending messages
176 */
177 struct PendingMessages *next;
178
179 /**
180 * Message that is pending
181 */
182 struct GNUNET_DV_SendMessage *msg;
183
184 /**
185 * Timeout for this message
186 */
187 struct GNUNET_TIME_Absolute timeout;
188
189};
190
191/**
192 * Handle for the service.
193 */
194struct GNUNET_DV_Handle
195{
196
197 /**
198 * Configuration to use.
199 */
200 const struct GNUNET_CONFIGURATION_Handle *cfg;
201
202 /** 86 /**
203 * Socket (if available). 87 * Connection to DV service.
204 */ 88 */
205 struct GNUNET_CLIENT_Connection *client; 89 struct GNUNET_CLIENT_Connection *client;
206 90
207 /** 91 /**
208 * Currently pending transmission request. 92 * Active request for transmission to DV service.
209 */ 93 */
210 struct GNUNET_CLIENT_TransmitHandle *th; 94 struct GNUNET_CLIENT_TransmitHandle *th;
211 95
212 /** 96 /**
213 * List of the currently pending messages for the DV service. 97 * Our configuration.
214 */
215 struct PendingMessages *pending_list;
216
217 /**
218 * Message we are currently sending.
219 */
220 struct PendingMessages *current;
221
222 /**
223 * Handler for messages we receive from the DV service
224 */
225 GNUNET_DV_MessageReceivedHandler receive_handler;
226
227 /**
228 * Closure for the receive handler
229 */ 98 */
230 void *receive_cls; 99 const struct GNUNET_CONFIGURATION_Handle *cfg;
231 100
232 /** 101 /**
233 * Current unique ID 102 * Closure for the callbacks.
234 */ 103 */
235 uint32_t uid_gen; 104 void *cls;
236 105
237 /** 106 /**
238 * Hashmap containing outstanding send requests awaiting confirmation. 107 * Function to call on connect events.
239 */ 108 */
240 struct GNUNET_CONTAINER_MultiHashMap *send_callbacks; 109 GNUNET_DV_ConnectCallback connect_cb;
241
242};
243
244 110
245struct StartContext
246{
247 /** 111 /**
248 * Start message 112 * Function to call on disconnect events.
249 */ 113 */
250 struct GNUNET_MessageHeader *message; 114 GNUNET_DV_DisconnectCallback disconnect_cb;
251 115
252 /** 116 /**
253 * Handle to service, in case of timeout 117 * Function to call on receiving messages events.
254 */ 118 */
255 struct GNUNET_DV_Handle *handle; 119 GNUNET_DV_MessageReceivedCallback message_cb;
256};
257 120
258struct SendCallbackContext
259{
260 /** 121 /**
261 * The continuation to call once a message is confirmed sent (or failed) 122 * Head of messages to transmit.
262 */ 123 */
263 GNUNET_TRANSPORT_TransmitContinuation cont; 124 struct GNUNET_DV_TransmitHandle *th_head;
264 125
265 /** 126 /**
266 * Closure to call with send continuation. 127 * Tail of messages to transmit.
267 */ 128 */
268 void *cont_cls; 129 struct GNUNET_DV_TransmitHandle *th_tail;
269 130
270 /** 131 /**
271 * Target of the message. 132 * Mapping of peer identities to TransmitHandles to invoke
133 * upon successful transmission. The respective
134 * transmissions have already been done.
272 */ 135 */
273 struct GNUNET_PeerIdentity target; 136 struct GNUNET_CONTAINER_MultiHashMap *send_callbacks;
274 137
275 /** 138 /**
276 * Payload size in bytes 139 * Current unique ID
277 */ 140 */
278 size_t payload_size; 141 uint32_t uid_gen;
279 142
280 /**
281 * DV message size
282 */
283 size_t msg_size;
284}; 143};
285 144
286/**
287 * Convert unique ID to hash code.
288 *
289 * @param uid unique ID to convert
290 * @param hash set to uid (extended with zeros)
291 */
292static void
293hash_from_uid (uint32_t uid, struct GNUNET_HashCode * hash)
294{
295 memset (hash, 0, sizeof (struct GNUNET_HashCode));
296 *((uint32_t *) hash) = uid;
297}
298
299/**
300 * Try to (re)connect to the dv service.
301 *
302 * @param ret handle to the (disconnected) dv service
303 *
304 * @return GNUNET_YES on success, GNUNET_NO on failure.
305 */
306static int
307try_connect (struct GNUNET_DV_Handle *ret)
308{
309 if (ret->client != NULL)
310 return GNUNET_OK;
311 ret->client = GNUNET_CLIENT_connect ("dv", ret->cfg);
312 if (ret->client != NULL)
313 return GNUNET_YES;
314#if DEBUG_DV_MESSAGES
315 LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failed to connect to the dv service!\n"));
316#endif
317 return GNUNET_NO;
318}
319
320static void
321process_pending_message (struct GNUNET_DV_Handle *handle);
322 145
323/** 146/**
324 * Send complete, schedule next 147 * Disconnect and then reconnect to the DV service.
325 * 148 *
326 * @param handle handle to the dv service 149 * @param sh service handle
327 * @param code return code for send (unused)
328 */ 150 */
329static void 151static void
330finish (struct GNUNET_DV_Handle *handle, int code) 152reconnect (struct GNUNET_DV_ServiceHandle *sh);
331{
332 struct PendingMessages *pos = handle->current;
333 153
334 handle->current = NULL;
335 process_pending_message (handle);
336
337 GNUNET_free (pos->msg);
338 GNUNET_free (pos);
339}
340 154
341/** 155/**
342 * Notification that we can send data 156 * Gives a message from our queue to the DV service.
343 * 157 *
344 * @param cls handle to the dv service (struct GNUNET_DV_Handle) 158 * @param cls handle to the dv service (struct GNUNET_DV_ServiceHandle)
345 * @param size how many bytes can we send 159 * @param size how many bytes can we send
346 * @param buf where to copy the message to send 160 * @param buf where to copy the message to send
347 *
348 * @return how many bytes we copied to buf 161 * @return how many bytes we copied to buf
349 */ 162 */
350static size_t 163static size_t
351transmit_pending (void *cls, size_t size, void *buf) 164transmit_pending (void *cls, size_t size, void *buf)
352{ 165{
353 struct GNUNET_DV_Handle *handle = cls; 166 struct GNUNET_DV_ServiceHandle *sh = cls;
354 size_t ret; 167 size_t ret;
355 size_t tsize; 168 size_t tsize;
356 169
357#if DEBUG_DV 170 sh->th = NULL;
358 if (handle->current != NULL) 171 if (NULL == buf)
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "DV API: Transmit pending called with message type %d\n",
361 ntohs (handle->current->msg->header.type));
362#endif
363
364 if (buf == NULL)
365 { 172 {
366#if DEBUG_DV 173 reconnect (sh);
367 LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: Transmit pending FAILED!\n\n\n");
368#endif
369 finish (handle, GNUNET_SYSERR);
370 return 0; 174 return 0;
371 } 175 }
372 handle->th = NULL;
373
374 ret = 0; 176 ret = 0;
375 177 // FIXME: yuck! -- copy multiple, remove from DLL, and add to hash map!
376 if (handle->current != NULL) 178 if (NULL != sh->th_head)
377 { 179 {
378 tsize = ntohs (handle->current->msg->header.size); 180 tsize = ntohs (sh->th_head->msg->size);
379 if (size >= tsize) 181 if (size >= tsize)
380 { 182 {
381 memcpy (buf, handle->current->msg, tsize); 183 memcpy (buf, sh->th_head->msg, tsize);
382#if DEBUG_DV
383 LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "DV API: Copied %d bytes into buffer!\n\n\n", tsize);
385#endif
386 finish (handle, GNUNET_OK);
387 return tsize; 184 return tsize;
388 } 185 }
389
390 } 186 }
391
392 return ret; 187 return ret;
393} 188}
394 189
190
395/** 191/**
396 * Try to send messages from list of messages to send 192 * Start sending messages from our queue to the service.
397 * 193 *
398 * @param handle handle to the distance vector service 194 * @param sh service handle
399 */ 195 */
400static void 196static void
401process_pending_message (struct GNUNET_DV_Handle *handle) 197start_transmit (struct GNUNET_DV_ServiceHandle *sh)
402{ 198{
403 199 if (NULL != sh->th)
404 if (handle->current != NULL)
405 return; /* action already pending */
406 if (GNUNET_YES != try_connect (handle))
407 {
408 finish (handle, GNUNET_SYSERR);
409 return;
410 }
411
412 /* schedule next action */
413 handle->current = handle->pending_list;
414 if (NULL == handle->current)
415 {
416 return; 200 return;
417 } 201 if (NULL == sh->th_head)
418 handle->pending_list = handle->pending_list->next; 202 return;
419 handle->current->next = NULL; 203 sh->th =
420 204 GNUNET_CLIENT_notify_transmit_ready (sh->client,
421 if (NULL == 205 ntohs (sh->th_head->msg->size),
422 (handle->th = 206 GNUNET_TIME_UNIT_FOREVER_REL,
423 GNUNET_CLIENT_notify_transmit_ready (handle->client, 207 GNUNET_NO,
424 ntohs (handle->current->msg-> 208 &transmit_pending, sh);
425 header.size),
426 handle->current->msg->timeout,
427 GNUNET_YES, &transmit_pending,
428 handle)))
429 {
430#if DEBUG_DV
431 LOG (GNUNET_ERROR_TYPE_DEBUG,
432 "Failed to transmit request to dv service.\n");
433#endif
434 finish (handle, GNUNET_SYSERR);
435 }
436} 209}
437 210
438/**
439 * Add a pending message to the linked list
440 *
441 * @param handle handle to the specified DV api
442 * @param msg the message to add to the list
443 */
444static void
445add_pending (struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg)
446{
447 struct PendingMessages *new_message;
448 struct PendingMessages *pos;
449 struct PendingMessages *last;
450
451 new_message = GNUNET_malloc (sizeof (struct PendingMessages));
452 new_message->msg = msg;
453
454 if (handle->pending_list != NULL)
455 {
456 pos = handle->pending_list;
457 while (pos != NULL)
458 {
459 last = pos;
460 pos = pos->next;
461 }
462 last->next = new_message;
463 }
464 else
465 {
466 handle->pending_list = new_message;
467 }
468
469 process_pending_message (handle);
470}
471 211
472/** 212/**
473 * Handles a message sent from the DV service to us. 213 * Handles a message sent from the DV service to us.
@@ -476,295 +216,255 @@ add_pending (struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg)
476 * @param cls the handle to the DV API 216 * @param cls the handle to the DV API
477 * @param msg the message that was received 217 * @param msg the message that was received
478 */ 218 */
479void 219static void
480handle_message_receipt (void *cls, const struct GNUNET_MessageHeader *msg) 220handle_message_receipt (void *cls,
221 const struct GNUNET_MessageHeader *msg)
481{ 222{
482 struct GNUNET_DV_Handle *handle = cls; 223 struct GNUNET_DV_ServiceHandle *sh = cls;
483 struct GNUNET_DV_MessageReceived *received_msg; 224 const struct GNUNET_DV_ConnectMessage *cm;
484 struct GNUNET_DV_SendResultMessage *send_result_msg; 225 const struct GNUNET_DV_DisconnectMessage *dm;
485 size_t packed_msg_len; 226 const struct GNUNET_DV_ReceivedMessage *rm;
486 size_t sender_address_len; 227
487 char *sender_address; 228 if (NULL == msg)
488 char *packed_msg;
489 char *packed_msg_start;
490 struct GNUNET_HashCode uidhash;
491 struct SendCallbackContext *send_ctx;
492
493 if (msg == NULL)
494 { 229 {
495#if DEBUG_DV_MESSAGES 230 /* Connection closed */
496 LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: connection closed\n"); 231 reconnect (sh);
497#endif 232 return;
498 return; /* Connection closed? */
499 } 233 }
500
501 GNUNET_assert ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE)
502 || (ntohs (msg->type) ==
503 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT));
504
505 switch (ntohs (msg->type)) 234 switch (ntohs (msg->type))
506 { 235 {
507 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE: 236 case GNUNET_MESSAGE_TYPE_DV_CONNECT:
508 if (ntohs (msg->size) < sizeof (struct GNUNET_DV_MessageReceived)) 237 if (ntohs (msg->size) != sizeof (struct GNUNET_DV_ConnectMessage))
238 {
239 GNUNET_break (0);
240 reconnect (sh);
509 return; 241 return;
510 242 }
511 received_msg = (struct GNUNET_DV_MessageReceived *) msg; 243 cm = (const struct GNUNET_DV_ConnectMessage *) msg;
512 packed_msg_len = ntohl (received_msg->msg_len); 244 // FIXME
513 sender_address_len =
514 ntohs (msg->size) - packed_msg_len -
515 sizeof (struct GNUNET_DV_MessageReceived);
516 GNUNET_assert (sender_address_len > 0);
517 sender_address = GNUNET_malloc (sender_address_len);
518 memcpy (sender_address, &received_msg[1], sender_address_len);
519 packed_msg_start = (char *) &received_msg[1];
520 packed_msg = GNUNET_malloc (packed_msg_len);
521 memcpy (packed_msg, &packed_msg_start[sender_address_len], packed_msg_len);
522
523#if DEBUG_DV_MESSAGES
524 LOG (GNUNET_ERROR_TYPE_DEBUG,
525 "DV_API receive: packed message type: %d or %d\n",
526 ntohs (((struct GNUNET_MessageHeader *) packed_msg)->type),
527 ((struct GNUNET_MessageHeader *) packed_msg)->type);
528 LOG (GNUNET_ERROR_TYPE_DEBUG,
529 "DV_API receive: message sender reported as %s\n",
530 GNUNET_i2s (&received_msg->sender));
531 LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: distance is %u\n",
532 ntohl (received_msg->distance));
533#endif
534
535 handle->receive_handler (handle->receive_cls, &received_msg->sender,
536 packed_msg, packed_msg_len,
537 ntohl (received_msg->distance), sender_address,
538 sender_address_len);
539
540 GNUNET_free (sender_address);
541 break; 245 break;
542 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT: 246 case GNUNET_MESSAGE_TYPE_DV_DISCONNECT:
543 if (ntohs (msg->size) < sizeof (struct GNUNET_DV_SendResultMessage)) 247 if (ntohs (msg->size) != sizeof (struct GNUNET_DV_DisconnectMessage))
248 {
249 GNUNET_break (0);
250 reconnect (sh);
544 return; 251 return;
545 252 }
546 send_result_msg = (struct GNUNET_DV_SendResultMessage *) msg; 253 dm = (const struct GNUNET_DV_DisconnectMessage *) msg;
547 hash_from_uid (ntohl (send_result_msg->uid), &uidhash); 254 // FIXME
548 send_ctx = 255 break;
549 GNUNET_CONTAINER_multihashmap_get (handle->send_callbacks, &uidhash); 256 case GNUNET_MESSAGE_TYPE_DV_RECV:
550 257 if (ntohs (msg->size) < sizeof (struct GNUNET_DV_ReceivedMessage))
551 if ((send_ctx != NULL) && (send_ctx->cont != NULL))
552 { 258 {
553 if (ntohl (send_result_msg->result) == 0) 259 GNUNET_break (0);
554 { 260 reconnect (sh);
555 send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_OK, 261 return;
556 send_ctx->payload_size, send_ctx->msg_size);
557 }
558 else
559 {
560 send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_SYSERR,
561 send_ctx->payload_size, 0);
562 }
563 } 262 }
564 GNUNET_free_non_null (send_ctx); 263 rm = (const struct GNUNET_DV_ReceivedMessage *) msg;
264 // FIXME
565 break; 265 break;
566 default: 266 default:
267 reconnect (sh);
567 break; 268 break;
568 } 269 }
569 GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, 270 GNUNET_CLIENT_receive (sh->client,
271 &handle_message_receipt, sh,
570 GNUNET_TIME_UNIT_FOREVER_REL); 272 GNUNET_TIME_UNIT_FOREVER_REL);
571} 273}
572 274
573/**
574 * Send a message from the plugin to the DV service indicating that
575 * a message should be sent via DV to some peer.
576 *
577 * @param dv_handle the handle to the DV api
578 * @param target the final target of the message
579 * @param msgbuf the msg(s) to send
580 * @param msgbuf_size the size of msgbuf
581 * @param priority priority to pass on to core when sending the message
582 * @param timeout how long can this message be delayed (pass through to core)
583 * @param addr the address of this peer (internally known to DV)
584 * @param addrlen the length of the peer address
585 * @param cont continuation to call once the message has been sent (or failed)
586 * @param cont_cls closure for continuation
587 *
588 */
589int
590GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle,
591 const struct GNUNET_PeerIdentity *target, const char *msgbuf,
592 size_t msgbuf_size, unsigned int priority,
593 struct GNUNET_TIME_Relative timeout, const void *addr,
594 size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont,
595 void *cont_cls)
596{
597 struct GNUNET_DV_SendMessage *msg;
598 struct SendCallbackContext *send_ctx;
599 char *end_of_message;
600 struct GNUNET_HashCode uidhash;
601 int msize;
602
603#if DEBUG_DV_MESSAGES
604 dv_handle->uid_gen =
605 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, UINT32_MAX);
606#else
607 dv_handle->uid_gen++;
608#endif
609
610 msize = sizeof (struct GNUNET_DV_SendMessage) + addrlen + msgbuf_size;
611 msg = GNUNET_malloc (msize);
612 msg->header.size = htons (msize);
613 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND);
614 memcpy (&msg->target, target, sizeof (struct GNUNET_PeerIdentity));
615 msg->priority = htonl (priority);
616 msg->timeout = timeout;
617 msg->addrlen = htonl (addrlen);
618 msg->uid = htonl (dv_handle->uid_gen);
619 memcpy (&msg[1], addr, addrlen);
620 end_of_message = (char *) &msg[1];
621 end_of_message = &end_of_message[addrlen];
622 memcpy (end_of_message, msgbuf, msgbuf_size);
623 add_pending (dv_handle, msg);
624 send_ctx = GNUNET_malloc (sizeof (struct SendCallbackContext));
625 send_ctx->payload_size = msgbuf_size;
626 send_ctx->msg_size = msize;
627 send_ctx->cont = cont;
628 send_ctx->cont_cls = cont_cls;
629 memcpy (&send_ctx->target, target, sizeof (struct GNUNET_PeerIdentity));
630 hash_from_uid (dv_handle->uid_gen, &uidhash);
631 GNUNET_CONTAINER_multihashmap_put (dv_handle->send_callbacks, &uidhash,
632 send_ctx,
633 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
634
635 return GNUNET_OK;
636}
637 275
638/** 276/**
639 * Callback to transmit a start message to 277 * Transmit the start message to the DV service.
640 * the DV service, once we can send
641 * 278 *
642 * @param cls struct StartContext 279 * @param cls the 'struct GNUNET_DV_ServiceHandle'
643 * @param size how much can we send 280 * @param size number of bytes available in buf
644 * @param buf where to copy the message 281 * @param buf where to copy the message
645 * 282 * @return number of bytes written to buf
646 * @return number of bytes copied to buf 283 */
647 */
648static size_t 284static size_t
649transmit_start (void *cls, size_t size, void *buf) 285transmit_start (void *cls,
286 size_t size,
287 void *buf)
650{ 288{
651 struct StartContext *start_context = cls; 289 struct GNUNET_DV_ServiceHandle *sh = cls;
652 struct GNUNET_DV_Handle *handle = start_context->handle; 290 struct GNUNET_MessageHeader start_message;
653 size_t tsize;
654 291
655#if DEBUG_DV 292 sh->th = NULL;
656 LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: sending start request to service\n"); 293 if (NULL == buf)
657#endif
658 if (buf == NULL)
659 { 294 {
660 GNUNET_free (start_context->message); 295 GNUNET_break (0);
661 GNUNET_free (start_context); 296 reconnect (sh);
662 GNUNET_DV_disconnect (handle);
663 return 0; 297 return 0;
664 } 298 }
665 299 GNUNET_assert (size >= sizeof (start_message));
666 tsize = ntohs (start_context->message->size); 300 start_message.size = htons (sizeof (struct GNUNET_MessageHeader));
667 if (size >= tsize) 301 start_message.type = htons (GNUNET_MESSAGE_TYPE_DV_START);
668 { 302 memcpy (buf, &start_message, sizeof (start_message));
669 memcpy (buf, start_context->message, tsize); 303 GNUNET_CLIENT_receive (sh->client,
670 GNUNET_free (start_context->message); 304 &handle_message_receipt, sh,
671 GNUNET_free (start_context); 305 GNUNET_TIME_UNIT_FOREVER_REL);
672 GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, 306 start_transmit (sh);
673 GNUNET_TIME_UNIT_FOREVER_REL); 307 return sizeof (start_message);
674
675
676 return tsize;
677 }
678
679 return 0;
680} 308}
681 309
310
682/** 311/**
683 * Connect to the DV service 312 * Disconnect and then reconnect to the DV service.
684 * 313 *
685 * @param cfg the configuration to use 314 * @param sh service handle
686 * @param receive_handler method call when on receipt from the service
687 * @param receive_handler_cls closure for receive_handler
688 *
689 * @return handle to the DV service
690 */ 315 */
691struct GNUNET_DV_Handle * 316static void
692GNUNET_DV_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, 317reconnect (struct GNUNET_DV_ServiceHandle *sh)
693 GNUNET_DV_MessageReceivedHandler receive_handler,
694 void *receive_handler_cls)
695{ 318{
696 struct GNUNET_DV_Handle *handle; 319 if (NULL != sh->th)
697 struct GNUNET_MessageHeader *start_message;
698 struct StartContext *start_context;
699
700 handle = GNUNET_malloc (sizeof (struct GNUNET_DV_Handle));
701
702 handle->cfg = cfg;
703 handle->pending_list = NULL;
704 handle->current = NULL;
705 handle->th = NULL;
706 handle->client = GNUNET_CLIENT_connect ("dv", cfg);
707 handle->receive_handler = receive_handler;
708 handle->receive_cls = receive_handler_cls;
709
710 if (handle->client == NULL)
711 { 320 {
712 GNUNET_free (handle); 321 GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
713 return NULL; 322 sh->th = NULL;
714 } 323 }
324 if (NULL != sh->client)
325 {
326 GNUNET_CLIENT_disconnect (sh->client);
327 sh->client = NULL;
328 }
329 sh->client = GNUNET_CLIENT_connect ("dv", sh->cfg);
330 if (NULL == sh->client)
331 {
332 GNUNET_break (0);
333 return;
334 }
335 sh->th = GNUNET_CLIENT_notify_transmit_ready (sh->client,
336 sizeof (struct GNUNET_MessageHeader),
337 GNUNET_TIME_UNIT_FOREVER_REL,
338 GNUNET_YES,
339 &transmit_start,
340 sh);
341}
715 342
716 start_message = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader));
717 start_message->size = htons (sizeof (struct GNUNET_MessageHeader));
718 start_message->type = htons (GNUNET_MESSAGE_TYPE_DV_START);
719
720 start_context = GNUNET_malloc (sizeof (struct StartContext));
721 start_context->handle = handle;
722 start_context->message = start_message;
723 GNUNET_CLIENT_notify_transmit_ready (handle->client,
724 sizeof (struct GNUNET_MessageHeader),
725 GNUNET_TIME_relative_multiply
726 (GNUNET_TIME_UNIT_SECONDS, 60),
727 GNUNET_YES, &transmit_start,
728 start_context);
729 343
730 handle->send_callbacks = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); 344/**
345 * Connect to the DV service.
346 *
347 * @param cfg configuration
348 * @param cls closure for callbacks
349 * @param connect_cb function to call on connects
350 * @param disconnect_cb function to call on disconnects
351 * @param message_cb function to call if we receive messages
352 * @return handle to access the service
353 */
354struct GNUNET_DV_ServiceHandle *
355GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
356 void *cls,
357 GNUNET_DV_ConnectCallback connect_cb,
358 GNUNET_DV_DisconnectCallback disconnect_cb,
359 GNUNET_DV_MessageReceivedCallback message_cb)
360{
361 struct GNUNET_DV_ServiceHandle *sh;
731 362
732 return handle; 363 sh = GNUNET_malloc (sizeof (struct GNUNET_DV_ServiceHandle));
364 sh->cfg = cfg;
365 sh->cls = cls;
366 sh->connect_cb = connect_cb;
367 sh->disconnect_cb = disconnect_cb;
368 sh->message_cb = message_cb;
369 sh->send_callbacks = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES);
370 reconnect (sh);
371 return sh;
733} 372}
734 373
374
735/** 375/**
736 * Disconnect from the DV service 376 * Disconnect from DV service.
737 * 377 *
738 * @param handle the current handle to the service to disconnect 378 * @param sh service handle
739 */ 379 */
740void 380void
741GNUNET_DV_disconnect (struct GNUNET_DV_Handle *handle) 381GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh)
742{ 382{
743 struct PendingMessages *pos; 383 struct GNUNET_DV_TransmitHandle *pos;
744 384
745 GNUNET_assert (handle != NULL); 385 if (NULL == sh)
746 386 return;
747 if (handle->th != NULL) /* We have a live transmit request in the Aether */ 387 if (NULL != sh->th)
748 { 388 {
749 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); 389 GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
750 handle->th = NULL; 390 sh->th = NULL;
751 } 391 }
752 if (handle->current != NULL) /* We are trying to send something now, clean it up */ 392 while (NULL != (pos = sh->th_head))
753 GNUNET_free (handle->current);
754 while (NULL != (pos = handle->pending_list)) /* Remove all pending sends from the list */
755 { 393 {
756 handle->pending_list = pos->next; 394 GNUNET_CONTAINER_DLL_remove (sh->th_head,
395 sh->th_tail,
396 pos);
757 GNUNET_free (pos); 397 GNUNET_free (pos);
758 } 398 }
759 if (handle->client != NULL) /* Finally, disconnect from the service */ 399 if (NULL != sh->client)
760 { 400 {
761 GNUNET_CLIENT_disconnect (handle->client); 401 GNUNET_CLIENT_disconnect (sh->client);
762 handle->client = NULL; 402 sh->client = NULL;
763 } 403 }
404 // FIXME: handle and/or free entries in 'send_callbacks'!
405 GNUNET_CONTAINER_multihashmap_destroy (sh->send_callbacks);
406 GNUNET_free (sh);
407}
764 408
765 GNUNET_free (handle); 409
410/**
411 * Send a message via DV service.
412 *
413 * @param sh service handle
414 * @param target intended recpient
415 * @param msg message payload
416 * @param cb function to invoke when done
417 * @param cb_cls closure for 'cb'
418 * @return handle to cancel the operation
419 */
420struct GNUNET_DV_TransmitHandle *
421GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
422 const struct GNUNET_PeerIdentity *target,
423 const struct GNUNET_MessageHeader *msg,
424 GNUNET_DV_MessageSentCallback cb,
425 void *cb_cls)
426{
427 struct GNUNET_DV_TransmitHandle *th;
428
429 th = GNUNET_malloc (sizeof (struct GNUNET_DV_TransmitHandle) +
430 ntohs (msg->size));
431 th->sh = sh;
432 th->target = *target;
433 th->cb = cb;
434 th->cb_cls = cb_cls;
435 // FIXME: wrong, need to box 'msg' AND generate UID!
436 th->msg = (const struct GNUNET_MessageHeader *) &th[1];
437 memcpy (&th[1], msg, ntohs (msg->size));
438 GNUNET_CONTAINER_DLL_insert (sh->th_head,
439 sh->th_tail,
440 th);
441 start_transmit (sh);
442 return th;
443}
444
445
446/**
447 * Abort send operation (naturally, the message may have
448 * already been transmitted; this only stops the 'cb'
449 * from being called again).
450 *
451 * @param th send operation to cancel
452 */
453void
454GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th)
455{
456 struct GNUNET_DV_ServiceHandle *sh = th->sh;
457 int ret;
458
459 ret = GNUNET_CONTAINER_multihashmap_remove (sh->send_callbacks,
460 &th->target.hashPubKey,
461 th);
462 if (GNUNET_YES != ret)
463 GNUNET_CONTAINER_DLL_remove (sh->th_head,
464 sh->th_tail,
465 th);
466 GNUNET_free (th);
766} 467}
767 468
768#endif
769 469
770/* end of dv_api.c */ 470/* end of dv_api.c */
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c
index 451a438f9..c9b45b4e0 100644
--- a/src/dv/gnunet-service-dv.c
+++ b/src/dv/gnunet-service-dv.c
@@ -445,7 +445,7 @@ send_data_to_plugin (const struct GNUNET_MessageHeader *message,
445 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size); 445 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
446 received_msg = (struct GNUNET_DV_ReceivedMessage *) &pending_message[1]; 446 received_msg = (struct GNUNET_DV_ReceivedMessage *) &pending_message[1];
447 received_msg->header.size = htons (size); 447 received_msg->header.size = htons (size);
448 received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECV); 448 received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
449 received_msg->distance = htonl (distance); 449 received_msg->distance = htonl (distance);
450 received_msg->sender = *distant_neighbor; 450 received_msg->sender = *distant_neighbor;
451 memcpy (&received_msg[1], message, ntohs (message->size)); 451 memcpy (&received_msg[1], message, ntohs (message->size));
@@ -490,7 +490,7 @@ send_ack_to_plugin (struct GNUNET_PeerIdentity *target,
490 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size); 490 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
491 ack_msg = (struct GNUNET_DV_AckMessage *) &pending_message[1]; 491 ack_msg = (struct GNUNET_DV_AckMessage *) &pending_message[1];
492 ack_msg->header.size = htons (size); 492 ack_msg->header.size = htons (size);
493 ack_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_ACK); 493 ack_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_SEND_ACK);
494 ack_msg->uid = htonl (uid); 494 ack_msg->uid = htonl (uid);
495 ack_msg->target = *target; 495 ack_msg->target = *target;
496 GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head, 496 GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head,
@@ -556,1282 +556,6 @@ core_transmit_notify (void *cls, size_t size, void *buf)
556} 556}
557 557
558 558
559#if 0
560// ////////////////////////////////////////////////////////////////////////
561
562
563/**
564 * Send a DV data message via DV.
565 *
566 * @param sender the original sender of the message
567 * @param recipient the next hop recipient, may be our direct peer, maybe not
568 * @param send_context the send context
569 */
570static int
571send_message_via (const struct GNUNET_PeerIdentity *sender,
572 const struct GNUNET_PeerIdentity *recipient,
573 struct DV_SendContext *send_context)
574{
575 p2p_dv_MESSAGE_Data *toSend;
576 unsigned int msg_size;
577 unsigned int recipient_id;
578 unsigned int sender_id;
579 struct DistantNeighbor *source;
580 struct PendingMessage *pending_message;
581 struct FindIDContext find_context;
582
583 msg_size = send_context->message_size + sizeof (p2p_dv_MESSAGE_Data);
584
585 find_context.dest = send_context->distant_peer;
586 find_context.via = recipient;
587 find_context.tid = 0;
588 GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors,
589 &send_context->
590 distant_peer->hashPubKey,
591 &find_specific_id, &find_context);
592
593 if (find_context.tid == 0)
594 {
595 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
596 "%s: find_specific_id failed to find peer!\n", my_short_id);
597 /* target unknown to us, drop! */
598 return GNUNET_SYSERR;
599 }
600 recipient_id = find_context.tid;
601
602 if (0 == (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity))))
603 {
604 sender_id = 0;
605 source =
606 GNUNET_CONTAINER_multihashmap_get (extended_neighbors,
607 &sender->hashPubKey);
608 if (source != NULL)
609 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
610 "%s: send_message_via found %s, myself in extended peer list???\n",
611 my_short_id, GNUNET_i2s (&source->identity));
612 }
613 else
614 {
615 source =
616 GNUNET_CONTAINER_multihashmap_get (extended_neighbors,
617 &sender->hashPubKey);
618 if (source == NULL)
619 {
620 /* sender unknown to us, drop! */
621 return GNUNET_SYSERR;
622 }
623 sender_id = source->our_id;
624 }
625
626 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
627 pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
628 pending_message->send_result = send_context->send_result;
629 memcpy (&pending_message->recipient, recipient,
630 sizeof (struct GNUNET_PeerIdentity));
631 pending_message->msg_size = msg_size;
632 pending_message->importance = send_context->importance;
633 pending_message->timeout = send_context->timeout;
634 toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg;
635 toSend->header.size = htons (msg_size);
636 toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
637 toSend->sender = htonl (sender_id);
638 toSend->recipient = htonl (recipient_id);
639#if DEBUG_DV_MESSAGES
640 toSend->uid = send_context->uid; /* Still sent around in network byte order */
641#else
642 toSend->uid = htonl (0);
643#endif
644
645 memcpy (&toSend[1], send_context->message, send_context->message_size);
646
647#if DEBUG_DV
648 memcpy (&shortname, GNUNET_i2s (send_context->distant_peer), 4);
649 shortname[4] = '\0';
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "%s: Notifying core of send to destination `%s' via `%s' size %u\n",
652 "DV", &shortname, GNUNET_i2s (recipient), msg_size);
653#endif
654
655 GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail,
656 core_pending_tail, pending_message);
657
658 GNUNET_SCHEDULER_add_now (try_core_send, NULL);
659
660 return GNUNET_YES;
661}
662
663/**
664 * Given a FindLeastCostContext, and a set
665 * of peers that match the target, return the cheapest.
666 *
667 * @param cls closure, a struct FindLeastCostContext
668 * @param key the key identifying the target peer
669 * @param value the target peer
670 *
671 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
672 */
673static int
674find_least_cost_peer (void *cls, const struct GNUNET_HashCode * key, void *value)
675{
676 struct FindLeastCostContext *find_context = cls;
677 struct DistantNeighbor *dn = value;
678
679 if (dn->cost < find_context->least_cost)
680 {
681 find_context->target = dn;
682 }
683 if (dn->cost == DIRECT_NEIGHBOR_COST)
684 return GNUNET_NO;
685 return GNUNET_YES;
686}
687
688/**
689 * Send a DV data message via DV.
690 *
691 * @param recipient the ultimate recipient of this message
692 * @param sender the original sender of the message
693 * @param specific_neighbor the specific neighbor to send this message via
694 * @param message the packed message
695 * @param message_size size of the message
696 * @param importance what priority to send this message with
697 * @param uid the unique identifier of this message (or 0 for none)
698 * @param timeout how long to possibly delay sending this message
699 */
700static int
701send_message (const struct GNUNET_PeerIdentity *recipient,
702 const struct GNUNET_PeerIdentity *sender,
703 const struct DistantNeighbor *specific_neighbor,
704 const struct GNUNET_MessageHeader *message, size_t message_size,
705 unsigned int importance, unsigned int uid,
706 struct GNUNET_TIME_Relative timeout)
707{
708 p2p_dv_MESSAGE_Data *toSend;
709 unsigned int msg_size;
710 unsigned int cost;
711 unsigned int recipient_id;
712 unsigned int sender_id;
713 struct DistantNeighbor *target;
714 struct DistantNeighbor *source;
715 struct PendingMessage *pending_message;
716 struct FindLeastCostContext find_least_ctx;
717
718#if DEBUG_DV_PEER_NUMBERS
719 struct GNUNET_CRYPTO_HashAsciiEncoded encPeerFrom;
720 struct GNUNET_CRYPTO_HashAsciiEncoded encPeerTo;
721 struct GNUNET_CRYPTO_HashAsciiEncoded encPeerVia;
722#endif
723 msg_size = message_size + sizeof (p2p_dv_MESSAGE_Data);
724
725 find_least_ctx.least_cost = -1;
726 find_least_ctx.target = NULL;
727 /*
728 * Need to find the least cost peer, lest the transport selection keep
729 * picking the same DV route for the same destination which results
730 * in messages looping forever. Relatively cheap, we don't iterate
731 * over all known peers, just those that apply.
732 */
733 GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors,
734 &recipient->hashPubKey,
735 &find_least_cost_peer,
736 &find_least_ctx);
737 target = find_least_ctx.target;
738
739 if (target == NULL)
740 {
741 /* target unknown to us, drop! */
742 return GNUNET_SYSERR;
743 }
744 recipient_id = target->referrer_id;
745
746 source =
747 GNUNET_CONTAINER_multihashmap_get (extended_neighbors,
748 &sender->hashPubKey);
749 if (source == NULL)
750 {
751 if (0 !=
752 (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity))))
753 {
754 /* sender unknown to us, drop! */
755 return GNUNET_SYSERR;
756 }
757 sender_id = 0; /* 0 == us */
758 }
759 else
760 {
761 /* find out the number that we use when we gossip about
762 * the sender */
763 sender_id = source->our_id;
764 }
765
766#if DEBUG_DV_PEER_NUMBERS
767 GNUNET_CRYPTO_hash_to_enc (&source->identity.hashPubKey, &encPeerFrom);
768 GNUNET_CRYPTO_hash_to_enc (&target->referrer->identity.hashPubKey,
769 &encPeerVia);
770 encPeerFrom.encoding[4] = '\0';
771 encPeerVia.encoding[4] = '\0';
772#endif
773 if ((sender_id != 0) &&
774 (0 ==
775 memcmp (&source->identity, &target->referrer->identity,
776 sizeof (struct GNUNET_PeerIdentity))))
777 {
778 return 0;
779 }
780
781 cost = target->cost;
782 pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
783 pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
784 pending_message->send_result = NULL;
785 pending_message->importance = importance;
786 pending_message->timeout = timeout;
787 memcpy (&pending_message->recipient, &target->referrer->identity,
788 sizeof (struct GNUNET_PeerIdentity));
789 pending_message->msg_size = msg_size;
790 toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg;
791 toSend->header.size = htons (msg_size);
792 toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
793 toSend->sender = htonl (sender_id);
794 toSend->recipient = htonl (recipient_id);
795#if DEBUG_DV_MESSAGES
796 toSend->uid = htonl (uid);
797#else
798 toSend->uid = htonl (0);
799#endif
800
801#if DEBUG_DV_PEER_NUMBERS
802 GNUNET_CRYPTO_hash_to_enc (&target->identity.hashPubKey, &encPeerTo);
803 encPeerTo.encoding[4] = '\0';
804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
805 "%s: Sending DATA message. Sender id %u, source %s, destination %s, via %s\n",
806 GNUNET_i2s (&my_identity), sender_id, &encPeerFrom, &encPeerTo,
807 &encPeerVia);
808#endif
809 memcpy (&toSend[1], message, message_size);
810 if ((source != NULL) && (source->pkey == NULL)) /* Test our hypothesis about message failures! */
811 {
812 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
813 "%s: Sending message, but anticipate recipient will not know sender!!!\n\n\n",
814 my_short_id);
815 }
816 GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail,
817 core_pending_tail, pending_message);
818#if DEBUG_DV
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "%s: Notifying core of send size %d to destination `%s'\n",
821 "DV SEND MESSAGE", msg_size, GNUNET_i2s (recipient));
822#endif
823
824 GNUNET_SCHEDULER_add_now (try_core_send, NULL);
825 return (int) cost;
826}
827
828#if USE_PEER_ID
829struct CheckPeerContext
830{
831 /**
832 * Peer we found
833 */
834 struct DistantNeighbor *peer;
835
836 /**
837 * Sender id to search for
838 */
839 unsigned int sender_id;
840};
841
842/**
843 * Iterator over hash map entries.
844 *
845 * @param cls closure
846 * @param key current key code
847 * @param value value in the hash map
848 * @return GNUNET_YES if we should continue to
849 * iterate,
850 * GNUNET_NO if not.
851 */
852int
853checkPeerID (void *cls, const struct GNUNET_HashCode * key, void *value)
854{
855 struct CheckPeerContext *ctx = cls;
856 struct DistantNeighbor *distant = value;
857
858 if (memcmp (key, &ctx->sender_id, sizeof (unsigned int)) == 0)
859 {
860 ctx->peer = distant;
861 return GNUNET_NO;
862 }
863 return GNUNET_YES;
864
865}
866#endif
867
868
869/**
870 * Handler for messages parsed out by the tokenizer from
871 * DV DATA received for this peer.
872 *
873 * @param cls NULL
874 * @param client the TokenizedMessageContext which contains message information
875 * @param message the actual message
876 */
877int
878tokenized_message_handler (void *cls, void *client,
879 const struct GNUNET_MessageHeader *message)
880{
881 struct TokenizedMessageContext *ctx = client;
882
883 GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
884 GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
885 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
886 (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA))
887 {
888#if DEBUG_DV_MESSAGES
889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
890 "%s: Receives %s message for me, uid %u, size %d, type %d cost %u from %s!\n",
891 my_short_id, "DV DATA", ctx->uid, ntohs (message->size),
892 ntohs (message->type), ctx->distant->cost,
893 GNUNET_i2s (&ctx->distant->identity));
894#endif
895 GNUNET_assert (memcmp
896 (ctx->peer, &ctx->distant->identity,
897 sizeof (struct GNUNET_PeerIdentity)) != 0);
898 send_to_plugin (ctx->peer, message, ntohs (message->size),
899 &ctx->distant->identity, ctx->distant->cost);
900 }
901 return GNUNET_OK;
902}
903
904#if DELAY_FORWARDS
905struct DelayedMessageContext
906{
907 struct GNUNET_PeerIdentity dest;
908 struct GNUNET_PeerIdentity sender;
909 struct GNUNET_MessageHeader *message;
910 size_t message_size;
911 uint32_t uid;
912};
913
914void
915send_message_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
916{
917 struct DelayedMessageContext *msg_ctx = cls;
918
919 if (msg_ctx != NULL)
920 {
921 send_message (&msg_ctx->dest, &msg_ctx->sender, NULL, msg_ctx->message,
922 msg_ctx->message_size, default_dv_priority, msg_ctx->uid,
923 GNUNET_TIME_UNIT_FOREVER_REL);
924 GNUNET_free (msg_ctx->message);
925 GNUNET_free (msg_ctx);
926 }
927}
928#endif
929
930/**
931 * Find latency information in 'atsi'.
932 *
933 * @param atsi performance data
934 * @param atsi_count number of entries in atsi
935 * @return connection latency
936 */
937static struct GNUNET_TIME_Relative
938get_atsi_latency (const struct GNUNET_ATS_Information *atsi,
939 unsigned int atsi_count)
940{
941 unsigned int i;
942
943 for (i = 0; i < atsi_count; i++)
944 if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DELAY)
945 return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
946 ntohl (atsi->value));
947 GNUNET_break (0);
948 /* how can we not have latency data? */
949 return GNUNET_TIME_UNIT_SECONDS;
950}
951
952
953#if DEBUG_DV
954/**
955 * Iterator over hash map entries.
956 *
957 * @param cls closure (NULL)
958 * @param key current key code
959 * @param value value in the hash map (DistantNeighbor)
960 * @return GNUNET_YES if we should continue to
961 * iterate,
962 * GNUNET_NO if not.
963 */
964int
965print_neighbors (void *cls, const struct GNUNET_HashCode * key, void *abs_value)
966{
967 struct DistantNeighbor *distant_neighbor = abs_value;
968 char my_shortname[5];
969 char referrer_shortname[5];
970
971 memcpy (&my_shortname, GNUNET_i2s (&my_identity), 4);
972 my_shortname[4] = '\0';
973 memcpy (&referrer_shortname,
974 GNUNET_i2s (&distant_neighbor->referrer->identity), 4);
975 referrer_shortname[4] = '\0';
976
977 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
978 "`%s' %s: Peer `%s', distance %d, referrer `%s' pkey: %s\n",
979 &my_shortname, "DV", GNUNET_i2s (&distant_neighbor->identity),
980 distant_neighbor->cost, &referrer_shortname,
981 distant_neighbor->pkey == NULL ? "no" : "yes");
982 return GNUNET_YES;
983}
984#endif
985
986/**
987 * Scheduled task which gossips about known direct peers to other connected
988 * peers. Will run until called with reason shutdown.
989 */
990static void
991neighbor_send_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
992{
993 struct NeighborSendContext *send_context = cls;
994
995#if DEBUG_DV_GOSSIP_SEND
996 char *encPeerAbout;
997 char *encPeerTo;
998#endif
999 struct DistantNeighbor *about;
1000 struct DirectNeighbor *to;
1001 struct FastGossipNeighborList *about_list;
1002
1003 p2p_dv_MESSAGE_NeighborInfo *message;
1004 struct PendingMessage *pending_message;
1005
1006 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
1007 {
1008#if DEBUG_DV_GOSSIP
1009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010 "%s: Called with reason shutdown, shutting down!\n",
1011 GNUNET_i2s (&my_identity));
1012#endif
1013 return;
1014 }
1015
1016 if (send_context->fast_gossip_list_head != NULL)
1017 {
1018 about_list = send_context->fast_gossip_list_head;
1019 about = about_list->about;
1020 GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head,
1021 send_context->fast_gossip_list_tail,
1022 about_list);
1023 GNUNET_free (about_list);
1024 }
1025 else
1026 {
1027 /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means
1028 * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
1029 * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
1030 * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
1031 * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk
1032 * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap
1033 * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
1034 * in the mean time that becomes nasty. For now we'll just assume that the walking is done
1035 * asynchronously enough to avoid major problems (-;
1036 *
1037 * NOTE: probably fixed once we decided send rate based on allowed bandwidth.
1038 */
1039 about = GNUNET_CONTAINER_heap_walk_get_next (neighbor_min_heap);
1040 }
1041 to = send_context->toNeighbor;
1042
1043 if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
1044#if SUPPORT_HIDING
1045 (about->hidden == GNUNET_NO) &&
1046#endif
1047 (to != NULL) &&
1048 (0 !=
1049 memcmp (&about->identity, &to->identity,
1050 sizeof (struct GNUNET_PeerIdentity))) && (about->pkey != NULL))
1051 {
1052#if DEBUG_DV_GOSSIP_SEND
1053 encPeerAbout = GNUNET_strdup (GNUNET_i2s (&about->identity));
1054 encPeerTo = GNUNET_strdup (GNUNET_i2s (&to->identity));
1055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1056 "%s: Sending info about peer %s id %u to directly connected peer %s\n",
1057 GNUNET_i2s (&my_identity), encPeerAbout, about->our_id,
1058 encPeerTo);
1059 GNUNET_free (encPeerAbout);
1060 GNUNET_free (encPeerTo);
1061#endif
1062 about->last_gossip = GNUNET_TIME_absolute_get ();
1063 pending_message =
1064 GNUNET_malloc (sizeof (struct PendingMessage) +
1065 sizeof (p2p_dv_MESSAGE_NeighborInfo));
1066 pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
1067 pending_message->importance = default_dv_priority;
1068 pending_message->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1069 memcpy (&pending_message->recipient, &to->identity,
1070 sizeof (struct GNUNET_PeerIdentity));
1071 pending_message->msg_size = sizeof (p2p_dv_MESSAGE_NeighborInfo);
1072 message = (p2p_dv_MESSAGE_NeighborInfo *) pending_message->msg;
1073 message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
1074 message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
1075 message->cost = htonl (about->cost);
1076 message->neighbor_id = htonl (about->our_id);
1077
1078 memcpy (&message->pkey, about->pkey,
1079 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
1080 memcpy (&message->neighbor, &about->identity,
1081 sizeof (struct GNUNET_PeerIdentity));
1082
1083 GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail,
1084 core_pending_tail, pending_message);
1085
1086 GNUNET_SCHEDULER_add_now (try_core_send, NULL);
1087 /*if (core_transmit_handle == NULL)
1088 * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_UNIT_FOREVER_REL, &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); */
1089
1090 }
1091
1092 if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */
1093 {
1094#if DEBUG_DV_PEER_NUMBERS
1095 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1096 "DV SERVICE: still in fast send mode\n");
1097#endif
1098 send_context->task =
1099 GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context);
1100 }
1101 else
1102 {
1103#if DEBUG_DV_PEER_NUMBERS
1104 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1105 "DV SERVICE: entering slow send mode\n");
1106#endif
1107 send_context->task =
1108 GNUNET_SCHEDULER_add_delayed (GNUNET_DV_DEFAULT_SEND_INTERVAL,
1109 &neighbor_send_task, send_context);
1110 }
1111
1112 return;
1113}
1114
1115
1116
1117#if UNSIMPLER
1118/**
1119 * Iterate over hash map entries for a distant neighbor,
1120 * if direct neighbor matches context call send message
1121 *
1122 * @param cls closure, a DV_SendContext
1123 * @param key current key code
1124 * @param value value in the hash map
1125 * @return GNUNET_YES if we should continue to
1126 * iterate,
1127 * GNUNET_NO if not.
1128 */
1129int
1130send_iterator (void *cls, const struct GNUNET_HashCode * key, void *abs_value)
1131{
1132 struct DV_SendContext *send_context = cls;
1133 struct DistantNeighbor *distant_neighbor = abs_value;
1134
1135 if (memcmp (distant_neighbor->referrer, send_context->direct_peer, sizeof (struct GNUNET_PeerIdentity)) == 0) /* They match, send and free */
1136 {
1137 send_message_via (&my_identity, distant_neighbor, send_context);
1138 return GNUNET_NO;
1139 }
1140 return GNUNET_YES;
1141}
1142#endif
1143
1144
1145/** Forward declarations **/
1146static int
1147handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer,
1148 const struct GNUNET_MessageHeader *message,
1149 const struct GNUNET_ATS_Information *atsi,
1150 unsigned int atsi_count);
1151
1152static int
1153handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer,
1154 const struct GNUNET_MessageHeader *message,
1155 const struct GNUNET_ATS_Information *atsi,
1156 unsigned int atsi_count);
1157/** End forward declarations **/
1158
1159
1160/**
1161 * Free a DistantNeighbor node, including removing it
1162 * from the referer's list.
1163 */
1164static void
1165distant_neighbor_free (struct DistantNeighbor *referee)
1166{
1167 struct DirectNeighbor *referrer;
1168
1169 referrer = referee->referrer;
1170 if (referrer != NULL)
1171 {
1172 GNUNET_CONTAINER_DLL_remove (referrer->referee_head, referrer->referee_tail,
1173 referee);
1174 }
1175 GNUNET_CONTAINER_heap_remove_node (referee->max_loc);
1176 GNUNET_CONTAINER_heap_remove_node (referee->min_loc);
1177 GNUNET_CONTAINER_multihashmap_remove_all (extended_neighbors,
1178 &referee->identity.hashPubKey);
1179 GNUNET_free_non_null (referee->pkey);
1180 GNUNET_free (referee);
1181}
1182
1183/**
1184 * Free a DirectNeighbor node, including removing it
1185 * from the referer's list.
1186 */
1187static void
1188direct_neighbor_free (struct DirectNeighbor *direct)
1189{
1190 struct NeighborSendContext *send_context;
1191 struct FastGossipNeighborList *about_list;
1192 struct FastGossipNeighborList *prev_about;
1193
1194 send_context = direct->send_context;
1195
1196 if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
1197 GNUNET_SCHEDULER_cancel (send_context->task);
1198
1199 about_list = send_context->fast_gossip_list_head;
1200 while (about_list != NULL)
1201 {
1202 GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head,
1203 send_context->fast_gossip_list_tail,
1204 about_list);
1205 prev_about = about_list;
1206 about_list = about_list->next;
1207 GNUNET_free (prev_about);
1208 }
1209 GNUNET_free (send_context);
1210 GNUNET_free (direct);
1211}
1212
1213/**
1214 * Multihashmap iterator for sending out disconnect messages
1215 * for a peer.
1216 *
1217 * @param cls the peer that was disconnected
1218 * @param key key value stored under
1219 * @param value the direct neighbor to send disconnect to
1220 *
1221 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1222 */
1223static int
1224schedule_disconnect_messages (void *cls, const struct GNUNET_HashCode * key,
1225 void *value)
1226{
1227 struct DisconnectContext *disconnect_context = cls;
1228 struct DirectNeighbor *disconnected = disconnect_context->direct;
1229 struct DirectNeighbor *notify = value;
1230 struct PendingMessage *pending_message;
1231 p2p_dv_MESSAGE_Disconnect *disconnect_message;
1232
1233 if (memcmp
1234 (&notify->identity, &disconnected->identity,
1235 sizeof (struct GNUNET_PeerIdentity)) == 0)
1236 return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */
1237
1238 pending_message =
1239 GNUNET_malloc (sizeof (struct PendingMessage) +
1240 sizeof (p2p_dv_MESSAGE_Disconnect));
1241 pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
1242 pending_message->importance = default_dv_priority;
1243 pending_message->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1244 memcpy (&pending_message->recipient, &notify->identity,
1245 sizeof (struct GNUNET_PeerIdentity));
1246 pending_message->msg_size = sizeof (p2p_dv_MESSAGE_Disconnect);
1247 disconnect_message = (p2p_dv_MESSAGE_Disconnect *) pending_message->msg;
1248 disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect));
1249 disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
1250 disconnect_message->peer_id = htonl (disconnect_context->distant->our_id);
1251
1252 GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail,
1253 core_pending_tail, pending_message);
1254
1255 GNUNET_SCHEDULER_add_now (try_core_send, NULL);
1256 /*if (core_transmit_handle == NULL)
1257 * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_UNIT_FOREVER_REL, &notify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL); */
1258
1259 return GNUNET_YES;
1260}
1261
1262
1263#if PKEY_NO_NEIGHBOR_ON_ADD
1264/**
1265 * Iterator over hash map entries.
1266 *
1267 * @param cls closure
1268 * @param key current key code
1269 * @param value value in the hash map
1270 * @return GNUNET_YES if we should continue to
1271 * iterate,
1272 * GNUNET_NO if not.
1273 */
1274static int
1275add_pkey_to_extended (void *cls, const struct GNUNET_HashCode * key, void *abs_value)
1276{
1277 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pkey = cls;
1278 struct DistantNeighbor *distant_neighbor = abs_value;
1279
1280 if (distant_neighbor->pkey == NULL)
1281 {
1282 distant_neighbor->pkey =
1283 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
1284 memcpy (distant_neighbor->pkey, pkey,
1285 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
1286 }
1287
1288 return GNUNET_YES;
1289}
1290#endif
1291
1292/**
1293 * Iterator over hash map entries.
1294 *
1295 * @param cls closure
1296 * @param key current key code
1297 * @param value value in the hash map
1298 * @return GNUNET_YES if we should continue to
1299 * iterate,
1300 * GNUNET_NO if not.
1301 */
1302static int
1303update_matching_neighbors (void *cls, const struct GNUNET_HashCode * key, void *value)
1304{
1305 struct NeighborUpdateInfo *update_info = cls;
1306 struct DistantNeighbor *distant_neighbor = value;
1307
1308 if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */
1309 {
1310 /* same referrer, cost change! */
1311 GNUNET_CONTAINER_heap_update_cost (neighbor_max_heap,
1312 update_info->neighbor->max_loc,
1313 update_info->cost);
1314 GNUNET_CONTAINER_heap_update_cost (neighbor_min_heap,
1315 update_info->neighbor->min_loc,
1316 update_info->cost);
1317 update_info->neighbor->last_activity = update_info->now;
1318 update_info->neighbor->cost = update_info->cost;
1319 update_info->neighbor->referrer_id = update_info->referrer_peer_id;
1320 return GNUNET_NO;
1321 }
1322
1323 return GNUNET_YES;
1324}
1325
1326
1327/**
1328 * Iterate over all current direct peers, add DISTANT newly connected
1329 * peer to the fast gossip list for that peer so we get DV routing
1330 * information out as fast as possible!
1331 *
1332 * @param cls the newly connected neighbor we will gossip about
1333 * @param key the hashcode of the peer
1334 * @param value the direct neighbor we should gossip to
1335 *
1336 * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
1337 */
1338static int
1339add_distant_all_direct_neighbors (void *cls, const struct GNUNET_HashCode * key,
1340 void *value)
1341{
1342 struct DirectNeighbor *direct = (struct DirectNeighbor *) value;
1343 struct DistantNeighbor *distant = (struct DistantNeighbor *) cls;
1344 struct NeighborSendContext *send_context = direct->send_context;
1345 struct FastGossipNeighborList *gossip_entry;
1346
1347#if DEBUG_DV
1348 char *encPeerAbout;
1349 char *encPeerTo;
1350#endif
1351
1352 if (distant == NULL)
1353 {
1354 return GNUNET_YES;
1355 }
1356
1357 if (memcmp
1358 (&direct->identity, &distant->identity,
1359 sizeof (struct GNUNET_PeerIdentity)) == 0)
1360 {
1361 return GNUNET_YES; /* Don't gossip to a peer about itself! */
1362 }
1363
1364#if SUPPORT_HIDING
1365 if (distant->hidden == GNUNET_YES)
1366 return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
1367#endif
1368 gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList));
1369 gossip_entry->about = distant;
1370
1371 GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head,
1372 send_context->fast_gossip_list_tail,
1373 send_context->fast_gossip_list_tail,
1374 gossip_entry);
1375#if DEBUG_DV
1376 encPeerAbout = GNUNET_strdup (GNUNET_i2s (&distant->identity));
1377 encPeerTo = GNUNET_strdup (GNUNET_i2s (&direct->identity));
1378
1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380 "%s: Fast send info about peer %s id %u for directly connected peer %s\n",
1381 GNUNET_i2s (&my_identity), encPeerAbout, distant->our_id,
1382 encPeerTo);
1383 GNUNET_free (encPeerAbout);
1384 GNUNET_free (encPeerTo);
1385#endif
1386 /*if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
1387 * GNUNET_SCHEDULER_cancel(send_context->task); */
1388
1389 send_context->task =
1390 GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context);
1391 return GNUNET_YES;
1392}
1393
1394/**
1395 * Callback for hello address creation.
1396 *
1397 * @param cls closure, a struct HelloContext
1398 * @param max maximum number of bytes that can be written to buf
1399 * @param buf where to write the address information
1400 *
1401 * @return number of bytes written, 0 to signal the
1402 * end of the iteration.
1403 */
1404static size_t
1405generate_hello_address (void *cls, size_t max, void *buf)
1406{
1407 struct HelloContext *hello_context = cls;
1408 struct GNUNET_HELLO_Address hello_address;
1409 char *addr_buffer;
1410 size_t offset;
1411 size_t size;
1412 size_t ret;
1413
1414 if (hello_context->addresses_to_add == 0)
1415 return 0;
1416
1417 /* Hello "address" will be concatenation of distant peer and direct peer identities */
1418 size = 2 * sizeof (struct GNUNET_PeerIdentity);
1419 GNUNET_assert (max >= size);
1420
1421 addr_buffer = GNUNET_malloc (size);
1422 offset = 0;
1423 /* Copy the distant peer identity to buffer */
1424 memcpy (addr_buffer, &hello_context->distant_peer,
1425 sizeof (struct GNUNET_PeerIdentity));
1426 offset += sizeof (struct GNUNET_PeerIdentity);
1427 /* Copy the direct peer identity to buffer */
1428 memcpy (&addr_buffer[offset], hello_context->direct_peer,
1429 sizeof (struct GNUNET_PeerIdentity));
1430 memset (&hello_address.peer, 0, sizeof (struct GNUNET_PeerIdentity));
1431 hello_address.address = addr_buffer;
1432 hello_address.transport_name = "dv";
1433 hello_address.address_length = size;
1434 ret =
1435 GNUNET_HELLO_add_address (&hello_address,
1436 GNUNET_TIME_relative_to_absolute
1437 (GNUNET_TIME_UNIT_HOURS), buf, max);
1438
1439 hello_context->addresses_to_add--;
1440
1441 GNUNET_free (addr_buffer);
1442 return ret;
1443}
1444
1445
1446/**
1447 * Handles when a peer is either added due to being newly connected
1448 * or having been gossiped about, also called when the cost for a neighbor
1449 * needs to be updated.
1450 *
1451 * @param peer identity of the peer whose info is being added/updated
1452 * @param pkey public key of the peer whose info is being added/updated
1453 * @param referrer_peer_id id to use when sending to 'peer'
1454 * @param referrer if this is a gossiped peer, who did we hear it from?
1455 * @param cost the cost of communicating with this peer via 'referrer'
1456 *
1457 * @return the added neighbor, the updated neighbor or NULL (neighbor
1458 * not added)
1459 */
1460static struct DistantNeighbor *
1461addUpdateNeighbor (const struct GNUNET_PeerIdentity *peer,
1462 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pkey,
1463 unsigned int referrer_peer_id,
1464 struct DirectNeighbor *referrer, unsigned int cost)
1465{
1466 struct DistantNeighbor *neighbor;
1467 struct DistantNeighbor *max;
1468 struct GNUNET_TIME_Absolute now;
1469 struct NeighborUpdateInfo *neighbor_update;
1470 struct HelloContext *hello_context;
1471 struct GNUNET_HELLO_Message *hello_msg;
1472 unsigned int our_id;
1473 char *addr1;
1474 char *addr2;
1475 int i;
1476
1477#if DEBUG_DV_PEER_NUMBERS
1478 char *encAbout;
1479
1480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s Received sender id (%u)!\n",
1481 "DV SERVICE", referrer_peer_id);
1482#endif
1483
1484 now = GNUNET_TIME_absolute_get ();
1485 neighbor =
1486 GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey);
1487 neighbor_update = GNUNET_malloc (sizeof (struct NeighborUpdateInfo));
1488 neighbor_update->neighbor = neighbor;
1489 neighbor_update->cost = cost;
1490 neighbor_update->now = now;
1491 neighbor_update->referrer = referrer;
1492 neighbor_update->referrer_peer_id = referrer_peer_id;
1493
1494 if (neighbor != NULL)
1495 {
1496#if USE_PEER_ID
1497 memcpy (&our_id, &neighbor->identity, sizeof (unsigned int));
1498#else
1499 our_id = neighbor->our_id;
1500#endif
1501 }
1502 else
1503 {
1504#if USE_PEER_ID
1505 memcpy (&our_id, peer, sizeof (unsigned int));
1506#else
1507 our_id =
1508 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
1509 RAND_MAX - 1) + 1;
1510#endif
1511 }
1512
1513 /* Either we do not know this peer, or we already do but via a different immediate peer */
1514 if ((neighbor == NULL) ||
1515 (GNUNET_CONTAINER_multihashmap_get_multiple
1516 (extended_neighbors, &peer->hashPubKey, &update_matching_neighbors,
1517 neighbor_update) != GNUNET_SYSERR))
1518 {
1519#if AT_MOST_ONE
1520 if ((neighbor != NULL) && (cost < neighbor->cost)) /* New cost is less than old, remove old */
1521 {
1522 distant_neighbor_free (neighbor);
1523 }
1524 else if (neighbor != NULL) /* Only allow one DV connection to each peer */
1525 {
1526 return NULL;
1527 }
1528#endif
1529 /* new neighbor! */
1530 if (cost > fisheye_depth)
1531 {
1532 /* too costly */
1533 GNUNET_free (neighbor_update);
1534 return NULL;
1535 }
1536
1537#if DEBUG_DV_PEER_NUMBERS
1538 encAbout = GNUNET_strdup (GNUNET_i2s (peer));
1539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1540 "%s: %s Chose NEW id (%u) for peer %s!\n",
1541 GNUNET_i2s (&my_identity), "DV SERVICE", our_id, encAbout);
1542 GNUNET_free (encAbout);
1543#endif
1544
1545 if (max_table_size <=
1546 GNUNET_CONTAINER_multihashmap_size (extended_neighbors))
1547 {
1548 /* remove most expensive entry */
1549 max = GNUNET_CONTAINER_heap_peek (neighbor_max_heap);
1550 GNUNET_assert (max != NULL);
1551 if (cost > max->cost)
1552 {
1553 /* new entry most expensive, don't create */
1554 GNUNET_free (neighbor_update);
1555 return NULL;
1556 }
1557 if (max->cost > 1)
1558 {
1559 /* only free if this is not a direct connection;
1560 * we could theoretically have more direct
1561 * connections than DV entries allowed total! */
1562 distant_neighbor_free (max);
1563 }
1564 }
1565
1566 neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
1567 GNUNET_CONTAINER_DLL_insert (referrer->referee_head, referrer->referee_tail,
1568 neighbor);
1569 neighbor->max_loc =
1570 GNUNET_CONTAINER_heap_insert (neighbor_max_heap, neighbor, cost);
1571 neighbor->min_loc =
1572 GNUNET_CONTAINER_heap_insert (neighbor_min_heap, neighbor, cost);
1573 neighbor->referrer = referrer;
1574 memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1575 if (pkey != NULL) /* pkey will be null on direct neighbor addition */
1576 {
1577 neighbor->pkey =
1578 GNUNET_malloc (sizeof
1579 (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
1580 memcpy (neighbor->pkey, pkey,
1581 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
1582 }
1583 else
1584 neighbor->pkey = pkey;
1585
1586 neighbor->last_activity = now;
1587 neighbor->cost = cost;
1588 neighbor->referrer_id = referrer_peer_id;
1589 neighbor->our_id = our_id;
1590 neighbor->hidden =
1591 (cost ==
1592 DIRECT_NEIGHBOR_COST)
1593 ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1594 0) : GNUNET_NO;
1595
1596 GNUNET_CONTAINER_multihashmap_put (extended_neighbors, &peer->hashPubKey,
1597 neighbor,
1598 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1599 if (referrer_peer_id != 0)
1600 {
1601 for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++)
1602 {
1603 if (referrer->pending_messages[i].sender_id == referrer_peer_id) /* We have a queued message from just learned about peer! */
1604 {
1605#if DEBUG_DV_MESSAGES
1606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1607 "%s: learned about peer %llu from which we have a previous unknown message, processing!\n",
1608 my_short_id, referrer_peer_id);
1609#endif
1610 struct GNUNET_ATS_Information atsi[2];
1611
1612 atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
1613 atsi[0].value = htonl (referrer->pending_messages[i].distance);
1614 atsi[1].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
1615 atsi[1].value =
1616 htonl ((uint32_t) referrer->pending_messages[i].
1617 latency.rel_value);
1618 handle_dv_data_message (NULL, &referrer->pending_messages[i].sender,
1619 referrer->pending_messages[i].message, atsi,
1620 2);
1621 GNUNET_free (referrer->pending_messages[i].message);
1622 referrer->pending_messages[i].sender_id = 0;
1623 }
1624 }
1625 }
1626 if ((cost != DIRECT_NEIGHBOR_COST) && (neighbor->pkey != NULL))
1627 {
1628 /* Added neighbor, now send HELLO to transport */
1629 hello_context = GNUNET_malloc (sizeof (struct HelloContext));
1630 hello_context->direct_peer = &referrer->identity;
1631 memcpy (&hello_context->distant_peer, peer,
1632 sizeof (struct GNUNET_PeerIdentity));
1633 hello_context->addresses_to_add = 1;
1634 hello_msg =
1635 GNUNET_HELLO_create (pkey, &generate_hello_address, hello_context);
1636 GNUNET_assert (memcmp
1637 (hello_context->direct_peer, &hello_context->distant_peer,
1638 sizeof (struct GNUNET_PeerIdentity)) != 0);
1639 addr1 = GNUNET_strdup (GNUNET_i2s (hello_context->direct_peer));
1640 addr2 = GNUNET_strdup (GNUNET_i2s (&hello_context->distant_peer));
1641#if DEBUG_DV
1642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643 "%s: GIVING HELLO size %d for %s via %s to TRANSPORT\n",
1644 my_short_id, GNUNET_HELLO_size (hello_msg), addr2, addr1);
1645#endif
1646 GNUNET_free (addr1);
1647 GNUNET_free (addr2);
1648 send_to_plugin (hello_context->direct_peer,
1649 GNUNET_HELLO_get_header (hello_msg),
1650 GNUNET_HELLO_size (hello_msg),
1651 &hello_context->distant_peer, cost);
1652 GNUNET_free (hello_context);
1653 GNUNET_free (hello_msg);
1654 }
1655
1656 }
1657 else
1658 {
1659#if DEBUG_DV_GOSSIP
1660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1661 "%s: Already know peer %s distance %d, referrer id %d!\n", "dv",
1662 GNUNET_i2s (peer), cost, referrer_peer_id);
1663#endif
1664 }
1665#if DEBUG_DV
1666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Size of extended_neighbors is %d\n",
1667 "dv", GNUNET_CONTAINER_multihashmap_size (extended_neighbors));
1668#endif
1669
1670 GNUNET_free (neighbor_update);
1671 return neighbor;
1672}
1673
1674
1675/**
1676 * Core handler for dv disconnect messages. These will be used
1677 * by us to tell transport via the dv plugin that a peer can
1678 * no longer be contacted by us via a certain address. We should
1679 * then propagate these messages on, given that the distance to
1680 * the peer indicates we would have gossiped about it to others.
1681 *
1682 * @param cls closure
1683 * @param peer peer which sent the message (immediate sender)
1684 * @param message the message
1685 * @param atsi performance data
1686 * @param atsi_count number of entries in atsi
1687 */
1688static int
1689handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer,
1690 const struct GNUNET_MessageHeader *message,
1691 const struct GNUNET_ATS_Information *atsi,
1692 unsigned int atsi_count)
1693{
1694 struct DirectNeighbor *referrer;
1695 struct DistantNeighbor *distant;
1696 p2p_dv_MESSAGE_Disconnect *enc_message =
1697 (p2p_dv_MESSAGE_Disconnect *) message;
1698
1699 if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect))
1700 {
1701 return GNUNET_SYSERR; /* invalid message */
1702 }
1703
1704 referrer =
1705 GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
1706 if (referrer == NULL)
1707 return GNUNET_OK;
1708
1709 distant = referrer->referee_head;
1710 while (distant != NULL)
1711 {
1712 if (distant->referrer_id == ntohl (enc_message->peer_id))
1713 {
1714 distant_neighbor_free (distant);
1715 distant = referrer->referee_head;
1716 }
1717 else
1718 distant = distant->next;
1719 }
1720
1721 return GNUNET_OK;
1722}
1723
1724
1725/**
1726 * Iterate over all currently known peers, add them to the
1727 * fast gossip list for this peer so we get DV routing information
1728 * out as fast as possible!
1729 *
1730 * @param cls the direct neighbor we will gossip to
1731 * @param key the hashcode of the peer
1732 * @param value the distant neighbor we should add to the list
1733 *
1734 * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
1735 */
1736static int
1737add_all_extended_peers (void *cls, const struct GNUNET_HashCode * key, void *value)
1738{
1739 struct NeighborSendContext *send_context = (struct NeighborSendContext *) cls;
1740 struct DistantNeighbor *distant = (struct DistantNeighbor *) value;
1741 struct FastGossipNeighborList *gossip_entry;
1742
1743 if (memcmp
1744 (&send_context->toNeighbor->identity, &distant->identity,
1745 sizeof (struct GNUNET_PeerIdentity)) == 0)
1746 return GNUNET_YES; /* Don't gossip to a peer about itself! */
1747
1748#if SUPPORT_HIDING
1749 if (distant->hidden == GNUNET_YES)
1750 return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
1751#endif
1752 gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList));
1753 gossip_entry->about = distant;
1754
1755 GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head,
1756 send_context->fast_gossip_list_tail,
1757 send_context->fast_gossip_list_tail,
1758 gossip_entry);
1759
1760 return GNUNET_YES;
1761}
1762
1763
1764/**
1765 * Iterate over all current direct peers, add newly connected peer
1766 * to the fast gossip list for that peer so we get DV routing
1767 * information out as fast as possible!
1768 *
1769 * @param cls the newly connected neighbor we will gossip about
1770 * @param key the hashcode of the peer
1771 * @param value the direct neighbor we should gossip to
1772 *
1773 * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
1774 */
1775static int
1776add_all_direct_neighbors (void *cls, const struct GNUNET_HashCode * key, void *value)
1777{
1778 struct DirectNeighbor *direct = (struct DirectNeighbor *) value;
1779 struct DirectNeighbor *to = (struct DirectNeighbor *) cls;
1780 struct DistantNeighbor *distant;
1781 struct NeighborSendContext *send_context = direct->send_context;
1782 struct FastGossipNeighborList *gossip_entry;
1783 char *direct_id;
1784
1785
1786 distant =
1787 GNUNET_CONTAINER_multihashmap_get (extended_neighbors,
1788 &to->identity.hashPubKey);
1789 if (distant == NULL)
1790 {
1791 return GNUNET_YES;
1792 }
1793
1794 if (memcmp
1795 (&direct->identity, &to->identity,
1796 sizeof (struct GNUNET_PeerIdentity)) == 0)
1797 {
1798 return GNUNET_YES; /* Don't gossip to a peer about itself! */
1799 }
1800
1801#if SUPPORT_HIDING
1802 if (distant->hidden == GNUNET_YES)
1803 return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
1804#endif
1805 direct_id = GNUNET_strdup (GNUNET_i2s (&direct->identity));
1806#if DEBUG_DV_GOSSIP
1807 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1808 "%s: adding peer %s to fast send list for %s\n", my_short_id,
1809 GNUNET_i2s (&distant->identity), direct_id);
1810#endif
1811 GNUNET_free (direct_id);
1812 gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList));
1813 gossip_entry->about = distant;
1814
1815 GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head,
1816 send_context->fast_gossip_list_tail,
1817 send_context->fast_gossip_list_tail,
1818 gossip_entry);
1819 if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
1820 GNUNET_SCHEDULER_cancel (send_context->task);
1821
1822 send_context->task =
1823 GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context);
1824 //tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT;
1825 //neighbor_send_task(send_context, &tc);
1826 return GNUNET_YES;
1827}
1828
1829
1830////////////////////////////////////////////////////////////////////////
1831#endif
1832
1833
1834
1835/** 559/**
1836 * Method called whenever a peer connects. 560 * Method called whenever a peer connects.
1837 * 561 *
@@ -2168,7 +892,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
2168 GNUNET_MESSAGE_TYPE_DV_START, 892 GNUNET_MESSAGE_TYPE_DV_START,
2169 sizeof (struct GNUNET_MessageHeader) }, 893 sizeof (struct GNUNET_MessageHeader) },
2170 { &handle_dv_send_message, NULL, 894 { &handle_dv_send_message, NULL,
2171 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 895 GNUNET_MESSAGE_TYPE_DV_SEND,
2172 0}, 896 0},
2173 {NULL, NULL, 0, 0} 897 {NULL, NULL, 0, 0}
2174 }; 898 };