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