stuff
[oweals/gnunet.git] / src / core / gnunet-service-core_clients.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file core/gnunet-service-core_clients.c
23  * @brief code for managing interactions with clients of core service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_transport_service.h"
29 #include "gnunet_service_core.h"
30 #include "gnunet_service_core_clients.h"
31 #include "gnunet_service_core_sessions.h"
32 #include "gnunet_service_core_typemap.h"
33
34
35
36 /**
37  * Data structure for each client connected to the core service.
38  */
39 struct GSC_Client
40 {
41   /**
42    * Clients are kept in a linked list.
43    */
44   struct GSC_Client *next;
45
46   /**
47    * Clients are kept in a linked list.
48    */
49   struct GSC_Client *prev;
50
51   /**
52    * Handle for the client with the server API.
53    */
54   struct GNUNET_SERVER_Client *client_handle;
55
56   /**
57    * Array of the types of messages this peer cares
58    * about (with "tcnt" entries).  Allocated as part
59    * of this client struct, do not free!
60    */
61   const uint16_t *types;
62
63   /**
64    * Map of peer identities to active transmission requests of this
65    * client to the peer (of type 'struct GSC_ClientActiveRequest').
66    */
67   struct GNUNET_CONTAINER_MultiHashMap *requests;
68
69   /**
70    * Options for messages this client cares about,
71    * see GNUNET_CORE_OPTION_ values.
72    */
73   uint32_t options;
74
75   /**
76    * Number of types of incoming messages this client
77    * specifically cares about.  Size of the "types" array.
78    */
79   unsigned int tcnt;
80
81 };
82
83
84 /**
85  * Head of linked list of our clients.
86  */
87 static struct GSC_Client *client_head;
88
89 /**
90  * Tail of linked list of our clients.
91  */
92 static struct GSC_Client *client_tail;
93
94 /**
95  * Context for notifications we need to send to our clients.
96  */
97 static struct GNUNET_SERVER_NotificationContext *notifier;
98
99 /**
100  * Tokenizer for messages received from clients.
101  */
102 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
103
104
105 /**
106  * Lookup our client struct given the server's client handle.
107  *
108  * @param client server client handle to look up
109  * @return our client handle for the client
110  */
111 static struct GSC_Client *
112 find_client (struct GNUNET_SERVER_Client *client)
113 {
114   struct GSC_Client *c;
115
116   c = client_head;
117   while ((c != NULL) && (c->client_handle != client))
118     c = c->next;
119   return c;
120 }
121
122
123 /**
124  * Send a message to one of our clients.
125  *
126  * @param client target for the message
127  * @param msg message to transmit
128  * @param can_drop could this message be dropped if the
129  *        client's queue is getting too large?
130  */
131 static void
132 send_to_client (struct GSC_Client *client, 
133                 const struct GNUNET_MessageHeader *msg,
134                 int can_drop)
135 {
136 #if DEBUG_CORE_CLIENT
137   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
138               "Preparing to send %u bytes of message of type %u to client.\n",
139               (unsigned int) ntohs (msg->size),
140               (unsigned int) ntohs (msg->type));
141 #endif
142   GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
143                                               msg, can_drop);
144 }
145
146
147 /**
148  * Test if the client is interested in messages of the given type.
149  *
150  * @param type message type
151  * @param c client to test
152  * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
153  */
154 static int
155 type_match (uint16_t type,
156             struct GSC_Client *c)
157 {
158   unsigned int i;
159
160   for (i=0;i<c->tcnt;i++)
161     if (type == c->types[i])
162       return GNUNET_YES;
163   return GNUNET_NO;
164 }
165
166
167 /**
168  * Send a message to all of our current clients that have the right
169  * options set.
170  *
171  * @param msg message to multicast
172  * @param can_drop can this message be discarded if the queue is too long
173  * @param options mask to use
174  * @param type type of the embedded message, 0 for none
175  */
176 static void
177 send_to_all_clients (const struct GNUNET_MessageHeader *msg, 
178                      int can_drop,
179                      int options,
180                      uint16_t type)
181 {
182   struct GSC_Client *c;
183
184   for (c = client_head; c != NULL; c = c->next)
185   {
186     if ( (0 == (c->options & options)) &&
187          (GNUNET_YES != type_match (type, c)) )
188       continue;
189 #if DEBUG_CORE_CLIENT > 1
190     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191                 "Sending message of type %u to client.\n",
192                 (unsigned int) ntohs (msg->type));
193 #endif
194     send_to_client (c, msg, can_drop);
195   }
196 }
197
198
199 /**
200  * Handle CORE_INIT request.
201  *
202  * @param cls unused
203  * @param client new client that sent INIT
204  * @param message the 'struct InitMessage' (presumably)
205  */
206 static void
207 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
208                     const struct GNUNET_MessageHeader *message)
209 {
210   const struct InitMessage *im;
211   struct InitReplyMessage irm;
212   struct GSC_Client *c;
213   uint16_t msize;
214   const uint16_t *types;
215   uint16_t *wtypes;
216   unsigned int i;
217
218   /* check that we don't have an entry already */
219   c = find_client (client);
220   if (NULL != c)
221   {
222     GNUNET_break (0);
223     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
224     return;
225   }
226   msize = ntohs (message->size);
227   if (msize < sizeof (struct InitMessage))
228   {
229     GNUNET_break (0);
230     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
231     return;
232   }
233   GNUNET_SERVER_notification_context_add (notifier, client);
234   im = (const struct InitMessage *) message;
235   types = (const uint16_t *) &im[1];
236   msize -= sizeof (struct InitMessage);
237   c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
238   c->client_handle = client;
239   c->tcnt = msize / sizeof (uint16_t);
240   c->options = ntohl (im->options);
241   c->types = (const uint16_t *) &c[1];
242   wtypes = (uint16_t *) & c[1];
243   for (i = 0; i < c->tcnt; i++)
244     wtypes[i] = ntohs (types[i]);
245   GSC_TYPEMAP_add (wtypes, c->tcnt);
246   GNUNET_CONTAINER_DLL_insert (client_head,
247                                client_tail,
248                                c);
249 #if DEBUG_CORE_CLIENT
250   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251               "Client connecting to core service is interested in %u message types\n", 
252               (unsigned int) c->tcnt);
253 #endif
254   /* send init reply message */
255   irm.header.size = htons (sizeof (struct InitReplyMessage));
256   irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
257   irm.reserved = htonl (0);
258   irm.publicKey = GSC_my_public_key;
259   send_to_client (c, &irm.header, GNUNET_NO);
260   if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
261     GSC_SESSIONS_notify_client_about_sessions (c);
262   GNUNET_SERVER_receive_done (client, GNUNET_OK);
263 }
264
265
266 /**
267  * Handle CORE_SEND_REQUEST message.
268  *
269  * @param cls unused
270  * @param client new client that sent CORE_SEND_REQUEST
271  * @param message the 'struct InitMessage' (presumably)
272  */
273 static void
274 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
275                             const struct GNUNET_MessageHeader *message)
276 {
277   const struct SendMessageRequest *req;
278   struct GSC_Client *c;
279   struct GSC_ClientActiveRequest *car;
280
281   req = (const struct SendMessageRequest *) message;
282   c = find_client (client);
283   if (c == NULL)
284   {
285     /* client did not send INIT first! */
286     GNUNET_break (0);
287     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
288     return;
289   }
290   if (c->requests == NULL)
291     c->requests = GNUNET_CONTAINER_multihashmap_create (16);
292   car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
293   if (car == NULL)
294   {
295     /* create new entry */
296     car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
297     GNUNET_assert (GNUNET_OK ==
298                    GNUNET_CONTAINER_multihashmap_put (c->requests,
299                                                       &req->peer.hashPubKey,
300                                                       car,
301                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
302     car->client = c;
303   }
304   car->target = req->peer;
305   GNUNET_SERVER_client_keep (client);
306   car->client_handle = client;
307   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
308   car->priority = ntohl (req->priority);
309   car->msize = ntohs (req->size);
310   car->smr_id = req->smr_id;
311   if (0 ==
312       memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
313     GSC_CLIENTS_solicit_request (car);
314   else
315     GSC_SESSIONS_queue_request (car);
316   GNUNET_SERVER_receive_done (client, GNUNET_OK);
317 }
318
319
320 /**
321  * Handle CORE_SEND request.
322  *
323  * @param cls unused
324  * @param client the client issuing the request
325  * @param message the "struct SendMessage"
326  */
327 static void
328 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
329                     const struct GNUNET_MessageHeader *message)
330 {
331   const struct SendMessage *sm;
332   struct GSC_Client *c;
333   struct GSC_ClientActiveRequest *car;
334   uint16_t msize;
335
336   msize = ntohs (message->size);
337   if (msize <
338       sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
339   {
340     GNUNET_break (0);
341     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
342     return;
343   }
344   sm = (const struct SendMessage *) message;
345   msize -= sizeof (struct SendMessage);
346   GNUNET_break (0 == ntohl (sm->reserved));
347   c = find_client (client);
348   if (c == NULL)
349   {
350     /* client did not send INIT first! */
351     GNUNET_break (0);
352     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
353     return;
354   }
355   car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
356   if (NULL == car)
357   {
358     /* client did not request transmission first! */
359     GNUNET_break (0);
360     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
361     return;
362   }
363   GNUNET_assert (GNUNET_YES ==
364                  GNUNET_CONTAINER_multihashmap_remove (c->requests, 
365                                                        &sm->peer.hashPubKey,
366                                                        car));
367   GNUNET_SERVER_mst_receive (client_mst,
368                              car, 
369                              &sm[1], msize,
370                              GNUNET_YES,
371                              GNUNET_NO);
372   if (0 !=
373       memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
374     GSC_SESSIONS_dequeue_request (car);
375   GNUNET_free (car);  
376   GNUNET_SERVER_receive_done (client, GNUNET_OK);
377 }
378
379
380 /**
381  * Functions with this signature are called whenever a complete
382  * message is received by the tokenizer.  Used by the 'client_mst' for
383  * dispatching messages from clients to either the SESSION subsystem
384  * or other CLIENT (for loopback).
385  *
386  * @param cls closure
387  * @param client reservation request ('struct GSC_ClientActiveRequest')
388  * @param message the actual message
389  */
390 static void
391 client_tokenizer_callback (void *cls, void *client,
392                            const struct GNUNET_MessageHeader *message)
393 {
394   struct GSC_ClientActiveRequest *car = client;
395
396   if (0 ==
397       memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
398     GDS_CLIENTS_deliver_message (&GSC_my_identity, &payload->header);  
399   else
400     GSC_SESSIONS_transmit (car, &payload->header);
401 }
402
403
404 /**
405  * Free client request records.
406  *
407  * @param cls NULL
408  * @param key identity of peer for which this is an active request
409  * @param value the 'struct GSC_ClientActiveRequest' to free
410  * @return GNUNET_YES (continue iteration)
411  */
412 static int
413 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
414                                void *value)
415 {
416   struct GSC_ClientActiveRequest *car = value;
417
418   GNUNET_assert (GNUNET_YES ==
419                  GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
420                                                        &car->peer,
421                                                        car);
422   GSC_SESSIONS_dequeue_request (car);
423   GNUNET_free (car);
424   return GNUNET_YES;
425 }
426
427
428 /**
429  * A client disconnected, clean up.
430  *
431  * @param cls closure
432  * @param client identification of the client
433  */
434 static void
435 handle_client_disconnect (void *cls,
436                           struct GNUNET_SERVER_Client *client)
437 {
438   struct GSC_Client *c;
439
440   if (client == NULL)
441     return;
442 #if DEBUG_CORE_CLIENT
443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444               "Client %p has disconnected from core service.\n", client);
445 #endif
446   c = find_client (client);
447   if (c == NULL)
448     return; /* client never sent INIT */
449   GNUNET_CONTAINER_DLL_remove (client_head,
450                                client_tail,
451                                c);
452   if (c->requests != NULL)
453   {
454     GNUNET_CONTAINER_multihashmap_iterate (c->requests,
455                                            &destroy_active_client_request,
456                                            NULL);
457     GNUNET_CONTAINER_multihashmap_destroy (c->requests);
458   }
459   GSC_TYPEMAP_remove (c->types, c->tcnt);
460   GNUNET_free (c);
461 }
462
463
464 /**
465  * Tell a client that we are ready to receive the message.
466  *
467  * @param car request that is now ready; the responsibility
468  *        for the handle remains shared between CLIENTS
469  *        and SESSIONS after this call.
470  */
471 void
472 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
473 {
474   struct GSC_Client *c;
475   struct SendMessageReady smr;
476
477   c = car->client;
478   smr.header.size = htons (sizeof (struct SendMessageReady));
479   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
480   smr.size = htons (car->msize);
481   smr.smr_id = car->smr_id;
482   smr.peer = n->peer;
483   send_to_client (c, &smr.header, GNUNET_NO);
484 }
485
486
487 /**
488  * Tell a client that we will never be ready to receive the
489  * given message in time (disconnect or timeout).
490  *
491  * @param car request that now permanently failed; the
492  *        responsibility for the handle is now returned
493  *        to CLIENTS (SESSIONS is done with it).
494  */
495 void
496 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
497 {
498   GNUNET_assert (GNUNET_YES ==
499                  destroy_active_client_request (NULL, &car->peer.hashPubKey, car));  
500 }
501
502
503
504 // FIXME from here.......................................
505
506
507
508
509
510
511 /**
512  * Notify client about an existing connection to one of our neighbours.
513  */
514 static int
515 notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
516                                void *value)
517 {
518   struct GSC_Client *c = cls;
519   struct Neighbour *n = value;
520   size_t size;
521   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
522   struct GNUNET_TRANSPORT_ATS_Information *ats;
523   struct ConnectNotifyMessage *cnm;
524
525   size =
526       sizeof (struct ConnectNotifyMessage) +
527       (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
528   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
529   {
530     GNUNET_break (0);
531     /* recovery strategy: throw away performance data */
532     GNUNET_array_grow (n->ats, n->ats_count, 0);
533     size =
534         sizeof (struct ConnectNotifyMessage) +
535         (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
536   }
537   cnm = (struct ConnectNotifyMessage *) buf;
538   cnm->header.size = htons (size);
539   cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
540   cnm->ats_count = htonl (n->ats_count);
541   ats = &cnm->ats;
542   memcpy (ats, n->ats,
543           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
544   ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
545   ats[n->ats_count].value = htonl (0);
546   if (n->status == PEER_STATE_KEY_CONFIRMED)
547   {
548 #if DEBUG_CORE_CLIENT
549     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
550                 "NOTIFY_CONNECT");
551 #endif
552     cnm->peer = n->peer;
553     send_to_client (c, &cnm->header, GNUNET_NO);
554   }
555   return GNUNET_OK;
556 }
557
558
559
560 /**
561  * Helper function for handle_client_iterate_peers.
562  *
563  * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
564  * @param key identity of the connected peer
565  * @param value the 'struct Neighbour' for the peer
566  * @return GNUNET_OK (continue to iterate)
567  */
568 static int
569 queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
570 {
571   struct GNUNET_SERVER_TransmitContext *tc = cls;
572   struct Neighbour *n = value;
573   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
574   struct GNUNET_TRANSPORT_ATS_Information *ats;
575   size_t size;
576   struct ConnectNotifyMessage *cnm;
577
578   cnm = (struct ConnectNotifyMessage *) buf;
579   if (n->status != PEER_STATE_KEY_CONFIRMED)
580     return GNUNET_OK;
581   size =
582       sizeof (struct ConnectNotifyMessage) +
583       (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
584   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
585   {
586     GNUNET_break (0);
587     /* recovery strategy: throw away performance data */
588     GNUNET_array_grow (n->ats, n->ats_count, 0);
589     size =
590         sizeof (struct PeerStatusNotifyMessage) +
591         n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
592   }
593   cnm = (struct ConnectNotifyMessage *) buf;
594   cnm->header.size = htons (size);
595   cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
596   cnm->ats_count = htonl (n->ats_count);
597   ats = &cnm->ats;
598   memcpy (ats, n->ats,
599           n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
600   ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
601   ats[n->ats_count].value = htonl (0);
602 #if DEBUG_CORE_CLIENT
603   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
604               "NOTIFY_CONNECT");
605 #endif
606   cnm->peer = n->peer;
607   GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
608   return GNUNET_OK;
609 }
610
611
612
613
614 /**
615  * Send a P2P message to a client.
616  *
617  * @param sender who sent us the message?
618  * @param client who should we give the message to?
619  * @param m contains the message to transmit
620  * @param msize number of bytes in buf to transmit
621  */
622 static void
623 send_p2p_message_to_client (struct Neighbour *sender, struct GSC_Client *client,
624                             const void *m, size_t msize)
625 {
626   size_t size =
627       msize + sizeof (struct NotifyTrafficMessage) +
628       (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
629   char buf[size];
630   struct NotifyTrafficMessage *ntm;
631   struct GNUNET_TRANSPORT_ATS_Information *ats;
632
633   GNUNET_assert (GNUNET_YES == sender->is_connected);
634   GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
635   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
636   {
637     GNUNET_break (0);
638     /* recovery strategy: throw performance data away... */
639     GNUNET_array_grow (sender->ats, sender->ats_count, 0);
640     size =
641         msize + sizeof (struct NotifyTrafficMessage) +
642         (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
643   }
644 #if DEBUG_CORE
645   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646               "Core service passes message from `%4s' of type %u to client.\n",
647               GNUNET_i2s (&sender->peer),
648               (unsigned int)
649               ntohs (((const struct GNUNET_MessageHeader *) m)->type));
650 #endif
651   ntm = (struct NotifyTrafficMessage *) buf;
652   ntm->header.size = htons (size);
653   ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
654   ntm->ats_count = htonl (sender->ats_count);
655   ntm->peer = sender->peer;
656   ats = &ntm->ats;
657   memcpy (ats, sender->ats,
658           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * sender->ats_count);
659   ats[sender->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
660   ats[sender->ats_count].value = htonl (0);
661   memcpy (&ats[sender->ats_count + 1], m, msize);
662   send_to_client (client, &ntm->header, GNUNET_YES);
663 }
664
665
666
667 /**
668  * Notify a particular client about a change to existing connection to
669  * one of our neighbours (check if the client is interested).  Called
670  * from 'GSC_SESSIONS_notify_client_about_sessions'.
671  *
672  * @param client client to notify
673  * @param neighbour identity of the neighbour that changed status
674  * @param tmap_old previous type map for the neighbour, NULL for disconnect
675  * @param tmap_new updated type map for the neighbour, NULL for disconnect
676  */
677 void
678 GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
679                                            const struct GNUNET_PeerIdentity *neighbour,
680                                            const struct GSC_TypeMap *tmap_old,
681                                            const struct GSC_TypeMap *tmap_new)
682 {
683 }
684
685
686 /**
687  * Notify client about a change to existing connection to one of our neighbours.
688  *
689  * @param neighbour identity of the neighbour that changed status
690  * @param tmap_old previous type map for the neighbour, NULL for disconnect
691  * @param tmap_new updated type map for the neighbour, NULL for disconnect
692  */
693 void
694 GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
695                                             const struct GSC_TypeMap *tmap_old,
696                                             const struct GSC_TypeMap *tmap_new)
697 {
698 }
699
700
701 /**
702  * Deliver P2P message to interested clients.
703  *
704  * @param sender peer who sent us the message 
705  * @param m the message
706  */
707 void
708 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
709                              const struct GNUNET_MessageHeader *m)
710 {
711   struct Neighbour *sender = client;
712   size_t msize = ntohs (m->size);
713   char buf[256];
714   struct GSC_Client *cpos;
715   uint16_t type;
716   unsigned int tpos;
717   int deliver_full;
718   int dropped;
719
720   GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
721   type = ntohs (m->type);
722 #if DEBUG_CORE > 1
723   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724               "Received encapsulated message of type %u and size %u from `%4s'\n",
725               (unsigned int) type, ntohs (m->size), GNUNET_i2s (&sender->peer));
726 #endif
727   GNUNET_snprintf (buf, sizeof (buf),
728                    gettext_noop ("# bytes of messages of type %u received"),
729                    (unsigned int) type);
730   GNUNET_STATISTICS_update (stats, buf, msize, GNUNET_NO);
731   if ((GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) ||
732       (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type))
733   {
734     /* FIXME: update message type map for 'Neighbour' */
735     return;
736   }
737   dropped = GNUNET_YES;
738   cpos = clients;
739   while (cpos != NULL)
740   {
741     deliver_full = GNUNET_NO;
742     if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))
743       deliver_full = GNUNET_YES;
744     else
745     {
746       for (tpos = 0; tpos < cpos->tcnt; tpos++)
747       {
748         if (type != cpos->types[tpos])
749           continue;
750         deliver_full = GNUNET_YES;
751         break;
752       }
753     }
754     if (GNUNET_YES == deliver_full)
755     {
756       send_p2p_message_to_client (sender, cpos, m, msize);
757       dropped = GNUNET_NO;
758     }
759     else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)
760     {
761       send_p2p_message_to_client (sender, cpos, m,
762                                   sizeof (struct GNUNET_MessageHeader));
763     }
764     cpos = cpos->next;
765   }
766   if (dropped == GNUNET_YES)
767   {
768 #if DEBUG_CORE
769     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770                 "Message of type %u from `%4s' not delivered to any client.\n",
771                 (unsigned int) type, GNUNET_i2s (&sender->peer));
772 #endif
773     GNUNET_STATISTICS_update (stats,
774                               gettext_noop
775                               ("# messages not delivered to any client"), 1,
776                               GNUNET_NO);
777   }
778 }
779
780
781
782
783 /**
784  * Handle CORE_ITERATE_PEERS request.
785  *
786  * @param cls unused
787  * @param client client sending the iteration request
788  * @param message iteration request message
789  */
790 static void
791 handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
792                              const struct GNUNET_MessageHeader *message)
793 {
794   struct GNUNET_MessageHeader done_msg;
795   struct GNUNET_SERVER_TransmitContext *tc;
796   int msize;
797
798   /* notify new client about existing neighbours */
799
800   msize = ntohs (message->size);
801   tc = GNUNET_SERVER_transmit_context_create (client);
802   if (msize == sizeof (struct GNUNET_MessageHeader))
803     GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
804                                            tc);
805   else
806     GNUNET_break (0);
807
808   done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
809   done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
810   GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
811   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
812 }
813
814
815 /**
816  * Handle CORE_PEER_CONNECTED request.  Notify client about existing neighbours.
817  *
818  * @param cls unused
819  * @param client client sending the iteration request
820  * @param message iteration request message
821  */
822 static void
823 handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
824                          const struct GNUNET_MessageHeader *message)
825 {
826   struct GNUNET_MessageHeader done_msg;
827   struct GNUNET_SERVER_TransmitContext *tc;
828   struct GNUNET_PeerIdentity *peer;
829
830   tc = GNUNET_SERVER_transmit_context_create (client);
831   peer = (struct GNUNET_PeerIdentity *) &message[1];
832   GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
833                                               &queue_connect_message, tc);
834   done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
835   done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
836   GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
837   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
838 }
839
840
841 /**
842  * Handle REQUEST_INFO request.
843  *
844  * @param cls unused
845  * @param client client sending the request
846  * @param message iteration request message
847  */
848 static void
849 handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
850                             const struct GNUNET_MessageHeader *message)
851 {
852   const struct RequestInfoMessage *rcm;
853   struct GSC_Client *pos;
854   struct Neighbour *n;
855   struct ConfigurationInfoMessage cim;
856   int32_t want_reserv;
857   int32_t got_reserv;
858   unsigned long long old_preference;
859   struct GNUNET_TIME_Relative rdelay;
860
861   rdelay = GNUNET_TIME_relative_get_zero ();
862 #if DEBUG_CORE_CLIENT
863   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
864               "REQUEST_INFO");
865 #endif
866   pos = clients;
867   while (pos != NULL)
868   {
869     if (client == pos->client_handle)
870       break;
871     pos = pos->next;
872   }
873   if (pos == NULL)
874   {
875     GNUNET_break (0);
876     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
877     return;
878   }
879
880   rcm = (const struct RequestInfoMessage *) message;
881   n = find_neighbour (&rcm->peer);
882   memset (&cim, 0, sizeof (cim));
883   if ((n != NULL) && (GNUNET_YES == n->is_connected))
884   {
885     want_reserv = ntohl (rcm->reserve_inbound);
886     if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
887     {
888       n->bw_out_internal_limit = rcm->limit_outbound;
889       if (n->bw_out.value__ !=
890           GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
891                                       n->bw_out_external_limit).value__)
892       {
893         n->bw_out =
894             GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
895                                         n->bw_out_external_limit);
896         GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
897                                                n->bw_out);
898         GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
899         handle_peer_status_change (n);
900       }
901     }
902     if (want_reserv < 0)
903     {
904       got_reserv = want_reserv;
905     }
906     else if (want_reserv > 0)
907     {
908       rdelay =
909           GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
910                                               want_reserv);
911       if (rdelay.rel_value == 0)
912         got_reserv = want_reserv;
913       else
914         got_reserv = 0;         /* all or nothing */
915     }
916     else
917       got_reserv = 0;
918     GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
919     old_preference = n->current_preference;
920     n->current_preference += GNUNET_ntohll (rcm->preference_change);
921     if (old_preference > n->current_preference)
922     {
923       /* overflow; cap at maximum value */
924       n->current_preference = ULLONG_MAX;
925     }
926     update_preference_sum (n->current_preference - old_preference);
927 #if DEBUG_CORE_QUOTA
928     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929                 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
930                 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
931                 (unsigned long long) rdelay.rel_value);
932 #endif
933     cim.reserved_amount = htonl (got_reserv);
934     cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
935     cim.bw_out = n->bw_out;
936     cim.preference = n->current_preference;
937   }
938   else
939   {
940     /* Technically, this COULD happen (due to asynchronous behavior),
941      * but it should be rare, so we should generate an info event
942      * to help diagnosis of serious errors that might be masked by this */
943     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
944                 _
945                 ("Client asked for preference change with peer `%s', which is not connected!\n"),
946                 GNUNET_i2s (&rcm->peer));
947     GNUNET_SERVER_receive_done (client, GNUNET_OK);
948     return;
949   }
950   cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
951   cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
952   cim.peer = rcm->peer;
953   cim.rim_id = rcm->rim_id;
954 #if DEBUG_CORE_CLIENT
955   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
956               "CONFIGURATION_INFO");
957 #endif
958   send_to_client (pos, &cim.header, GNUNET_NO);
959   GNUNET_SERVER_receive_done (client, GNUNET_OK);
960 }
961
962
963
964
965 /**
966  * Initialize clients subsystem.
967  *
968  * @param server handle to server clients connect to
969  */
970 void
971 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
972 {
973   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
974     {&handle_client_init, NULL,
975      GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
976     {&handle_client_iterate_peers, NULL,
977      GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
978      sizeof (struct GNUNET_MessageHeader)},
979     {&handle_client_have_peer, NULL,
980      GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
981      sizeof (struct GNUNET_MessageHeader) +
982      sizeof (struct GNUNET_PeerIdentity)},
983     {&handle_client_request_info, NULL,
984      GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
985      sizeof (struct RequestInfoMessage)},
986     {&handle_client_send_request, NULL,
987      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
988      sizeof (struct SendMessageRequest)},
989     {&handle_client_send, NULL,
990      GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
991     {NULL, NULL, 0, 0}
992   };
993
994   /* setup notification */
995   client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
996   notifier =
997       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
998   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
999   GNUNET_SERVER_add_handlers (server, handlers);
1000 }
1001
1002
1003 /**
1004  * Shutdown clients subsystem.
1005  */
1006 void
1007 GSC_CLIENTS_done ()
1008 {
1009   struct GSC_Client *c;
1010
1011   while (NULL != (c = client_head))  
1012     handle_client_disconnect (NULL, c->client_handle);
1013   GNUNET_SERVER_notification_context_destroy (notifier);
1014   notifier = NULL;
1015   GNUNET_SERVER_MST_destroy (client_mst);
1016   client_mst = NULL;
1017 }
1018
1019 /* end of gnunet-service-core_clients.c */