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