aboutsummaryrefslogtreecommitdiff
path: root/src/peerinfo
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-01-11 22:13:37 +0000
committerChristian Grothoff <christian@grothoff.org>2010-01-11 22:13:37 +0000
commitbb4e48f94a3daba7b0294ce8760a231b0601fa11 (patch)
treec32408c3060ba0a51bf8ca031d944d478a65f866 /src/peerinfo
parentc85579b554836cd5a67e87abb3e11a2d53d6a3e8 (diff)
downloadgnunet-bb4e48f94a3daba7b0294ce8760a231b0601fa11.tar.gz
gnunet-bb4e48f94a3daba7b0294ce8760a231b0601fa11.zip
adding notification API to peerinfo
Diffstat (limited to 'src/peerinfo')
-rw-r--r--src/peerinfo/gnunet-service-peerinfo.c250
-rw-r--r--src/peerinfo/peerinfo_api.c243
2 files changed, 493 insertions, 0 deletions
diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c
index ee1287831..4323be478 100644
--- a/src/peerinfo/gnunet-service-peerinfo.c
+++ b/src/peerinfo/gnunet-service-peerinfo.c
@@ -26,6 +26,9 @@
26 * structure of data/hosts/ and data/credit/). 26 * structure of data/hosts/ and data/credit/).
27 * 27 *
28 * @author Christian Grothoff 28 * @author Christian Grothoff
29 *
30 * TODO:
31 * - HostEntries are never 'free'd (add expiration, upper bound?)
29 */ 32 */
30 33
31#include "platform.h" 34#include "platform.h"
@@ -84,12 +87,64 @@ struct HostEntry
84 87
85}; 88};
86 89
90
91/**
92 * Entries that we still need to tell the client about.
93 */
94struct PendingEntry
95{
96
97 /**
98 * This is a linked list.
99 */
100 struct PendingEntry *next;
101
102 /**
103 * Entry to tell the client about.
104 */
105 struct HostEntry *he;
106};
107
108
109/**
110 * Clients to notify of changes to the peer information.
111 */
112struct NotifyList
113{
114
115 /**
116 * This is a linked list.
117 */
118 struct NotifyList *next;
119
120 /**
121 * Client to notify.
122 */
123 struct GNUNET_SERVER_Client *client;
124
125 /**
126 * Notifications pending for this entry.
127 */
128 struct PendingEntry *pending;
129
130 /**
131 * Handle for a transmit ready request.
132 */
133 struct GNUNET_CONNECTION_TransmitHandle *transmit_ctx;
134};
135
136
87/** 137/**
88 * The in-memory list of known hosts. 138 * The in-memory list of known hosts.
89 */ 139 */
90static struct HostEntry *hosts; 140static struct HostEntry *hosts;
91 141
92/** 142/**
143 * Clients to immediately notify about all changes.
144 */
145static struct NotifyList *notify_list;
146
147/**
93 * Directory where the hellos are stored in (data/hosts) 148 * Directory where the hellos are stored in (data/hosts)
94 */ 149 */
95static char *networkIdDirectory; 150static char *networkIdDirectory;
@@ -101,6 +156,116 @@ static char *trustDirectory;
101 156
102 157
103/** 158/**
159 * Transmit peer information messages from the pending queue
160 * to the client.
161 *
162 * @param cls the 'struct NotifyList' that we are processing
163 * @param size number of bytes we can transmit
164 * @param vbuf where to write the messages
165 * @return number of bytes written to vbuf
166 */
167static size_t
168transmit_pending_notification (void *cls,
169 size_t size,
170 void *vbuf)
171{
172 struct NotifyList *nl = cls;
173 char *buf = vbuf;
174 struct PendingEntry *pos;
175 struct PendingEntry *next;
176 struct InfoMessage im;
177 uint16_t hs;
178 size_t left;
179
180 nl->transmit_ctx = NULL;
181 next = nl->pending;
182 pos = nl->pending;
183 left = size;
184 while ( (pos != NULL) &&
185 (left >= sizeof (struct InfoMessage) + (hs = GNUNET_HELLO_size (pos->he->hello))) )
186 {
187 next = pos->next;
188 im.header.size = htons (hs + sizeof (struct InfoMessage));
189 im.header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
190 im.trust = htonl (pos->he->trust);
191 im.peer = pos->he->identity;
192 memcpy (&buf[size - left], &im, sizeof (struct InfoMessage));
193 memcpy (&buf[size - left + sizeof (struct InfoMessage)], pos->he->hello, hs);
194 left -= hs + sizeof (struct InfoMessage);
195 GNUNET_free (pos);
196 pos = next;
197 }
198 nl->pending = next;
199 if (nl->pending != NULL)
200 {
201 nl->transmit_ctx
202 = GNUNET_SERVER_notify_transmit_ready (nl->client,
203 sizeof (struct InfoMessage) + hs,
204 GNUNET_TIME_UNIT_FOREVER_REL,
205 &transmit_pending_notification,
206 nl);
207 }
208 return size - left;
209}
210
211
212
213/**
214 * Notify client about host change. Checks if the
215 * respective host entry is already in the list of things
216 * to send to the client, and if not, adds it. Also
217 * triggers a new request for transmission if the pending
218 * list was previously empty.
219 *
220 * @param nl client to notify
221 * @param hc entry to notify about
222 */
223static void
224do_notify (struct NotifyList *nl,
225 struct HostEntry *he)
226{
227 struct PendingEntry *pe;
228
229 pe = nl->pending;
230 while (NULL != pe)
231 {
232 if (pe->he == he)
233 return; /* already in list */
234 pe = pe->next;
235 }
236 pe = GNUNET_malloc (sizeof (struct PendingEntry));
237 pe->next = nl->pending;
238 pe->he = he;
239 nl->pending = pe;
240 if (nl->transmit_ctx != NULL)
241 return; /* already trying to transmit */
242 nl->transmit_ctx = GNUNET_SERVER_notify_transmit_ready (nl->client,
243 sizeof (struct InfoMessage) + GNUNET_HELLO_size (he->hello),
244 GNUNET_TIME_UNIT_FOREVER_REL,
245 &transmit_pending_notification,
246 nl);
247}
248
249
250/**
251 * Notify all clients in the notify list about the
252 * given host entry changing.
253 */
254static void
255notify_all (struct HostEntry *he)
256{
257 struct NotifyList *nl;
258
259 nl = notify_list;
260 while (NULL != nl)
261 {
262 do_notify (nl, he);
263 nl = nl->next;
264 }
265}
266
267
268/**
104 * Address iterator that causes expired entries to be discarded. 269 * Address iterator that causes expired entries to be discarded.
105 * 270 *
106 * @param cls pointer to the current time 271 * @param cls pointer to the current time
@@ -231,6 +396,7 @@ add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
231 GNUNET_free (fn); 396 GNUNET_free (fn);
232 entry->next = hosts; 397 entry->next = hosts;
233 hosts = entry; 398 hosts = entry;
399 notify_all (entry);
234} 400}
235 401
236 402
@@ -246,6 +412,7 @@ static int
246change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value) 412change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value)
247{ 413{
248 struct HostEntry *host; 414 struct HostEntry *host;
415 unsigned int old_trust;
249 416
250 if (value == 0) 417 if (value == 0)
251 return 0; 418 return 0;
@@ -256,6 +423,7 @@ change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value)
256 host = lookup_host_entry (hostId); 423 host = lookup_host_entry (hostId);
257 } 424 }
258 GNUNET_assert (host != NULL); 425 GNUNET_assert (host != NULL);
426 old_trust = host->trust;
259 if (value > 0) 427 if (value > 0)
260 { 428 {
261 if (host->trust + value < host->trust) 429 if (host->trust + value < host->trust)
@@ -276,6 +444,8 @@ change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value)
276 else 444 else
277 host->trust += value; 445 host->trust += value;
278 } 446 }
447 if (host->trust != old_trust)
448 notify_all (host);
279 return value; 449 return value;
280} 450}
281 451
@@ -383,6 +553,8 @@ bind_address (const struct GNUNET_PeerIdentity *peer,
383 else 553 else
384 { 554 {
385 mrg = GNUNET_HELLO_merge (host->hello, hello); 555 mrg = GNUNET_HELLO_merge (host->hello, hello);
556 /* FIXME: check if old and merged hello are equal,
557 and if so, bail out early... */
386 GNUNET_free (host->hello); 558 GNUNET_free (host->hello);
387 host->hello = mrg; 559 host->hello = mrg;
388 } 560 }
@@ -393,6 +565,7 @@ bind_address (const struct GNUNET_PeerIdentity *peer,
393 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE 565 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
394 | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ); 566 | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ);
395 GNUNET_free (fn); 567 GNUNET_free (fn);
568 notify_all (host);
396} 569}
397 570
398 571
@@ -643,6 +816,35 @@ handle_get_all (void *cls,
643 816
644 817
645/** 818/**
819 * Handle NOTIFY-message.
820 *
821 * @param cls closure
822 * @param client identification of the client
823 * @param message the actual message
824 */
825static void
826handle_notify (void *cls,
827 struct GNUNET_SERVER_Client *client,
828 const struct GNUNET_MessageHeader *message)
829{
830 struct NotifyList *nl;
831 struct HostEntry *pos;
832
833 nl = GNUNET_malloc (sizeof (struct NotifyList));
834 nl->next = notify_list;
835 nl->client = client;
836 GNUNET_SERVER_client_keep (client);
837 notify_list = nl;
838 pos = hosts;
839 while (NULL != pos)
840 {
841 do_notify (nl, pos);
842 pos = pos->next;
843 }
844}
845
846
847/**
646 * List of handlers for the messages understood by this 848 * List of handlers for the messages understood by this
647 * service. 849 * service.
648 */ 850 */
@@ -652,10 +854,57 @@ static struct GNUNET_SERVER_MessageHandler handlers[] = {
652 sizeof (struct ListPeerMessage)}, 854 sizeof (struct ListPeerMessage)},
653 {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL, 855 {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL,
654 sizeof (struct ListAllPeersMessage)}, 856 sizeof (struct ListAllPeersMessage)},
857 {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY,
858 sizeof (struct GNUNET_MessageHeader)},
655 {NULL, NULL, 0, 0} 859 {NULL, NULL, 0, 0}
656}; 860};
657 861
658 862
863/**
864 * Function that is called when a client disconnects.
865 */
866static void
867notify_disconnect (void *cls,
868 struct GNUNET_SERVER_Client *client)
869{
870 struct NotifyList *pos;
871 struct NotifyList *prev;
872 struct NotifyList *next;
873 struct PendingEntry *p;
874
875 pos = notify_list;
876 prev = NULL;
877 while (pos != NULL)
878 {
879 next = pos->next;
880 if (pos->client == client)
881 {
882 while (NULL != (p = pos->pending))
883 {
884 pos->pending = p->next;
885 GNUNET_free (p);
886 }
887 if (pos->transmit_ctx != NULL)
888 {
889 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->transmit_ctx);
890 pos->transmit_ctx = NULL;
891 }
892 if (prev == NULL)
893 notify_list = next;
894 else
895 prev->next = next;
896 GNUNET_SERVER_client_drop (client);
897 GNUNET_free (pos);
898 }
899 else
900 {
901 prev = pos;
902 }
903 pos = next;
904 }
905
906}
907
659 908
660/** 909/**
661 * Process statistics requests. 910 * Process statistics requests.
@@ -692,6 +941,7 @@ run (void *cls,
692 GNUNET_SCHEDULER_add_with_priority (sched, 941 GNUNET_SCHEDULER_add_with_priority (sched,
693 GNUNET_SCHEDULER_PRIORITY_IDLE, 942 GNUNET_SCHEDULER_PRIORITY_IDLE,
694 &cron_clean_data_hosts, NULL); 943 &cron_clean_data_hosts, NULL);
944 GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, NULL);
695 GNUNET_SERVER_add_handlers (server, handlers); 945 GNUNET_SERVER_add_handlers (server, handlers);
696} 946}
697 947
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
index b5c6c99d7..906c01d77 100644
--- a/src/peerinfo/peerinfo_api.c
+++ b/src/peerinfo/peerinfo_api.c
@@ -298,4 +298,247 @@ GNUNET_PEERINFO_for_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
298 } 298 }
299} 299}
300 300
301
302
303/**
304 * Context for the info handler.
305 */
306struct GNUNET_PEERINFO_NotifyContext
307{
308
309 /**
310 * Our connection to the PEERINFO service.
311 */
312 struct GNUNET_CLIENT_Connection *client;
313
314 /**
315 * Function to call with information.
316 */
317 GNUNET_PEERINFO_Processor callback;
318
319 /**
320 * Closure for callback.
321 */
322 void *callback_cls;
323
324 /**
325 * Handle to our initial request for message transmission to
326 * the peerinfo service.
327 */
328 struct GNUNET_CLIENT_TransmitHandle *init;
329
330 /**
331 * Configuration.
332 */
333 const struct GNUNET_CONFIGURATION_Handle *cfg;
334
335 /**
336 * Scheduler.
337 */
338 struct GNUNET_SCHEDULER_Handle *sched;
339};
340
341
342/**
343 * Send a request to the peerinfo service to start being
344 * notified about all changes to peer information.
345 *
346 * @param nc our context
347 */
348static void
349request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc);
350
351
352/**
353 * Read notifications from the client handle and pass them
354 * to the callback.
355 *
356 * @param nc our context
357 */
358static void
359receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc);
360
361
362/**
363 * Receive a peerinfo information message, process it and
364 * go for more.
365 *
366 * @param cls closure
367 * @param msg message received, NULL on timeout or fatal error
368 */
369static void
370process_notification (void *cls,
371 const struct
372 GNUNET_MessageHeader * msg)
373{
374 struct GNUNET_PEERINFO_NotifyContext *nc = cls;
375 const struct InfoMessage *im;
376 const struct GNUNET_HELLO_Message *hello;
377 uint16_t ms;
378
379 if (msg == NULL)
380 {
381 GNUNET_CLIENT_disconnect (nc->client);
382 nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
383 request_notifications (nc);
384 return;
385 }
386 ms = ntohs (msg->size);
387 if ((ms < sizeof (struct InfoMessage)) ||
388 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
389 {
390 GNUNET_break (0);
391 GNUNET_CLIENT_disconnect (nc->client);
392 nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
393 request_notifications (nc);
394 return;
395 }
396 im = (const struct InfoMessage *) msg;
397 hello = NULL;
398 if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
399 {
400 hello = (const struct GNUNET_HELLO_Message *) &im[1];
401 if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
402 {
403 GNUNET_break (0);
404 GNUNET_CLIENT_disconnect (nc->client);
405 nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
406 request_notifications (nc);
407 return;
408 }
409 }
410#if DEBUG_PEERINFO
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Received information about peer `%s' from peerinfo database\n",
413 GNUNET_i2s (&im->peer));
414#endif
415 nc->callback (nc->callback_cls, &im->peer, hello, ntohl (im->trust));
416 receive_notifications (nc);
417}
418
419
420/**
421 * Read notifications from the client handle and pass them
422 * to the callback.
423 *
424 * @param nc our context
425 */
426static void
427receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc)
428{
429 GNUNET_CLIENT_receive (nc->client,
430 &process_notification,
431 nc,
432 GNUNET_TIME_UNIT_FOREVER_REL);
433}
434
435
436/**
437 * Transmit our init-notify request, start receiving.
438 *
439 * @param cls closure (our 'struct GNUNET_PEERINFO_NotifyContext')
440 * @param size number of bytes available in buf
441 * @param buf where the callee should write the message
442 * @return number of bytes written to buf
443 */
444static size_t
445transmit_notify_request (void *cls,
446 size_t size,
447 void *buf)
448{
449 struct GNUNET_PEERINFO_NotifyContext *nc = cls;
450 struct GNUNET_MessageHeader hdr;
451
452 nc->init = NULL;
453 if (buf == NULL)
454 {
455 GNUNET_CLIENT_disconnect (nc->client);
456 nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
457 request_notifications (nc);
458 return 0;
459 }
460 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
461 hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
462 hdr.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY);
463 memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
464 receive_notifications (nc);
465 return sizeof (struct GNUNET_MessageHeader);
466}
467
468
469/**
470 * Send a request to the peerinfo service to start being
471 * notified about all changes to peer information.
472 *
473 * @param nc our context
474 */
475static void
476request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc)
477{
478 GNUNET_assert (NULL == nc->init);
479 nc->init =GNUNET_CLIENT_notify_transmit_ready (nc->client,
480 sizeof (struct GNUNET_MessageHeader),
481 GNUNET_TIME_UNIT_FOREVER_REL,
482 GNUNET_YES,
483 &transmit_notify_request,
484 nc);
485}
486
487
488/**
489 * Call a method whenever our known information about peers
490 * changes. Initially calls the given function for all known
491 * peers and then only signals changes.
492 *
493 * @param cfg configuration to use
494 * @param sched scheduler to use
495 * @param callback the method to call for each peer
496 * @param callback_cls closure for callback
497 * @return NULL on error
498 */
499struct GNUNET_PEERINFO_NotifyContext *
500GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg,
501 struct GNUNET_SCHEDULER_Handle *sched,
502 GNUNET_PEERINFO_Processor callback,
503 void *callback_cls)
504{
505 struct GNUNET_PEERINFO_NotifyContext *nc;
506 struct GNUNET_CLIENT_Connection *client;
507
508 client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
509 if (client == NULL)
510 {
511 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
512 _("Could not connect to `%s' service.\n"), "peerinfo");
513 return NULL;
514 }
515 nc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_NotifyContext));
516 nc->sched = sched;
517 nc->cfg = cfg;
518 nc->client = client;
519 nc->callback = callback;
520 nc->callback_cls = callback_cls;
521 request_notifications (nc);
522 return nc;
523}
524
525
526/**
527 * Stop notifying about changes.
528 *
529 * @param nc context to stop notifying
530 */
531void
532GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc)
533{
534 if (NULL != nc->init)
535 {
536 GNUNET_CLIENT_notify_transmit_ready_cancel (nc->init);
537 nc->init = NULL;
538 }
539 GNUNET_CLIENT_disconnect (nc->client);
540 GNUNET_free (nc);
541}
542
543
301/* end of peerinfo_api.c */ 544/* end of peerinfo_api.c */