-preparations for replacement of try_connect call
[oweals/gnunet.git] / src / transport / gnunet-service-transport_clients.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015 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., 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  * Handle request connect message
880  *
881  * @param cls closure (always NULL)
882  * @param client identification of the client
883  * @param message the actual message
884  */
885 static void
886 clients_handle_request_connect (void *cls,
887                                 struct GNUNET_SERVER_Client *client,
888                                 const struct GNUNET_MessageHeader *message)
889 {
890   const struct TransportRequestConnectMessage *trcm;
891
892   trcm = (const struct TransportRequestConnectMessage *) message;
893   GNUNET_break (0 == ntohl (trcm->reserved));
894   GNUNET_STATISTICS_update (GST_stats,
895                             gettext_noop
896                             ("# REQUEST CONNECT messages received"), 1,
897                             GNUNET_NO);
898   if (0 == memcmp (&trcm->peer,
899                    &GST_my_identity,
900                    sizeof (struct GNUNET_PeerIdentity)))
901   {
902     GNUNET_break (0);
903     GNUNET_SERVER_receive_done (client,
904                                 GNUNET_OK);
905     return;
906   }
907   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908               "Received a request connect message for peer `%s'\n",
909               GNUNET_i2s (&trcm->peer));
910   GST_neighbours_try_connect (&trcm->peer);
911   GNUNET_SERVER_receive_done (client, GNUNET_OK);
912 }
913
914
915 /**
916  * Take the given address and append it to the set of results sent back to
917  * the client.  This function may be called serveral times for a single
918  * conversion.   The last invocation will be with a @a address of
919  * NULL and a @a res of #GNUNET_OK.  Thus, to indicate conversion
920  * errors, the callback might be called first with @a address NULL and
921  * @a res being #GNUNET_SYSERR.  In that case, there will still be a
922  * subsequent call later with @a address NULL and @a res #GNUNET_OK.
923  *
924  * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
925  * @param buf text to transmit (contains the human-readable address, or NULL)
926  * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
927  *            never #GNUNET_NO
928  */
929 static void
930 transmit_address_to_client (void *cls,
931                             const char *buf,
932                             int res)
933 {
934   struct AddressToStringContext *actx = cls;
935   struct AddressToStringResultMessage *atsm;
936   size_t len;
937   size_t slen;
938
939   GNUNET_assert ( (GNUNET_OK == res) ||
940                   (GNUNET_SYSERR == res) );
941   if (NULL == buf)
942   {
943     len = sizeof (struct AddressToStringResultMessage);
944     atsm = GNUNET_malloc (len);
945     atsm->header.size = ntohs (len);
946     atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
947     if (GNUNET_OK == res)
948     {
949       /* this was the last call, transmit */
950       atsm->res = htonl (GNUNET_OK);
951       atsm->addr_len = htonl (0);
952       GNUNET_SERVER_transmit_context_append_message (actx->tc,
953                                                      (const struct GNUNET_MessageHeader *) atsm);
954       GNUNET_SERVER_transmit_context_run (actx->tc,
955                                           GNUNET_TIME_UNIT_FOREVER_REL);
956       GNUNET_CONTAINER_DLL_remove (a2s_head,
957                                    a2s_tail,
958                                    actx);
959       GNUNET_free (atsm);
960       GNUNET_free (actx);
961       return;
962     }
963     if (GNUNET_SYSERR == res)
964     {
965       /* address conversion failed, but there will be more callbacks */
966       atsm->res = htonl (GNUNET_SYSERR);
967       atsm->addr_len = htonl (0);
968       GNUNET_SERVER_transmit_context_append_message (actx->tc,
969                                                      (const struct GNUNET_MessageHeader *) atsm);
970       GNUNET_free (atsm);
971       return;
972     }
973   }
974   GNUNET_assert (GNUNET_OK == res);
975   /* succesful conversion, append*/
976   slen = strlen (buf) + 1;
977   len = sizeof (struct AddressToStringResultMessage) + slen;
978   atsm = GNUNET_malloc (len);
979   atsm->header.size = ntohs (len);
980   atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
981   atsm->res = htonl (GNUNET_YES);
982   atsm->addr_len = htonl (slen);
983   memcpy (&atsm[1],
984           buf,
985           slen);
986   GNUNET_SERVER_transmit_context_append_message (actx->tc,
987                                                  (const struct GNUNET_MessageHeader *) atsm);
988   GNUNET_free (atsm);
989 }
990
991
992 /**
993  * Client asked to resolve an address.  Process the request.
994  *
995  * @param cls unused
996  * @param client the client
997  * @param message the resolution request
998  */
999 static void
1000 clients_handle_address_to_string (void *cls,
1001                                   struct GNUNET_SERVER_Client *client,
1002                                   const struct GNUNET_MessageHeader *message)
1003 {
1004   const struct AddressLookupMessage *alum;
1005   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1006   const char *plugin_name;
1007   const char *address;
1008   uint32_t address_len;
1009   uint16_t size;
1010   struct GNUNET_SERVER_TransmitContext *tc;
1011   struct AddressToStringContext *actx;
1012   struct AddressToStringResultMessage atsm;
1013   struct GNUNET_TIME_Relative rtimeout;
1014   int32_t numeric;
1015
1016   size = ntohs (message->size);
1017   if (size < sizeof (struct AddressLookupMessage))
1018   {
1019     GNUNET_break (0);
1020     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1021     return;
1022   }
1023   alum = (const struct AddressLookupMessage *) message;
1024   address_len = ntohs (alum->addrlen);
1025   if (size <= sizeof (struct AddressLookupMessage) + address_len)
1026   {
1027     GNUNET_break (0);
1028     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1029     return;
1030   }
1031   address = (const char *) &alum[1];
1032   plugin_name = (const char *) &address[address_len];
1033   if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
1034   {
1035     GNUNET_break (0);
1036     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1037     return;
1038   }
1039   rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
1040   numeric = ntohs (alum->numeric_only);
1041   tc = GNUNET_SERVER_transmit_context_create (client);
1042   papi = GST_plugins_printer_find (plugin_name);
1043   if (NULL == papi)
1044   {
1045     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1046                 "Failed to find plugin `%s'\n",
1047                 plugin_name);
1048     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1049     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1050     atsm.res = htonl (GNUNET_SYSERR);
1051     atsm.addr_len = htonl (0);
1052     GNUNET_SERVER_transmit_context_append_message (tc,
1053                                                    &atsm.header);
1054     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
1055     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
1056     atsm.res = htonl (GNUNET_OK);
1057     atsm.addr_len = htonl (0);
1058     GNUNET_SERVER_transmit_context_append_message (tc,
1059                                                    &atsm.header);
1060     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1061     return;
1062   }
1063   actx = GNUNET_new (struct AddressToStringContext);
1064   actx->tc = tc;
1065   GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
1066   GNUNET_SERVER_disable_receive_done_warning (client);
1067   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068               "Pretty-printing address of %u bytes using plugin `%s'\n",
1069               address_len,
1070               plugin_name);
1071   papi->address_pretty_printer (papi->cls,
1072                                 plugin_name,
1073                                 address, address_len,
1074                                 numeric,
1075                                 rtimeout,
1076                                 &transmit_address_to_client,
1077                                 actx);
1078 }
1079
1080
1081 /**
1082  * Compose #PeerIterateResponseMessage using the given peer and address.
1083  *
1084  * @param peer identity of the peer
1085  * @param address the address, NULL on disconnect
1086  * @return composed message
1087  */
1088 static struct PeerIterateResponseMessage *
1089 compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1090                                           const struct GNUNET_HELLO_Address *address)
1091 {
1092   struct PeerIterateResponseMessage *msg;
1093   size_t size;
1094   size_t tlen;
1095   size_t alen;
1096   char *addr;
1097
1098   GNUNET_assert (NULL != peer);
1099   if (NULL != address)
1100   {
1101     tlen = strlen (address->transport_name) + 1;
1102     alen = address->address_length;
1103   }
1104   else
1105   {
1106     tlen = 0;
1107     alen = 0;
1108   }
1109   size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1110   msg = GNUNET_malloc (size);
1111   msg->header.size = htons (size);
1112   msg->header.type =
1113       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1114   msg->reserved = htonl (0);
1115   msg->peer = *peer;
1116   msg->addrlen = htonl (alen);
1117   msg->pluginlen = htonl (tlen);
1118
1119   if (NULL != address)
1120   {
1121     msg->local_address_info = htonl((uint32_t) address->local_info);
1122     addr = (char *) &msg[1];
1123     memcpy (addr, address->address, alen);
1124     memcpy (&addr[alen], address->transport_name, tlen);
1125   }
1126   return msg;
1127 }
1128
1129
1130 /**
1131  * Compose #PeerIterateResponseMessage using the given peer and address.
1132  *
1133  * @param peer identity of the peer
1134  * @param address the address, NULL on disconnect
1135  * @return composed message
1136  */
1137 static struct ValidationIterateResponseMessage *
1138 compose_validation_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
1139                                              const struct GNUNET_HELLO_Address *address)
1140 {
1141   struct ValidationIterateResponseMessage *msg;
1142   size_t size;
1143   size_t tlen;
1144   size_t alen;
1145   char *addr;
1146
1147   GNUNET_assert (NULL != peer);
1148   if (NULL != address)
1149   {
1150     tlen = strlen (address->transport_name) + 1;
1151     alen = address->address_length;
1152   }
1153   else
1154   {
1155     tlen = 0;
1156     alen = 0;
1157   }
1158   size = (sizeof (struct ValidationIterateResponseMessage) + alen + tlen);
1159   msg = GNUNET_malloc (size);
1160   msg->header.size = htons (size);
1161   msg->header.type =
1162       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1163   msg->reserved = htonl (0);
1164   msg->peer = *peer;
1165   msg->addrlen = htonl (alen);
1166   msg->pluginlen = htonl (tlen);
1167
1168   if (NULL != address)
1169   {
1170     msg->local_address_info = htonl((uint32_t) address->local_info);
1171     addr = (char *) &msg[1];
1172     memcpy (addr, address->address, alen);
1173     memcpy (&addr[alen], address->transport_name, tlen);
1174   }
1175   return msg;
1176 }
1177
1178
1179 /**
1180  * Context for #send_validation_information() and
1181  * #send_peer_information().
1182  */
1183 struct IterationContext
1184 {
1185   /**
1186    * Context to use for the transmission.
1187    */
1188   struct GNUNET_SERVER_TransmitContext *tc;
1189
1190   /**
1191    * Which peers do we care about?
1192    */
1193   struct GNUNET_PeerIdentity id;
1194
1195   /**
1196    * #GNUNET_YES if @e id should be ignored because we want all peers.
1197    */
1198   int all;
1199 };
1200
1201
1202 /**
1203  * Output information of validation entries to the given client.
1204  *
1205  * @param cls the `struct IterationContext *`
1206  * @param address the address
1207  * @param last_validation point in time when last validation was performed
1208  * @param valid_until point in time how long address is valid
1209  * @param next_validation point in time when next validation will be performed
1210  * @param state state of validation notification
1211  */
1212 static void
1213 send_validation_information (void *cls,
1214                              const struct GNUNET_HELLO_Address *address,
1215                              struct GNUNET_TIME_Absolute last_validation,
1216                              struct GNUNET_TIME_Absolute valid_until,
1217                              struct GNUNET_TIME_Absolute next_validation,
1218                              enum GNUNET_TRANSPORT_ValidationState state)
1219 {
1220   struct IterationContext *pc = cls;
1221   struct ValidationIterateResponseMessage *msg;
1222
1223   if ( (GNUNET_YES != pc->all) &&
1224        (0 != memcmp (&address->peer, &pc->id, sizeof (pc->id))) )
1225     return;
1226   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227               "Sending information about for validation entry for peer `%s' using address `%s'\n",
1228               GNUNET_i2s (&address->peer),
1229               (NULL != address) ? GST_plugins_a2s (address) : "<none>");
1230   msg = compose_validation_iterate_response_message (&address->peer, address);
1231   msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1232   msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1233   msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1234   msg->state = htonl ((uint32_t) state);
1235   GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1236   GNUNET_free (msg);
1237 }
1238
1239
1240 /**
1241  * Output information of neighbours to the given client.
1242  *
1243  * @param cls the `struct PeerIterationContext *`
1244  * @param peer identity of the neighbour
1245  * @param address the address
1246  * @param state current state this peer is in
1247  * @param state_timeout timeout for the current state of the peer
1248  * @param bandwidth_in inbound quota in NBO
1249  * @param bandwidth_out outbound quota in NBO
1250  */
1251 static void
1252 send_peer_information (void *cls,
1253                        const struct GNUNET_PeerIdentity *peer,
1254                        const struct GNUNET_HELLO_Address *address,
1255                        enum GNUNET_TRANSPORT_PeerState state,
1256                        struct GNUNET_TIME_Absolute state_timeout,
1257                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1258                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1259 {
1260   struct IterationContext *pc = cls;
1261   struct PeerIterateResponseMessage *msg;
1262
1263   if ( (GNUNET_YES != pc->all) &&
1264        (0 != memcmp (peer, &pc->id, sizeof (pc->id))) )
1265     return;
1266   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1267               "Sending information about `%s' using address `%s' in state `%s'\n",
1268               GNUNET_i2s(peer),
1269               (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1270               GNUNET_TRANSPORT_ps2s (state));
1271   msg = compose_address_iterate_response_message (peer, address);
1272   msg->state = htonl (state);
1273   msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1274   GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1275   GNUNET_free (msg);
1276 }
1277
1278
1279 /**
1280  * Client asked to obtain information about a specific or all peers
1281  * Process the request.
1282  *
1283  * @param cls unused
1284  * @param client the client
1285  * @param message the peer address information request
1286  */
1287 static void
1288 clients_handle_monitor_peers (void *cls,
1289                               struct GNUNET_SERVER_Client *client,
1290                               const struct GNUNET_MessageHeader *message)
1291 {
1292   struct GNUNET_SERVER_TransmitContext *tc;
1293   const struct PeerMonitorMessage *msg;
1294   struct IterationContext pc;
1295
1296   msg = (const struct PeerMonitorMessage *) message;
1297   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1298        (NULL != lookup_monitoring_client (peer_monitoring_clients_head,
1299                                           client)) )
1300   {
1301     GNUNET_break (0);
1302     GNUNET_SERVER_receive_done (client,
1303                                 GNUNET_SYSERR);
1304     return;
1305   }
1306   GNUNET_SERVER_disable_receive_done_warning (client);
1307   GNUNET_SERVER_client_mark_monitor (client);
1308   pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1309
1310   /* Send initial list */
1311   if (0 == memcmp (&msg->peer,
1312                    &all_zeros,
1313                    sizeof (struct GNUNET_PeerIdentity)))
1314   {
1315     /* iterate over all neighbours */
1316     pc.all = GNUNET_YES;
1317     pc.id = msg->peer;
1318   }
1319   else
1320   {
1321     /* just return one neighbour */
1322     pc.all = GNUNET_NO;
1323     pc.id = msg->peer;
1324   }
1325   GST_neighbours_iterate (&send_peer_information,
1326                           &pc);
1327
1328   if (GNUNET_YES != ntohl (msg->one_shot))
1329   {
1330     setup_peer_monitoring_client (client,
1331                                   &msg->peer);
1332   }
1333   else
1334   {
1335     GNUNET_SERVER_transmit_context_append_data (tc,
1336                                                 NULL,
1337                                                 0,
1338                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1339   }
1340   GNUNET_SERVER_transmit_context_run (tc,
1341                                       GNUNET_TIME_UNIT_FOREVER_REL);
1342 }
1343
1344
1345 /**
1346  * Client asked to obtain information about a specific or all validation
1347  * processes
1348  *
1349  * @param cls unused
1350  * @param client the client
1351  * @param message the peer address information request
1352  */
1353 static void
1354 clients_handle_monitor_validation (void *cls,
1355                                    struct GNUNET_SERVER_Client *client,
1356                                    const struct GNUNET_MessageHeader *message)
1357 {
1358   struct GNUNET_SERVER_TransmitContext *tc;
1359   struct PeerMonitorMessage *msg;
1360   struct IterationContext pc;
1361
1362   if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST)
1363   {
1364     GNUNET_break (0);
1365     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1366     return;
1367   }
1368   if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage))
1369   {
1370     GNUNET_break (0);
1371     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1372     return;
1373   }
1374   msg = (struct PeerMonitorMessage *) message;
1375   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1376        (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) )
1377   {
1378     GNUNET_break (0);
1379     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1380     return;
1381   }
1382   GNUNET_SERVER_disable_receive_done_warning (client);
1383   GNUNET_SERVER_client_mark_monitor (client);
1384   pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1385
1386   /* Send initial list */
1387   if (0 == memcmp (&msg->peer,
1388                    &all_zeros,
1389                    sizeof (struct GNUNET_PeerIdentity)))
1390   {
1391     /* iterate over all neighbours */
1392     pc.all = GNUNET_YES;
1393     pc.id = msg->peer;
1394   }
1395   else
1396   {
1397     /* just return one neighbour */
1398     pc.all = GNUNET_NO;
1399     pc.id = msg->peer;
1400   }
1401   GST_validation_iterate (&send_validation_information,
1402                           &pc);
1403
1404   if (GNUNET_YES != ntohl (msg->one_shot))
1405   {
1406     setup_val_monitoring_client (client, &msg->peer);
1407   }
1408   else
1409   {
1410     GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
1411                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
1412   }
1413   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
1414 }
1415
1416
1417 /**
1418  * Function called by the plugin with information about the
1419  * current sessions managed by the plugin (for monitoring).
1420  *
1421  * @param cls closure
1422  * @param session session handle this information is about,
1423  *        NULL to indicate that we are "in sync" (initial
1424  *        iteration complete)
1425  * @param info information about the state of the session,
1426  *        NULL if @a session is also NULL and we are
1427  *        merely signalling that the initial iteration is over
1428  */
1429 static void
1430 plugin_session_info_cb (void *cls,
1431                         struct GNUNET_ATS_Session *session,
1432                         const struct GNUNET_TRANSPORT_SessionInfo *info)
1433 {
1434   struct TransportPluginMonitorMessage *msg;
1435   struct GNUNET_MessageHeader sync;
1436   size_t size;
1437   size_t slen;
1438   uint16_t alen;
1439   char *name;
1440   char *addr;
1441
1442   if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc))
1443   {
1444     GST_plugins_monitor_subscribe (NULL,
1445                                    NULL);
1446     return;
1447   }
1448   if ( (NULL == info) &&
1449        (NULL == session) )
1450   {
1451     /* end of initial iteration */
1452     if (NULL != sync_client)
1453     {
1454       sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1455       sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1456       GNUNET_SERVER_notification_context_unicast (plugin_nc,
1457                                                   sync_client,
1458                                                   &sync,
1459                                                   GNUNET_NO);
1460       sync_client = NULL;
1461     }
1462     return;
1463   }
1464   GNUNET_assert (NULL != info);
1465   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1466               "Plugin event for peer %s on transport %s\n",
1467               GNUNET_i2s (&info->address->peer),
1468               info->address->transport_name);
1469   slen = strlen (info->address->transport_name) + 1;
1470   alen = info->address->address_length;
1471   size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1472   if (size > UINT16_MAX)
1473   {
1474     GNUNET_break (0);
1475     return;
1476   }
1477   msg = GNUNET_malloc (size);
1478   msg->header.size = htons (size);
1479   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1480   msg->session_state = htons ((uint16_t) info->state);
1481   msg->is_inbound = htons ((int16_t) info->is_inbound);
1482   msg->msgs_pending = htonl (info->num_msg_pending);
1483   msg->bytes_pending = htonl (info->num_bytes_pending);
1484   msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1485   msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1486   msg->peer = info->address->peer;
1487   msg->session_id = (uint64_t) (intptr_t) session;
1488   msg->plugin_name_len = htons (slen);
1489   msg->plugin_address_len = htons (alen);
1490   name = (char *) &msg[1];
1491   memcpy (name,
1492           info->address->transport_name,
1493           slen);
1494   addr = &name[slen];
1495   memcpy (addr,
1496           info->address->address,
1497           alen);
1498   if (NULL != sync_client)
1499     GNUNET_SERVER_notification_context_unicast (plugin_nc,
1500                                                 sync_client,
1501                                                 &msg->header,
1502                                                 GNUNET_NO);
1503   else
1504     GNUNET_SERVER_notification_context_broadcast (plugin_nc,
1505                                                   &msg->header,
1506                                                   GNUNET_NO);
1507   GNUNET_free (msg);
1508 }
1509
1510
1511 /**
1512  * Client asked to obtain information about all plugin connections.
1513  *
1514  * @param cls unused
1515  * @param client the client
1516  * @param message the peer address information request
1517  */
1518 static void
1519 clients_handle_monitor_plugins (void *cls,
1520                                 struct GNUNET_SERVER_Client *client,
1521                                 const struct GNUNET_MessageHeader *message)
1522 {
1523   GNUNET_SERVER_client_mark_monitor (client);
1524   GNUNET_SERVER_disable_receive_done_warning (client);
1525   GNUNET_SERVER_notification_context_add (plugin_nc,
1526                                           client);
1527   GNUNET_assert (NULL == sync_client);
1528   sync_client = client;
1529   GST_plugins_monitor_subscribe (&plugin_session_info_cb,
1530                                  NULL);
1531 }
1532
1533
1534 /**
1535  * Start handling requests from clients.
1536  *
1537  * @param server server used to accept clients from.
1538  */
1539 void
1540 GST_clients_start (struct GNUNET_SERVER_Handle *server)
1541 {
1542   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1543     {&clients_handle_start, NULL,
1544      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
1545     {&clients_handle_hello, NULL,
1546      GNUNET_MESSAGE_TYPE_HELLO, 0},
1547     {&clients_handle_send, NULL,
1548      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
1549     {&clients_handle_request_connect, NULL,
1550      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
1551      sizeof (struct TransportRequestConnectMessage)},
1552     {&clients_handle_address_to_string, NULL,
1553      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
1554     {&clients_handle_monitor_peers, NULL,
1555      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
1556      sizeof (struct PeerMonitorMessage)},
1557     {&clients_handle_monitor_validation, NULL,
1558      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST,
1559      sizeof (struct ValidationMonitorMessage)},
1560     {&GST_blacklist_handle_init, NULL,
1561      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
1562      sizeof (struct GNUNET_MessageHeader)},
1563     {&GST_blacklist_handle_reply, NULL,
1564      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
1565      sizeof (struct BlacklistMessage)},
1566     {&GST_manipulation_set_metric, NULL,
1567      GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
1568      sizeof (struct TrafficMetricMessage) },
1569     {&clients_handle_monitor_plugins, NULL,
1570      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
1571      sizeof (struct GNUNET_MessageHeader) },
1572     {NULL, NULL, 0, 0}
1573   };
1574   active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
1575                                                        GNUNET_YES);
1576   peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
1577   val_nc = GNUNET_SERVER_notification_context_create (server, 0);
1578   plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
1579   GNUNET_SERVER_add_handlers (server, handlers);
1580   GNUNET_SERVER_disconnect_notify (server,
1581                                    &client_disconnect_notification,
1582                                    NULL);
1583 }
1584
1585
1586 /**
1587  * Stop processing clients.
1588  */
1589 void
1590 GST_clients_stop ()
1591 {
1592   struct AddressToStringContext *cur;
1593
1594   while (NULL != (cur = a2s_head))
1595   {
1596     GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO);
1597     GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
1598     GNUNET_free (cur);
1599   }
1600   if (NULL != peer_nc)
1601   {
1602     GNUNET_SERVER_notification_context_destroy (peer_nc);
1603     peer_nc = NULL;
1604   }
1605   if (NULL != val_nc)
1606   {
1607     GNUNET_SERVER_notification_context_destroy (val_nc);
1608     val_nc = NULL;
1609   }
1610   if (NULL != plugin_nc)
1611   {
1612     GNUNET_SERVER_notification_context_destroy (plugin_nc);
1613     plugin_nc = NULL;
1614   }
1615   GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
1616   active_stccs = NULL;
1617 }
1618
1619
1620 /**
1621  * Broadcast the given message to all of our clients.
1622  *
1623  * @param msg message to broadcast
1624  * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1625  */
1626 void
1627 GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1628                        int may_drop)
1629 {
1630   struct TransportClient *tc;
1631
1632   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1633               "Asked to broadcast message of type %u with %u bytes\n",
1634               (unsigned int) ntohs (msg->type),
1635               (unsigned int) ntohs (msg->size));
1636   for (tc = clients_head; NULL != tc; tc = tc->next)
1637   {
1638     if ( (GNUNET_YES == may_drop) &&
1639          (GNUNET_YES != tc->send_payload) )
1640       continue; /* skip, this client does not care about payload */
1641     unicast (tc, msg, may_drop);
1642   }
1643 }
1644
1645
1646 /**
1647  * Send the given message to a particular client
1648  *
1649  * @param client target of the message
1650  * @param msg message to transmit
1651  * @param may_drop #GNUNET_YES if the message can be dropped
1652  */
1653 void
1654 GST_clients_unicast (struct GNUNET_SERVER_Client *client,
1655                      const struct GNUNET_MessageHeader *msg,
1656                      int may_drop)
1657 {
1658   struct TransportClient *tc;
1659
1660   tc = lookup_client (client);
1661   if (NULL == tc)
1662     return;                     /* client got disconnected in the meantime, drop message */
1663   unicast (tc, msg, may_drop);
1664 }
1665
1666
1667 /**
1668  * Broadcast the new active address to all clients monitoring the peer.
1669  *
1670  * @param peer peer this update is about (never NULL)
1671  * @param address address, NULL on disconnect
1672  * @param state the current state of the peer
1673  * @param state_timeout the time out for the state
1674  */
1675 void
1676 GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1677                                          const struct GNUNET_HELLO_Address *address,
1678                                          enum GNUNET_TRANSPORT_PeerState state,
1679                                          struct GNUNET_TIME_Absolute state_timeout)
1680 {
1681   struct PeerIterateResponseMessage *msg;
1682   struct MonitoringClient *mc;
1683
1684   msg = compose_address_iterate_response_message (peer, address);
1685   msg->state = htonl (state);
1686   msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1687   for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next)
1688     if ((0 == memcmp (&mc->peer, &all_zeros,
1689                       sizeof (struct GNUNET_PeerIdentity))) ||
1690         (0 == memcmp (&mc->peer, peer,
1691                       sizeof (struct GNUNET_PeerIdentity))))
1692       GNUNET_SERVER_notification_context_unicast (peer_nc,
1693                                                   mc->client,
1694                                                   &msg->header,
1695                                                   GNUNET_NO);
1696   GNUNET_free (msg);
1697 }
1698
1699
1700 /**
1701  * Broadcast the new validation changes to all clients monitoring the peer.
1702  *
1703  * @param peer peer this update is about (never NULL)
1704  * @param address address, NULL on disconnect
1705  * @param last_validation point in time when last validation was performed
1706  * @param valid_until point in time how long address is valid
1707  * @param next_validation point in time when next validation will be performed
1708  * @param state state of validation notification
1709  */
1710 void
1711 GST_clients_broadcast_validation_notification (const struct GNUNET_PeerIdentity *peer,
1712                                                const struct GNUNET_HELLO_Address *address,
1713                                                struct GNUNET_TIME_Absolute last_validation,
1714                                                struct GNUNET_TIME_Absolute valid_until,
1715                                                struct GNUNET_TIME_Absolute next_validation,
1716                                                enum GNUNET_TRANSPORT_ValidationState state)
1717 {
1718   struct ValidationIterateResponseMessage *msg;
1719   struct MonitoringClient *mc;
1720
1721   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1722               "Sending information about for validation entry for peer `%s' using address `%s'\n",
1723               GNUNET_i2s(peer),
1724               (address != NULL) ? GST_plugins_a2s (address) : "<none>");
1725   msg = compose_validation_iterate_response_message (peer, address);
1726   msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
1727   msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
1728   msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
1729   msg->state = htonl ((uint32_t) state);
1730   for (mc = val_monitoring_clients_head; NULL != mc; mc = mc->next)
1731     if ((0 == memcmp (&mc->peer, &all_zeros,
1732                       sizeof (struct GNUNET_PeerIdentity))) ||
1733         (0 == memcmp (&mc->peer, peer,
1734                       sizeof (struct GNUNET_PeerIdentity))))
1735       GNUNET_SERVER_notification_context_unicast (val_nc,
1736                                                   mc->client,
1737                                                   &msg->header,
1738                                                   GNUNET_NO);
1739   GNUNET_free (msg);
1740 }
1741
1742
1743 /**
1744  * Mark the peer as down so we don't call the continuation
1745  * context in the future.
1746  *
1747  * @param cls NULL
1748  * @param peer peer that got disconnected
1749  * @param value a `struct SendTransmitContinuationContext` to mark
1750  * @return #GNUNET_OK (continue to iterate)
1751  */
1752 static int
1753 mark_peer_down (void *cls,
1754                 const struct GNUNET_PeerIdentity *peer,
1755                 void *value)
1756 {
1757   struct SendTransmitContinuationContext *stcc = value;
1758
1759   stcc->down = GNUNET_YES;
1760   return GNUNET_OK;
1761 }
1762
1763
1764 /**
1765  * Notify all clients about a disconnect, and cancel
1766  * pending SEND_OK messages for this peer.
1767  *
1768  * @param peer peer that disconnected
1769  */
1770 void
1771 GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1772 {
1773   struct DisconnectInfoMessage disconnect_msg;
1774
1775   GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1776                                               peer,
1777                                               &mark_peer_down,
1778                                               NULL);
1779   disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1780   disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1781   disconnect_msg.reserved = htonl (0);
1782   disconnect_msg.peer = *peer;
1783   GST_clients_broadcast (&disconnect_msg.header,
1784                          GNUNET_NO);
1785
1786 }
1787
1788
1789 /* end of file gnunet-service-transport_clients.c */