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