-fix (C) notices
[oweals/gnunet.git] / src / transport / gnunet-service-transport_clients.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file transport/gnunet-service-transport_clients.c
23  * @brief communication with clients (core service and monitors)
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-transport_blacklist.h"
28 #include "gnunet-service-transport_clients.h"
29 #include "gnunet-service-transport_hello.h"
30 #include "gnunet-service-transport_neighbours.h"
31 #include "gnunet-service-transport_plugins.h"
32 #include "gnunet-service-transport_validation.h"
33 #include "gnunet-service-transport_manipulation.h"
34 #include "gnunet-service-transport.h"
35 #include "transport.h"
36
37
38 /**
39  * How many messages can we have pending for a given client process
40  * before we start to drop incoming messages?  We typically should
41  * have only one client and so this would be the primary buffer for
42   * messages, so the number should be chosen rather generously.
43  *
44  * The expectation here is that most of the time the queue is large
45  * enough so that a drop is virtually never required.  Note that
46  * this value must be about as large as 'TOTAL_MSGS' in the
47  * 'test_transport_api_reliability.c', otherwise that testcase may
48  * fail.
49  */
50 #define MAX_PENDING (128 * 1024)
51
52
53 /**
54  * Linked list of messages to be transmitted to the client.  Each
55  * entry is followed by the actual message.
56  */
57 struct ClientMessageQueueEntry
58 {
59   /**
60    * This is a doubly-linked list.
61    */
62   struct ClientMessageQueueEntry *next;
63
64   /**
65    * This is a doubly-linked list.
66    */
67   struct ClientMessageQueueEntry *prev;
68 };
69
70
71 /**
72  * Client connected to the transport service.
73  */
74 struct TransportClient
75 {
76
77   /**
78    * This is a doubly-linked list.
79    */
80   struct TransportClient *next;
81
82   /**
83    * This is a doubly-linked list.
84    */
85   struct TransportClient *prev;
86
87   /**
88    * Handle to the client.
89    */
90   struct GNUNET_SERVER_Client *client;
91
92   /**
93    * Linked list of messages yet to be transmitted to
94    * the client.
95    */
96   struct ClientMessageQueueEntry *message_queue_head;
97
98   /**
99    * Tail of linked list of messages yet to be transmitted to the
100    * client.
101    */
102   struct ClientMessageQueueEntry *message_queue_tail;
103
104   /**
105    * Current transmit request handle.
106    */
107   struct GNUNET_SERVER_TransmitHandle *th;
108
109   /**
110    * Length of the list of messages pending for this client.
111    */
112   unsigned int message_count;
113
114   /**
115    * Is this client interested in payload messages?
116    */
117   int send_payload;
118 };
119
120
121 /**
122  * Context for address to string operations
123  */
124 struct AddressToStringContext
125 {
126   /**
127    * This is a doubly-linked list.
128    */
129   struct AddressToStringContext *next;
130
131   /**
132    * This is a doubly-linked list.
133    */
134   struct AddressToStringContext *prev;
135
136   /**
137    * Transmission context
138    */
139   struct GNUNET_SERVER_TransmitContext* tc;
140 };
141
142
143 /**
144  * Client monitoring changes of active addresses or validations
145  * of our neighbours. Which type is being monitored depends on the
146  * DLL this struct is in.
147  */
148 struct MonitoringClient
149 {
150   /**
151    * This is a doubly-linked list.
152    */
153   struct MonitoringClient *next;
154
155   /**
156    * This is a doubly-linked list.
157    */
158   struct MonitoringClient *prev;
159
160   /**
161    * Handle to the client.
162    */
163   struct GNUNET_SERVER_Client *client;
164
165   /**
166    * Peer identity to monitor the addresses of.
167    * Zero to monitor all neighrours.
168    */
169   struct GNUNET_PeerIdentity peer;
170
171 };
172
173
174 /**
175  * Closure for #handle_send_transmit_continuation()
176  */
177 struct SendTransmitContinuationContext
178 {
179   /**
180    * Client that made the request.
181    */
182   struct GNUNET_SERVER_Client *client;
183
184   /**
185    * Peer that was the target.
186    */
187   struct GNUNET_PeerIdentity target;
188
189   /**
190    * At what time did we receive the message?
191    */
192   struct GNUNET_TIME_Absolute send_time;
193
194   /**
195    * Unique ID, for logging.
196    */
197   unsigned long long uuid;
198
199   /**
200    * Set to #GNUNET_YES if the connection for @e target goes
201    * down and we thus must no longer send the
202    * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
203    */
204   int down;
205 };
206
207
208 /**
209  * Head of linked list of all clients to this service.
210  */
211 static struct TransportClient *clients_head;
212
213 /**
214  * Tail of linked list of all clients to this service.
215  */
216 static struct TransportClient *clients_tail;
217
218 /**
219  * Map of peer identities to active send transmit continuation
220  * contexts. Used to flag contexts as 'dead' when a connection goes
221  * down. Values are of type `struct SendTransmitContinuationContext
222  * *`.
223  */
224 static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
225
226 /**
227  * Head of linked list of all pending address iterations
228  */
229 static struct AddressToStringContext *a2s_head;
230
231 /**
232  * Tail of linked list of all pending address iterations
233  */
234 static struct AddressToStringContext *a2s_tail;
235
236 /**
237  * Head of linked list of monitoring clients.
238  */
239 static struct MonitoringClient *peer_monitoring_clients_head;
240
241 /**
242  * Tail of linked list of monitoring clients.
243  */
244 static struct MonitoringClient *peer_monitoring_clients_tail;
245
246 /**
247  * Head of linked list of validation monitoring clients.
248  */
249 static struct MonitoringClient *val_monitoring_clients_head;
250
251 /**
252  * Tail of linked list of validation monitoring clients.
253  */
254 static struct MonitoringClient *val_monitoring_clients_tail;
255
256 /**
257  * Notification context, to send updates on changes to active addresses
258  * of our neighbours.
259  */
260 static struct GNUNET_SERVER_NotificationContext *peer_nc;
261
262 /**
263  * Notification context, to send updates on changes to active addresses
264  * of our neighbours.
265  */
266 static struct GNUNET_SERVER_NotificationContext *val_nc;
267
268 /**
269  * Notification context, to send updates on changes to active plugin
270  * connections.
271  */
272 static struct GNUNET_SERVER_NotificationContext *plugin_nc;
273
274 /**
275  * Plugin monitoring client we are currently syncing, NULL if all
276  * monitoring clients are in sync.
277  */
278 static struct GNUNET_SERVER_Client *sync_client;
279
280 /**
281  * Peer identity that is all zeros, used as a way to indicate
282  * "all peers".  Used for comparissons.
283  */
284 static struct GNUNET_PeerIdentity all_zeros;
285
286
287 /**
288  * Find the internal handle associated with the given client handle.
289  *
290  * @param client server's client handle to look up
291  * @return internal client handle
292  */
293 static struct TransportClient *
294 lookup_client (struct GNUNET_SERVER_Client *client)
295 {
296   return GNUNET_SERVER_client_get_user_context (client,
297                                                 struct TransportClient);
298 }
299
300
301 /**
302  * Create the internal handle for the given server client handle.
303  *
304  * @param client server's client handle to create our internal handle for
305  * @return fresh internal client handle
306  */
307 static struct TransportClient *
308 setup_client (struct GNUNET_SERVER_Client *client)
309 {
310   struct TransportClient *tc;
311
312   GNUNET_assert (NULL == lookup_client (client));
313   tc = GNUNET_new (struct TransportClient);
314   tc->client = client;
315   GNUNET_SERVER_client_set_user_context (client, tc);
316   GNUNET_CONTAINER_DLL_insert (clients_head,
317                                clients_tail,
318                                tc);
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320               "Client %p connected\n",
321               tc);
322   return tc;
323 }
324
325
326 /**
327  * Find the handle to the monitoring client associated with the given
328  * client handle.
329  *
330  * @param head the head of the client queue to look in
331  * @param client server's client handle to look up
332  * @return handle to the monitoring client
333  */
334 static struct MonitoringClient *
335 lookup_monitoring_client (struct MonitoringClient *head,
336                           struct GNUNET_SERVER_Client *client)
337 {
338   struct MonitoringClient *mc;
339
340   for (mc = head; NULL != mc; mc = mc->next)
341     if (mc->client == client)
342       return mc;
343   return NULL;
344 }
345
346
347 /**
348  * Setup a new monitoring client using the given server client handle and
349  * the peer identity.
350  *
351  * @param client server's client handle to create our internal handle for
352  * @param peer identity of the peer to monitor the addresses of,
353  *             zero to monitor all neighrours.
354  * @return handle to the new monitoring client
355  */
356 static struct MonitoringClient *
357 setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client,
358                               const struct GNUNET_PeerIdentity *peer)
359 {
360   struct MonitoringClient *mc;
361
362   GNUNET_assert (NULL ==
363                  lookup_monitoring_client (peer_monitoring_clients_head,
364                                            client));
365   mc = GNUNET_new (struct MonitoringClient);
366   mc->client = client;
367   mc->peer = *peer;
368   GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head,
369                                peer_monitoring_clients_tail,
370                                mc);
371   GNUNET_SERVER_client_mark_monitor (client);
372   GNUNET_SERVER_notification_context_add (peer_nc,
373                                           client);
374   if (0 != memcmp (peer,
375                    &all_zeros,
376                    sizeof (struct GNUNET_PeerIdentity)))
377     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378                 "Client %p started monitoring of the peer `%s'\n",
379                 mc,
380                 GNUNET_i2s (peer));
381   else
382     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383                 "Client %p started monitoring all peers\n",
384                 mc);
385   return mc;
386 }
387
388
389 /**
390  * Setup a new monitoring client using the given server client handle and
391  * the peer identity.
392  *
393  * @param client server's client handle to create our internal handle for
394  * @param peer identity of the peer to monitor the addresses of,
395  *             zero to monitor all neighrours.
396  * @return handle to the new monitoring client
397  */
398 static struct MonitoringClient *
399 setup_val_monitoring_client (struct GNUNET_SERVER_Client *client,
400                              struct GNUNET_PeerIdentity *peer)
401 {
402   struct MonitoringClient *mc;
403
404   GNUNET_assert (NULL ==
405                  lookup_monitoring_client (val_monitoring_clients_head,
406                                            client));
407   mc = GNUNET_new (struct MonitoringClient);
408   mc->client = client;
409   mc->peer = *peer;
410   GNUNET_CONTAINER_DLL_insert (val_monitoring_clients_head,
411                                val_monitoring_clients_tail,
412                                mc);
413   GNUNET_SERVER_notification_context_add (val_nc, client);
414
415   if (0 != memcmp (peer,
416                    &all_zeros,
417                    sizeof (struct GNUNET_PeerIdentity)))
418     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419                 "Client %p started monitoring of the peer `%s'\n",
420                 mc,
421                 GNUNET_i2s (peer));
422   else
423     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424                 "Client %p started monitoring all peers\n",
425                 mc);
426   return mc;
427 }
428
429
430 /**
431  * Function called to notify a client about the socket being ready to
432  * queue more data.  @a buf will be NULL and @a size zero if the socket
433  * was closed for writing in the meantime.
434  *
435  * @param cls closure
436  * @param size number of bytes available in @a buf
437  * @param buf where the callee should write the message
438  * @return number of bytes written to @a buf
439  */
440 static size_t
441 transmit_to_client_callback (void *cls,
442                              size_t size,
443                              void *buf)
444 {
445   struct TransportClient *tc = cls;
446   struct ClientMessageQueueEntry *q;
447   const struct GNUNET_MessageHeader *msg;
448   char *cbuf;
449   uint16_t msize;
450   size_t tsize;
451
452   tc->th = NULL;
453   if (NULL == buf)
454   {
455     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456                 "Transmission to client failed, closing connection.\n");
457     return 0;
458   }
459   cbuf = buf;
460   tsize = 0;
461   while (NULL != (q = tc->message_queue_head))
462   {
463     msg = (const struct GNUNET_MessageHeader *) &q[1];
464     msize = ntohs (msg->size);
465     if (msize + tsize > size)
466       break;
467     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468                 "Transmitting message of type %u to client %p.\n",
469                 ntohs (msg->type),
470                 tc);
471     GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
472                                  tc->message_queue_tail,
473                                  q);
474     tc->message_count--;
475     memcpy (&cbuf[tsize], msg, msize);
476     GNUNET_free (q);
477     tsize += msize;
478   }
479   if (NULL != q)
480   {
481     GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
482     tc->th =
483         GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
484                                              GNUNET_TIME_UNIT_FOREVER_REL,
485                                              &transmit_to_client_callback, tc);
486     GNUNET_assert (NULL != tc->th);
487   }
488   return tsize;
489 }
490
491
492 /**
493  * Queue the given message for transmission to the given client
494  *
495  * @param tc target of the message
496  * @param msg message to transmit
497  * @param may_drop #GNUNET_YES if the message can be dropped
498  */
499 static void
500 unicast (struct TransportClient *tc,
501          const struct GNUNET_MessageHeader *msg,
502          int may_drop)
503 {
504   struct ClientMessageQueueEntry *q;
505   uint16_t msize;
506
507   if (NULL == msg)
508   {
509     GNUNET_break (0);
510     return;
511   }
512   if ( (tc->message_count >= MAX_PENDING) &&
513        (GNUNET_YES == may_drop) )
514   {
515     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516                 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
517                 ntohs (msg->type),
518                 ntohs (msg->size),
519                 tc->message_count,
520                 MAX_PENDING);
521     GNUNET_STATISTICS_update (GST_stats,
522                               gettext_noop
523                               ("# messages dropped due to slow client"), 1,
524                               GNUNET_NO);
525     return;
526   }
527   msize = ntohs (msg->size);
528   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
529   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
530   memcpy (&q[1], msg, msize);
531   GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
532                                     tc->message_queue_tail,
533                                     q);
534   tc->message_count++;
535   if (NULL != tc->th)
536     return;
537   tc->th =
538       GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
539                                            GNUNET_TIME_UNIT_FOREVER_REL,
540                                            &transmit_to_client_callback, tc);
541   GNUNET_assert (NULL != tc->th);
542 }
543
544
545 /**
546  * Called whenever a client is disconnected.  Frees our
547  * resources associated with that client.
548  *
549  * @param cls closure, NULL
550  * @param client identification of the client
551  */
552 static void
553 client_disconnect_notification (void *cls,
554                                 struct GNUNET_SERVER_Client *client)
555 {
556   struct TransportClient *tc;
557   struct MonitoringClient *mc;
558   struct ClientMessageQueueEntry *mqe;
559
560   if (NULL == client)
561     return;
562   mc = lookup_monitoring_client (peer_monitoring_clients_head,
563                                  client);
564   if (NULL != mc)
565   {
566     GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head,
567                                  peer_monitoring_clients_tail,
568                                  mc);
569     GNUNET_free (mc);
570   }
571   mc = lookup_monitoring_client (val_monitoring_clients_head,
572                                  client);
573   if (NULL != mc)
574   {
575     GNUNET_CONTAINER_DLL_remove (val_monitoring_clients_head,
576                                  val_monitoring_clients_tail,
577                                  mc);
578     GNUNET_free (mc);
579   }
580   tc = lookup_client (client);
581   if (NULL == tc)
582     return;
583   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
584               "Client %p disconnected, cleaning up.\n",
585               tc);
586   while (NULL != (mqe = tc->message_queue_head))
587   {
588     GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
589                                  tc->message_queue_tail,
590                                  mqe);
591     tc->message_count--;
592     GNUNET_free (mqe);
593   }
594   GNUNET_CONTAINER_DLL_remove (clients_head,
595                                clients_tail,
596                                tc);
597   GNUNET_SERVER_client_set_user_context (client, NULL);
598   if (NULL != tc->th)
599   {
600     GNUNET_SERVER_notify_transmit_ready_cancel (tc->th);
601     tc->th = NULL;
602   }
603   GNUNET_break (0 == tc->message_count);
604   GNUNET_free (tc);
605 }
606
607
608 /**
609  * Function called for each of our connected neighbours.  Notify the
610  * client about the existing neighbour.
611  *
612  * @param cls the `struct TransportClient *` to notify
613  * @param peer identity of the neighbour
614  * @param address the address
615  * @param state the current state of the peer
616  * @param state_timeout the time out for the state
617  * @param bandwidth_in inbound bandwidth in NBO
618  * @param bandwidth_out outbound bandwidth in NBO
619  */
620 static void
621 notify_client_about_neighbour (void *cls,
622                                const struct GNUNET_PeerIdentity *peer,
623                                const struct GNUNET_HELLO_Address *address,
624                                enum GNUNET_TRANSPORT_PeerState state,
625                                struct GNUNET_TIME_Absolute state_timeout,
626                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
627                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
628 {
629   struct TransportClient *tc = cls;
630   struct ConnectInfoMessage cim;
631
632   if (GNUNET_NO == GST_neighbours_test_connected (peer))
633     return;
634   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
635   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
636   cim.id = *peer;
637   cim.quota_in = bandwidth_in;
638   cim.quota_out = bandwidth_out;
639   unicast (tc, &cim.header, GNUNET_NO);
640 }
641
642
643 /**
644  * Initialize a normal client.  We got a start message from this
645  * client, add him to the list of clients for broadcasting of inbound
646  * messages.
647  *
648  * @param cls unused
649  * @param client the client
650  * @param message the start message that was sent
651  */
652 static void
653 clients_handle_start (void *cls,
654                       struct GNUNET_SERVER_Client *client,
655                       const struct GNUNET_MessageHeader *message)
656 {
657   const struct StartMessage *start;
658   const struct GNUNET_MessageHeader *hello;
659   struct TransportClient *tc;
660   uint32_t options;
661
662   tc = lookup_client (client);
663   if (NULL != tc)
664   {
665     /* got 'start' twice from the same client, not allowed */
666     GNUNET_break (0);
667     GNUNET_SERVER_receive_done (client,
668                                 GNUNET_SYSERR);
669     return;
670   }
671   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672               "Client %p sent START\n",
673               client);
674   start = (const struct StartMessage *) message;
675   options = ntohl (start->options);
676   if ((0 != (1 & options)) &&
677       (0 !=
678        memcmp (&start->self,
679                &GST_my_identity,
680                sizeof (struct GNUNET_PeerIdentity))))
681   {
682     /* client thinks this is a different peer, reject */
683     GNUNET_break (0);
684     GNUNET_SERVER_receive_done (client,
685                                 GNUNET_SYSERR);
686     return;
687   }
688   tc = setup_client (client);
689   tc->send_payload = (0 != (2 & options));
690   hello = GST_hello_get ();
691   if (NULL != hello)
692     unicast (tc,
693              hello,
694              GNUNET_NO);
695   GST_neighbours_iterate (&notify_client_about_neighbour,
696                           tc);
697   GNUNET_SERVER_receive_done (client,
698                               GNUNET_OK);
699 }
700
701
702 /**
703  * Client sent us a HELLO.  Process the request.
704  *
705  * @param cls unused
706  * @param client the client
707  * @param message the HELLO message
708  */
709 static void
710 clients_handle_hello (void *cls,
711                       struct GNUNET_SERVER_Client *client,
712                       const struct GNUNET_MessageHeader *message)
713 {
714   GST_validation_handle_hello (message);
715   GNUNET_SERVER_receive_done (client, GNUNET_OK);
716 }
717
718
719 /**
720  * Function called after the transmission is done.  Notify the client that it is
721  * OK to send the next message.
722  *
723  * @param cls closure
724  * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
725  * @param bytes_payload bytes payload sent
726  * @param bytes_on_wire bytes sent on wire
727  */
728 static void
729 handle_send_transmit_continuation (void *cls,
730                                    int success,
731                                    size_t bytes_payload,
732                                    size_t bytes_on_wire)
733 {
734   struct SendTransmitContinuationContext *stcc = cls;
735   struct SendOkMessage send_ok_msg;
736   struct GNUNET_TIME_Relative delay;
737   const struct GNUNET_HELLO_Address *addr;
738
739   delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
740   addr = GST_neighbour_get_current_address (&stcc->target);
741   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
742     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
743                 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
744                 GNUNET_STRINGS_relative_time_to_string (delay,
745                                                         GNUNET_YES),
746                 (unsigned int) bytes_payload,
747                 (unsigned int) bytes_on_wire,
748                 GNUNET_i2s (&stcc->target),
749                 success,
750                 (NULL != addr) ? addr->transport_name : "%");
751   else
752     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753                 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
754                 GNUNET_STRINGS_relative_time_to_string (delay,
755                                                         GNUNET_YES),
756                 (unsigned int) bytes_payload,
757                 (unsigned int) bytes_on_wire,
758                 GNUNET_i2s (&stcc->target),
759                 success,
760                 (NULL != addr) ? addr->transport_name : "%");
761
762   if (GNUNET_NO == stcc->down)
763   {
764     /* Only send confirmation if we are still connected */
765     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
766                 "Sending SEND_OK for transmission request %llu\n",
767                 stcc->uuid);
768     send_ok_msg.header.size = htons (sizeof (send_ok_msg));
769     send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
770     send_ok_msg.bytes_msg = htonl (bytes_payload);
771     send_ok_msg.bytes_physical = htonl (bytes_on_wire);
772     send_ok_msg.success = htonl (success);
773     send_ok_msg.peer = stcc->target;
774     GST_clients_unicast (stcc->client,
775                          &send_ok_msg.header,
776                          GNUNET_NO);
777   }
778   GNUNET_SERVER_client_drop (stcc->client);
779   GNUNET_assert (GNUNET_OK ==
780                  GNUNET_CONTAINER_multipeermap_remove (active_stccs,
781                                                        &stcc->target,
782                                                        stcc));
783   GNUNET_free (stcc);
784 }
785
786
787 /**
788  * Client asked for transmission to a peer.  Process the request.
789  *
790  * @param cls unused
791  * @param client the client
792  * @param message the send message that was sent
793  */
794 static void
795 clients_handle_send (void *cls,
796                      struct GNUNET_SERVER_Client *client,
797                      const struct GNUNET_MessageHeader *message)
798 {
799   static unsigned long long uuid_gen;
800   const struct OutboundMessage *obm;
801   const struct GNUNET_MessageHeader *obmm;
802   struct SendTransmitContinuationContext *stcc;
803   uint16_t size;
804   uint16_t msize;
805   struct TransportClient *tc;
806
807   tc = lookup_client (client);
808   if (NULL == tc)
809   {
810     /* client asked for transmission before 'START' */
811     GNUNET_break (0);
812     GNUNET_SERVER_receive_done (client,
813                                 GNUNET_SYSERR);
814     return;
815   }
816
817   size = ntohs (message->size);
818   if (size <
819       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
820   {
821     GNUNET_break (0);
822     GNUNET_SERVER_receive_done (client,
823                                 GNUNET_SYSERR);
824     return;
825   }
826   obm = (const struct OutboundMessage *) message;
827   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
828   msize = size - sizeof (struct OutboundMessage);
829   if (msize < sizeof (struct GNUNET_MessageHeader))
830   {
831     GNUNET_break (0);
832     GNUNET_SERVER_receive_done (client,
833                                 GNUNET_SYSERR);
834     return;
835   }
836
837   if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
838   {
839     /* not connected, not allowed to send; can happen due to asynchronous operations */
840     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
841                 "Could not send message to peer `%s': not connected\n",
842                 GNUNET_i2s (&obm->peer));
843     GNUNET_STATISTICS_update (GST_stats,
844                               gettext_noop
845                               ("# bytes payload dropped (other peer was not connected)"),
846                               msize, GNUNET_NO);
847     GNUNET_SERVER_receive_done (client,
848                                 GNUNET_OK);
849     return;
850   }
851   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
852               "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
853               uuid_gen,
854               GNUNET_i2s (&obm->peer),
855               ntohs (obmm->type),
856               msize);
857   GNUNET_SERVER_receive_done (client,
858                               GNUNET_OK);
859   stcc = GNUNET_new (struct SendTransmitContinuationContext);
860   stcc->target = obm->peer;
861   stcc->client = client;
862   stcc->send_time = GNUNET_TIME_absolute_get ();
863   stcc->uuid = uuid_gen++;
864   (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
865                                             &stcc->target,
866                                             stcc,
867                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
868   GNUNET_SERVER_client_keep (client);
869   GST_manipulation_send (&obm->peer,
870                          obmm,
871                          msize,
872                          GNUNET_TIME_relative_ntoh (obm->timeout),
873                          &handle_send_transmit_continuation,
874                          stcc);
875 }
876
877
878 /**
879  * Take the given address and append it to the set of results sent back to
880  * the client.  This function may be called serveral times for a single
881  * conversion.   The last invocation will be with a @a address of
882  * NULL and a @a res of #GNUNET_OK.  Thus, to indicate conversion
883  * errors, the callback might be called first with @a address NULL and
884  * @a res being #GNUNET_SYSERR.  In that case, there will still be a
885  * subsequent call later with @a address NULL and @a res #GNUNET_OK.
886  *
887  * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
888  * @param buf text to transmit (contains the human-readable address, or NULL)
889  * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
890  *            never #GNUNET_NO
891  */
892 static void
893 transmit_address_to_client (void *cls,
894                             const char *buf,
895                             int res)
896 {
897   struct AddressToStringContext *actx = cls;
898   struct AddressToStringResultMessage *atsm;
899   size_t len;
900   size_t slen;
901
902   GNUNET_assert ( (GNUNET_OK == res) ||
903                   (GNUNET_SYSERR == res) );
904   if (NULL == buf)
905   {
906     len = sizeof (struct AddressToStringResultMessage);
907     atsm = GNUNET_malloc (len);
908     atsm->header.size = ntohs (len);
909     atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
910     if (GNUNET_OK == res)
911     {
912       /* this was the last call, transmit */
913       atsm->res = htonl (GNUNET_OK);
914       atsm->addr_len = htonl (0);
915       GNUNET_SERVER_transmit_context_append_message (actx->tc,
916                                                      (const struct GNUNET_MessageHeader *) atsm);
917       GNUNET_SERVER_transmit_context_run (actx->tc,
918                                           GNUNET_TIME_UNIT_FOREVER_REL);
919       GNUNET_CONTAINER_DLL_remove (a2s_head,
920                                    a2s_tail,
921                                    actx);
922       GNUNET_free (atsm);
923       GNUNET_free (actx);
924       return;
925     }
926     if (GNUNET_SYSERR == res)
927     {
928       /* address conversion failed, but there will be more callbacks */
929       atsm->res = htonl (GNUNET_SYSERR);
930       atsm->addr_len = htonl (0);
931       GNUNET_SERVER_transmit_context_append_message (actx->tc,
932                                                      (const struct GNUNET_MessageHeader *) atsm);
933       GNUNET_free (atsm);
934       return;
935     }
936   }
937   GNUNET_assert (GNUNET_OK == res);
938   /* succesful conversion, append*/
939   slen = strlen (buf) + 1;
940   len = sizeof (struct AddressToStringResultMessage) + slen;
941   atsm = GNUNET_malloc (len);
942   atsm->header.size = ntohs (len);
943   atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
944   atsm->res = htonl (GNUNET_YES);
945   atsm->addr_len = htonl (slen);
946   memcpy (&atsm[1],
947           buf,
948           slen);
949   GNUNET_SERVER_transmit_context_append_message (actx->tc,
950                                                  (const struct GNUNET_MessageHeader *) atsm);
951   GNUNET_free (atsm);
952 }
953
954
955 /**
956  * Client asked to resolve an address.  Process the request.
957  *
958  * @param cls unused
959  * @param client the client
960  * @param message the resolution request
961  */
962 static void
963 clients_handle_address_to_string (void *cls,
964                                   struct GNUNET_SERVER_Client *client,
965                                   const struct GNUNET_MessageHeader *message)
966 {
967   const struct AddressLookupMessage *alum;
968   struct GNUNET_TRANSPORT_PluginFunctions *papi;
969   const char *plugin_name;
970   const char *address;
971   uint32_t address_len;
972   uint16_t size;
973   struct GNUNET_SERVER_TransmitContext *tc;
974   struct AddressToStringContext *actx;
975   struct AddressToStringResultMessage atsm;
976   struct GNUNET_TIME_Relative rtimeout;
977   int32_t numeric;
978
979   size = ntohs (message->size);
980   if (size < sizeof (struct AddressLookupMessage))
981   {
982     GNUNET_break (0);
983     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
984     return;
985   }
986   alum = (const struct AddressLookupMessage *) message;
987   address_len = ntohs (alum->addrlen);
988   if (size <= sizeof (struct AddressLookupMessage) + address_len)
989   {
990     GNUNET_break (0);
991     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
992     return;
993   }
994   address = (const char *) &alum[1];
995   plugin_name = (const char *) &address[address_len];
996   if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
997   {
998     GNUNET_break (0);
999     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1000     return;
1001   }
1002   rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
1003   numeric = ntohs (alum->numeric_only);
1004   tc = GNUNET_SERVER_transmit_context_create (client);
1005   papi = GST_plugins_printer_find (plugin_name);
1006   if (NULL == papi)
1007   {
1008     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1009                 "Failed to find plugin `%s'\n",
1010                 plugin_name);
1011     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1012     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1013     atsm.res = htonl (GNUNET_SYSERR);
1014     atsm.addr_len = htonl (0);
1015     GNUNET_SERVER_transmit_context_append_message (tc,
1016                                                    &atsm.header);
1017     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1018     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1019     atsm.res = htonl (GNUNET_OK);
1020     atsm.addr_len = htonl (0);
1021     GNUNET_SERVER_transmit_context_append_message (tc,
1022                                                    &atsm.header);
1023     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1024     return;
1025   }
1026   actx = GNUNET_new (struct AddressToStringContext);
1027   actx->tc = tc;
1028   GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
1029   GNUNET_SERVER_disable_receive_done_warning (client);
1030   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031               "Pretty-printing address of %u bytes using plugin `%s'\n",
1032               address_len,
1033               plugin_name);
1034   papi->address_pretty_printer (papi->cls,
1035                                 plugin_name,
1036                                 address, address_len,
1037                                 numeric,
1038                                 rtimeout,
1039                                 &transmit_address_to_client,
1040                                 actx);
1041 }
1042
1043
1044 /**
1045  * Compose #PeerIterateResponseMessage using the given peer and address.
1046  *
1047  * @param peer identity of the peer
1048  * @param address the address, NULL on disconnect
1049  * @return composed message
1050  */
1051 static struct PeerIterateResponseMessage *
1052 compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1053                                           const struct GNUNET_HELLO_Address *address)
1054 {
1055   struct PeerIterateResponseMessage *msg;
1056   size_t size;
1057   size_t tlen;
1058   size_t alen;
1059   char *addr;
1060
1061   GNUNET_assert (NULL != peer);
1062   if (NULL != address)
1063   {
1064     tlen = strlen (address->transport_name) + 1;
1065     alen = address->address_length;
1066   }
1067   else
1068   {
1069     tlen = 0;
1070     alen = 0;
1071   }
1072   size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1073   msg = GNUNET_malloc (size);
1074   msg->header.size = htons (size);
1075   msg->header.type =
1076       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1077   msg->reserved = htonl (0);
1078   msg->peer = *peer;
1079   msg->addrlen = htonl (alen);
1080   msg->pluginlen = htonl (tlen);
1081
1082   if (NULL != address)
1083   {
1084     msg->local_address_info = htonl((uint32_t) address->local_info);
1085     addr = (char *) &msg[1];
1086     memcpy (addr, address->address, alen);
1087     memcpy (&addr[alen], address->transport_name, tlen);
1088   }
1089   return msg;
1090 }
1091
1092
1093 /**
1094  * Compose #PeerIterateResponseMessage using the given peer and address.
1095  *
1096  * @param peer identity of the peer
1097  * @param address the address, NULL on disconnect
1098  * @return composed message
1099  */
1100 static struct ValidationIterateResponseMessage *
1101 compose_validation_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1102                                              const struct GNUNET_HELLO_Address *address)
1103 {
1104   struct ValidationIterateResponseMessage *msg;
1105   size_t size;
1106   size_t tlen;
1107   size_t alen;
1108   char *addr;
1109
1110   GNUNET_assert (NULL != peer);
1111   if (NULL != address)
1112   {
1113     tlen = strlen (address->transport_name) + 1;
1114     alen = address->address_length;
1115   }
1116   else
1117   {
1118     tlen = 0;
1119     alen = 0;
1120   }
1121   size = (sizeof (struct ValidationIterateResponseMessage) + alen + tlen);
1122   msg = GNUNET_malloc (size);
1123   msg->header.size = htons (size);
1124   msg->header.type =
1125       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1126   msg->reserved = htonl (0);
1127   msg->peer = *peer;
1128   msg->addrlen = htonl (alen);
1129   msg->pluginlen = htonl (tlen);
1130
1131   if (NULL != address)
1132   {
1133     msg->local_address_info = htonl((uint32_t) address->local_info);
1134     addr = (char *) &msg[1];
1135     memcpy (addr, address->address, alen);
1136     memcpy (&addr[alen], address->transport_name, tlen);
1137   }
1138   return msg;
1139 }
1140
1141
1142 /**
1143  * Context for #send_validation_information() and
1144  * #send_peer_information().
1145  */
1146 struct IterationContext
1147 {
1148   /**
1149    * Context to use for the transmission.
1150    */
1151   struct GNUNET_SERVER_TransmitContext *tc;
1152
1153   /**
1154    * Which peers do we care about?
1155    */
1156   struct GNUNET_PeerIdentity id;
1157
1158   /**
1159    * #GNUNET_YES if @e id should be ignored because we want all peers.
1160    */
1161   int all;
1162 };
1163
1164
1165 /**
1166  * Output information of validation entries to the given client.
1167  *
1168  * @param cls the `struct IterationContext *`
1169  * @param address the address
1170  * @param last_validation point in time when last validation was performed
1171  * @param valid_until point in time how long address is valid
1172  * @param next_validation point in time when next validation will be performed
1173  * @param state state of validation notification
1174  */
1175 static void
1176 send_validation_information (void *cls,
1177                              const struct GNUNET_HELLO_Address *address,
1178                              struct GNUNET_TIME_Absolute last_validation,
1179                              struct GNUNET_TIME_Absolute valid_until,
1180                              struct GNUNET_TIME_Absolute next_validation,
1181                              enum GNUNET_TRANSPORT_ValidationState state)
1182 {
1183   struct IterationContext *pc = cls;
1184   struct ValidationIterateResponseMessage *msg;
1185
1186   if ( (GNUNET_YES != pc->all) &&
1187        (0 != memcmp (&address->peer, &pc->id, sizeof (pc->id))) )
1188     return;
1189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1190               "Sending information about for validation entry for peer `%s' using address `%s'\n",
1191               GNUNET_i2s (&address->peer),
1192               (NULL != address) ? GST_plugins_a2s (address) : "<none>");
1193   msg = compose_validation_iterate_response_message (&address->peer, address);
1194   msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1195   msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1196   msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1197   msg->state = htonl ((uint32_t) state);
1198   GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1199   GNUNET_free (msg);
1200 }
1201
1202
1203 /**
1204  * Output information of neighbours to the given client.
1205  *
1206  * @param cls the `struct PeerIterationContext *`
1207  * @param peer identity of the neighbour
1208  * @param address the address
1209  * @param state current state this peer is in
1210  * @param state_timeout timeout for the current state of the peer
1211  * @param bandwidth_in inbound quota in NBO
1212  * @param bandwidth_out outbound quota in NBO
1213  */
1214 static void
1215 send_peer_information (void *cls,
1216                        const struct GNUNET_PeerIdentity *peer,
1217                        const struct GNUNET_HELLO_Address *address,
1218                        enum GNUNET_TRANSPORT_PeerState state,
1219                        struct GNUNET_TIME_Absolute state_timeout,
1220                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1221                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1222 {
1223   struct IterationContext *pc = cls;
1224   struct PeerIterateResponseMessage *msg;
1225
1226   if ( (GNUNET_YES != pc->all) &&
1227        (0 != memcmp (peer, &pc->id, sizeof (pc->id))) )
1228     return;
1229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1230               "Sending information about `%s' using address `%s' in state `%s'\n",
1231               GNUNET_i2s(peer),
1232               (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1233               GNUNET_TRANSPORT_ps2s (state));
1234   msg = compose_address_iterate_response_message (peer, address);
1235   msg->state = htonl (state);
1236   msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1237   GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1238   GNUNET_free (msg);
1239 }
1240
1241
1242 /**
1243  * Client asked to obtain information about a specific or all peers
1244  * Process the request.
1245  *
1246  * @param cls unused
1247  * @param client the client
1248  * @param message the peer address information request
1249  */
1250 static void
1251 clients_handle_monitor_peers (void *cls,
1252                               struct GNUNET_SERVER_Client *client,
1253                               const struct GNUNET_MessageHeader *message)
1254 {
1255   struct GNUNET_SERVER_TransmitContext *tc;
1256   const struct PeerMonitorMessage *msg;
1257   struct IterationContext pc;
1258
1259   msg = (const struct PeerMonitorMessage *) message;
1260   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1261        (NULL != lookup_monitoring_client (peer_monitoring_clients_head,
1262                                           client)) )
1263   {
1264     GNUNET_break (0);
1265     GNUNET_SERVER_receive_done (client,
1266                                 GNUNET_SYSERR);
1267     return;
1268   }
1269   GNUNET_SERVER_disable_receive_done_warning (client);
1270   GNUNET_SERVER_client_mark_monitor (client);
1271   pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1272
1273   /* Send initial list */
1274   if (0 == memcmp (&msg->peer,
1275                    &all_zeros,
1276                    sizeof (struct GNUNET_PeerIdentity)))
1277   {
1278     /* iterate over all neighbours */
1279     pc.all = GNUNET_YES;
1280     pc.id = msg->peer;
1281   }
1282   else
1283   {
1284     /* just return one neighbour */
1285     pc.all = GNUNET_NO;
1286     pc.id = msg->peer;
1287   }
1288   GST_neighbours_iterate (&send_peer_information,
1289                           &pc);
1290
1291   if (GNUNET_YES != ntohl (msg->one_shot))
1292   {
1293     setup_peer_monitoring_client (client,
1294                                   &msg->peer);
1295   }
1296   else
1297   {
1298     GNUNET_SERVER_transmit_context_append_data (tc,
1299                                                 NULL,
1300                                                 0,
1301                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1302   }
1303   GNUNET_SERVER_transmit_context_run (tc,
1304                                       GNUNET_TIME_UNIT_FOREVER_REL);
1305 }
1306
1307
1308 /**
1309  * Client asked to obtain information about a specific or all validation
1310  * processes
1311  *
1312  * @param cls unused
1313  * @param client the client
1314  * @param message the peer address information request
1315  */
1316 static void
1317 clients_handle_monitor_validation (void *cls,
1318                                    struct GNUNET_SERVER_Client *client,
1319                                    const struct GNUNET_MessageHeader *message)
1320 {
1321   struct GNUNET_SERVER_TransmitContext *tc;
1322   struct PeerMonitorMessage *msg;
1323   struct IterationContext pc;
1324
1325   if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST)
1326   {
1327     GNUNET_break (0);
1328     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1329     return;
1330   }
1331   if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage))
1332   {
1333     GNUNET_break (0);
1334     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1335     return;
1336   }
1337   msg = (struct PeerMonitorMessage *) message;
1338   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1339        (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) )
1340   {
1341     GNUNET_break (0);
1342     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1343     return;
1344   }
1345   GNUNET_SERVER_disable_receive_done_warning (client);
1346   GNUNET_SERVER_client_mark_monitor (client);
1347   pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1348
1349   /* Send initial list */
1350   if (0 == memcmp (&msg->peer,
1351                    &all_zeros,
1352                    sizeof (struct GNUNET_PeerIdentity)))
1353   {
1354     /* iterate over all neighbours */
1355     pc.all = GNUNET_YES;
1356     pc.id = msg->peer;
1357   }
1358   else
1359   {
1360     /* just return one neighbour */
1361     pc.all = GNUNET_NO;
1362     pc.id = msg->peer;
1363   }
1364   GST_validation_iterate (&send_validation_information,
1365                           &pc);
1366
1367   if (GNUNET_YES != ntohl (msg->one_shot))
1368   {
1369     setup_val_monitoring_client (client, &msg->peer);
1370   }
1371   else
1372   {
1373     GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
1374                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1375   }
1376   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1377 }
1378
1379
1380 /**
1381  * Function called by the plugin with information about the
1382  * current sessions managed by the plugin (for monitoring).
1383  *
1384  * @param cls closure
1385  * @param session session handle this information is about,
1386  *        NULL to indicate that we are "in sync" (initial
1387  *        iteration complete)
1388  * @param info information about the state of the session,
1389  *        NULL if @a session is also NULL and we are
1390  *        merely signalling that the initial iteration is over
1391  */
1392 static void
1393 plugin_session_info_cb (void *cls,
1394                         struct GNUNET_ATS_Session *session,
1395                         const struct GNUNET_TRANSPORT_SessionInfo *info)
1396 {
1397   struct TransportPluginMonitorMessage *msg;
1398   struct GNUNET_MessageHeader sync;
1399   size_t size;
1400   size_t slen;
1401   uint16_t alen;
1402   char *name;
1403   char *addr;
1404
1405   if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc))
1406   {
1407     GST_plugins_monitor_subscribe (NULL,
1408                                    NULL);
1409     return;
1410   }
1411   if ( (NULL == info) &&
1412        (NULL == session) )
1413   {
1414     /* end of initial iteration */
1415     if (NULL != sync_client)
1416     {
1417       sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1418       sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1419       GNUNET_SERVER_notification_context_unicast (plugin_nc,
1420                                                   sync_client,
1421                                                   &sync,
1422                                                   GNUNET_NO);
1423       sync_client = NULL;
1424     }
1425     return;
1426   }
1427   GNUNET_assert (NULL != info);
1428   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1429               "Plugin event for peer %s on transport %s\n",
1430               GNUNET_i2s (&info->address->peer),
1431               info->address->transport_name);
1432   slen = strlen (info->address->transport_name) + 1;
1433   alen = info->address->address_length;
1434   size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1435   if (size > UINT16_MAX)
1436   {
1437     GNUNET_break (0);
1438     return;
1439   }
1440   msg = GNUNET_malloc (size);
1441   msg->header.size = htons (size);
1442   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1443   msg->session_state = htons ((uint16_t) info->state);
1444   msg->is_inbound = htons ((int16_t) info->is_inbound);
1445   msg->msgs_pending = htonl (info->num_msg_pending);
1446   msg->bytes_pending = htonl (info->num_bytes_pending);
1447   msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1448   msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1449   msg->peer = info->address->peer;
1450   msg->session_id = (uint64_t) (intptr_t) session;
1451   msg->plugin_name_len = htons (slen);
1452   msg->plugin_address_len = htons (alen);
1453   name = (char *) &msg[1];
1454   memcpy (name,
1455           info->address->transport_name,
1456           slen);
1457   addr = &name[slen];
1458   memcpy (addr,
1459           info->address->address,
1460           alen);
1461   if (NULL != sync_client)
1462     GNUNET_SERVER_notification_context_unicast (plugin_nc,
1463                                                 sync_client,
1464                                                 &msg->header,
1465                                                 GNUNET_NO);
1466   else
1467     GNUNET_SERVER_notification_context_broadcast (plugin_nc,
1468                                                   &msg->header,
1469                                                   GNUNET_NO);
1470   GNUNET_free (msg);
1471 }
1472
1473
1474 /**
1475  * Client asked to obtain information about all plugin connections.
1476  *
1477  * @param cls unused
1478  * @param client the client
1479  * @param message the peer address information request
1480  */
1481 static void
1482 clients_handle_monitor_plugins (void *cls,
1483                                 struct GNUNET_SERVER_Client *client,
1484                                 const struct GNUNET_MessageHeader *message)
1485 {
1486   GNUNET_SERVER_client_mark_monitor (client);
1487   GNUNET_SERVER_disable_receive_done_warning (client);
1488   GNUNET_SERVER_notification_context_add (plugin_nc,
1489                                           client);
1490   GNUNET_assert (NULL == sync_client);
1491   sync_client = client;
1492   GST_plugins_monitor_subscribe (&plugin_session_info_cb,
1493                                  NULL);
1494 }
1495
1496
1497 /**
1498  * Start handling requests from clients.
1499  *
1500  * @param server server used to accept clients from.
1501  */
1502 void
1503 GST_clients_start (struct GNUNET_SERVER_Handle *server)
1504 {
1505   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1506     {&clients_handle_start, NULL,
1507      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
1508     {&clients_handle_hello, NULL,
1509      GNUNET_MESSAGE_TYPE_HELLO, 0},
1510     {&clients_handle_send, NULL,
1511      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
1512     {&clients_handle_address_to_string, NULL,
1513      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
1514     {&clients_handle_monitor_peers, NULL,
1515      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
1516      sizeof (struct PeerMonitorMessage)},
1517     {&clients_handle_monitor_validation, NULL,
1518      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST,
1519      sizeof (struct ValidationMonitorMessage)},
1520     {&GST_blacklist_handle_init, NULL,
1521      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
1522      sizeof (struct GNUNET_MessageHeader)},
1523     {&GST_blacklist_handle_reply, NULL,
1524      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
1525      sizeof (struct BlacklistMessage)},
1526     {&GST_manipulation_set_metric, NULL,
1527      GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
1528      sizeof (struct TrafficMetricMessage) },
1529     {&clients_handle_monitor_plugins, NULL,
1530      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
1531      sizeof (struct GNUNET_MessageHeader) },
1532     {NULL, NULL, 0, 0}
1533   };
1534   active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
1535                                                        GNUNET_YES);
1536   peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
1537   val_nc = GNUNET_SERVER_notification_context_create (server, 0);
1538   plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
1539   GNUNET_SERVER_add_handlers (server, handlers);
1540   GNUNET_SERVER_disconnect_notify (server,
1541                                    &client_disconnect_notification,
1542                                    NULL);
1543 }
1544
1545
1546 /**
1547  * Stop processing clients.
1548  */
1549 void
1550 GST_clients_stop ()
1551 {
1552   struct AddressToStringContext *cur;
1553
1554   while (NULL != (cur = a2s_head))
1555   {
1556     GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO);
1557     GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
1558     GNUNET_free (cur);
1559   }
1560   if (NULL != peer_nc)
1561   {
1562     GNUNET_SERVER_notification_context_destroy (peer_nc);
1563     peer_nc = NULL;
1564   }
1565   if (NULL != val_nc)
1566   {
1567     GNUNET_SERVER_notification_context_destroy (val_nc);
1568     val_nc = NULL;
1569   }
1570   if (NULL != plugin_nc)
1571   {
1572     GNUNET_SERVER_notification_context_destroy (plugin_nc);
1573     plugin_nc = NULL;
1574   }
1575   GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
1576   active_stccs = NULL;
1577 }
1578
1579
1580 /**
1581  * Broadcast the given message to all of our clients.
1582  *
1583  * @param msg message to broadcast
1584  * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1585  */
1586 void
1587 GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1588                        int may_drop)
1589 {
1590   struct TransportClient *tc;
1591
1592   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1593               "Asked to broadcast message of type %u with %u bytes\n",
1594               (unsigned int) ntohs (msg->type),
1595               (unsigned int) ntohs (msg->size));
1596   for (tc = clients_head; NULL != tc; tc = tc->next)
1597   {
1598     if ( (GNUNET_YES == may_drop) &&
1599          (GNUNET_YES != tc->send_payload) )
1600       continue; /* skip, this client does not care about payload */
1601     unicast (tc, msg, may_drop);
1602   }
1603 }
1604
1605
1606 /**
1607  * Send the given message to a particular client
1608  *
1609  * @param client target of the message
1610  * @param msg message to transmit
1611  * @param may_drop #GNUNET_YES if the message can be dropped
1612  */
1613 void
1614 GST_clients_unicast (struct GNUNET_SERVER_Client *client,
1615                      const struct GNUNET_MessageHeader *msg,
1616                      int may_drop)
1617 {
1618   struct TransportClient *tc;
1619
1620   tc = lookup_client (client);
1621   if (NULL == tc)
1622     return;                     /* client got disconnected in the meantime, drop message */
1623   unicast (tc, msg, may_drop);
1624 }
1625
1626
1627 /**
1628  * Broadcast the new active address to all clients monitoring the peer.
1629  *
1630  * @param peer peer this update is about (never NULL)
1631  * @param address address, NULL on disconnect
1632  * @param state the current state of the peer
1633  * @param state_timeout the time out for the state
1634  */
1635 void
1636 GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1637                                          const struct GNUNET_HELLO_Address *address,
1638                                          enum GNUNET_TRANSPORT_PeerState state,
1639                                          struct GNUNET_TIME_Absolute state_timeout)
1640 {
1641   struct PeerIterateResponseMessage *msg;
1642   struct MonitoringClient *mc;
1643
1644   msg = compose_address_iterate_response_message (peer, address);
1645   msg->state = htonl (state);
1646   msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1647   for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next)
1648     if ((0 == memcmp (&mc->peer, &all_zeros,
1649                       sizeof (struct GNUNET_PeerIdentity))) ||
1650         (0 == memcmp (&mc->peer, peer,
1651                       sizeof (struct GNUNET_PeerIdentity))))
1652       GNUNET_SERVER_notification_context_unicast (peer_nc,
1653                                                   mc->client,
1654                                                   &msg->header,
1655                                                   GNUNET_NO);
1656   GNUNET_free (msg);
1657 }
1658
1659
1660 /**
1661  * Broadcast the new validation changes to all clients monitoring the peer.
1662  *
1663  * @param peer peer this update is about (never NULL)
1664  * @param address address, NULL on disconnect
1665  * @param last_validation point in time when last validation was performed
1666  * @param valid_until point in time how long address is valid
1667  * @param next_validation point in time when next validation will be performed
1668  * @param state state of validation notification
1669  */
1670 void
1671 GST_clients_broadcast_validation_notification (const struct GNUNET_PeerIdentity *peer,
1672                                                const struct GNUNET_HELLO_Address *address,
1673                                                struct GNUNET_TIME_Absolute last_validation,
1674                                                struct GNUNET_TIME_Absolute valid_until,
1675                                                struct GNUNET_TIME_Absolute next_validation,
1676                                                enum GNUNET_TRANSPORT_ValidationState state)
1677 {
1678   struct ValidationIterateResponseMessage *msg;
1679   struct MonitoringClient *mc;
1680
1681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1682               "Sending information about for validation entry for peer `%s' using address `%s'\n",
1683               GNUNET_i2s(peer),
1684               (address != NULL) ? GST_plugins_a2s (address) : "<none>");
1685   msg = compose_validation_iterate_response_message (peer, address);
1686   msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1687   msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1688   msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1689   msg->state = htonl ((uint32_t) state);
1690   for (mc = val_monitoring_clients_head; NULL != mc; mc = mc->next)
1691     if ((0 == memcmp (&mc->peer, &all_zeros,
1692                       sizeof (struct GNUNET_PeerIdentity))) ||
1693         (0 == memcmp (&mc->peer, peer,
1694                       sizeof (struct GNUNET_PeerIdentity))))
1695       GNUNET_SERVER_notification_context_unicast (val_nc,
1696                                                   mc->client,
1697                                                   &msg->header,
1698                                                   GNUNET_NO);
1699   GNUNET_free (msg);
1700 }
1701
1702
1703 /**
1704  * Mark the peer as down so we don't call the continuation
1705  * context in the future.
1706  *
1707  * @param cls NULL
1708  * @param peer peer that got disconnected
1709  * @param value a `struct SendTransmitContinuationContext` to mark
1710  * @return #GNUNET_OK (continue to iterate)
1711  */
1712 static int
1713 mark_peer_down (void *cls,
1714                 const struct GNUNET_PeerIdentity *peer,
1715                 void *value)
1716 {
1717   struct SendTransmitContinuationContext *stcc = value;
1718
1719   stcc->down = GNUNET_YES;
1720   return GNUNET_OK;
1721 }
1722
1723
1724 /**
1725  * Notify all clients about a disconnect, and cancel
1726  * pending SEND_OK messages for this peer.
1727  *
1728  * @param peer peer that disconnected
1729  */
1730 void
1731 GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1732 {
1733   struct DisconnectInfoMessage disconnect_msg;
1734
1735   GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1736                                               peer,
1737                                               &mark_peer_down,
1738                                               NULL);
1739   disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1740   disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1741   disconnect_msg.reserved = htonl (0);
1742   disconnect_msg.peer = *peer;
1743   GST_clients_broadcast (&disconnect_msg.header,
1744                          GNUNET_NO);
1745
1746 }
1747
1748
1749 /* end of file gnunet-service-transport_clients.c */