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