- fix coverity
[oweals/gnunet.git] / src / transport / gnunet-service-transport_clients.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file transport/gnunet-service-transport_clients.c
23  * @brief communication with clients (core service and monitors)
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-transport_blacklist.h"
28 #include "gnunet-service-transport_clients.h"
29 #include "gnunet-service-transport_hello.h"
30 #include "gnunet-service-transport_neighbours.h"
31 #include "gnunet-service-transport_plugins.h"
32 #include "gnunet-service-transport_validation.h"
33 #include "gnunet-service-transport_manipulation.h"
34 #include "gnunet-service-transport.h"
35 #include "transport.h"
36
37
38 /**
39  * How many messages can we have pending for a given client process
40  * before we start to drop incoming messages?  We typically should
41  * have only one client and so this would be the primary buffer for
42   * messages, so the number should be chosen rather generously.
43  *
44  * The expectation here is that most of the time the queue is large
45  * enough so that a drop is virtually never required.  Note that
46  * this value must be about as large as 'TOTAL_MSGS' in the
47  * 'test_transport_api_reliability.c', otherwise that testcase may
48  * fail.
49  */
50 #define MAX_PENDING (128 * 1024)
51
52
53 /**
54  * Linked list of messages to be transmitted to the client.  Each
55  * entry is followed by the actual message.
56  */
57 struct ClientMessageQueueEntry
58 {
59   /**
60    * This is a doubly-linked list.
61    */
62   struct ClientMessageQueueEntry *next;
63
64   /**
65    * This is a doubly-linked list.
66    */
67   struct ClientMessageQueueEntry *prev;
68 };
69
70
71 /**
72  * Client connected to the transport service.
73  */
74 struct TransportClient
75 {
76
77   /**
78    * This is a doubly-linked list.
79    */
80   struct TransportClient *next;
81
82   /**
83    * This is a doubly-linked list.
84    */
85   struct TransportClient *prev;
86
87   /**
88    * Handle to the client.
89    */
90   struct GNUNET_SERVER_Client *client;
91
92   /**
93    * Linked list of messages yet to be transmitted to
94    * the client.
95    */
96   struct ClientMessageQueueEntry *message_queue_head;
97
98   /**
99    * Tail of linked list of messages yet to be transmitted to the
100    * client.
101    */
102   struct ClientMessageQueueEntry *message_queue_tail;
103
104   /**
105    * Current transmit request handle.
106    */
107   struct GNUNET_SERVER_TransmitHandle *th;
108
109   /**
110    * Length of the list of messages pending for this client.
111    */
112   unsigned int message_count;
113
114   /**
115    * Is this client interested in payload messages?
116    */
117   int send_payload;
118 };
119
120
121 /**
122  * Context for address to string operations
123  */
124 struct AddressToStringContext
125 {
126   /**
127    * This is a doubly-linked list.
128    */
129   struct AddressToStringContext *next;
130
131   /**
132    * This is a doubly-linked list.
133    */
134   struct AddressToStringContext *prev;
135
136   /**
137    * Transmission context
138    */
139   struct GNUNET_SERVER_TransmitContext* tc;
140 };
141
142
143 /**
144  * Client monitoring changes of active addresses or validations
145  * of our neighbours. Which type is being monitored depends on the
146  * DLL this struct is in.
147  */
148 struct MonitoringClient
149 {
150   /**
151    * This is a doubly-linked list.
152    */
153   struct MonitoringClient *next;
154
155   /**
156    * This is a doubly-linked list.
157    */
158   struct MonitoringClient *prev;
159
160   /**
161    * Handle to the client.
162    */
163   struct GNUNET_SERVER_Client *client;
164
165   /**
166    * Peer identity to monitor the addresses of.
167    * Zero to monitor all neighrours.
168    */
169   struct GNUNET_PeerIdentity peer;
170
171 };
172
173
174 /**
175  * Closure for #handle_send_transmit_continuation()
176  */
177 struct SendTransmitContinuationContext
178 {
179   /**
180    * Client that made the request.
181    */
182   struct GNUNET_SERVER_Client *client;
183
184   /**
185    * Peer that was the target.
186    */
187   struct GNUNET_PeerIdentity target;
188
189   /**
190    * At what time did we receive the message?
191    */
192   struct GNUNET_TIME_Absolute send_time;
193
194   /**
195    * Unique ID, for logging.
196    */
197   unsigned long long uuid;
198
199   /**
200    * Set to #GNUNET_YES if the connection for @e target goes
201    * down and we thus must no longer send the
202    * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
203    */
204   int down;
205 };
206
207
208 /**
209  * Head of linked list of all clients to this service.
210  */
211 static struct TransportClient *clients_head;
212
213 /**
214  * Tail of linked list of all clients to this service.
215  */
216 static struct TransportClient *clients_tail;
217
218 /**
219  * Map of peer identities to active send transmit continuation
220  * contexts. Used to flag contexts as 'dead' when a connection goes
221  * down. Values are of type `struct SendTransmitContinuationContext
222  * *`.
223  */
224 static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
225
226 /**
227  * Head of linked list of all pending address iterations
228  */
229 static struct AddressToStringContext *a2s_head;
230
231 /**
232  * Tail of linked list of all pending address iterations
233  */
234 static struct AddressToStringContext *a2s_tail;
235
236 /**
237  * Head of linked list of monitoring clients.
238  */
239 static struct MonitoringClient *peer_monitoring_clients_head;
240
241 /**
242  * Tail of linked list of monitoring clients.
243  */
244 static struct MonitoringClient *peer_monitoring_clients_tail;
245
246 /**
247  * Notification context, to send updates on changes to active addresses
248  * of our neighbours.
249  */
250 static struct GNUNET_SERVER_NotificationContext *peer_nc;
251
252 /**
253  * Notification context, to send updates on changes to active addresses
254  * of our neighbours.
255  */
256 static struct GNUNET_SERVER_NotificationContext *val_nc;
257
258 /**
259  * Notification context, to send updates on changes to active plugin
260  * connections.
261  */
262 static struct GNUNET_SERVER_NotificationContext *plugin_nc;
263
264 /**
265  * Plugin monitoring client we are currently syncing, NULL if all
266  * monitoring clients are in sync.
267  */
268 static struct GNUNET_SERVER_Client *sync_client;
269
270 /**
271  * Peer identity that is all zeros, used as a way to indicate
272  * "all peers".  Used for comparissons.
273  */
274 static struct GNUNET_PeerIdentity all_zeros;
275
276
277 /**
278  * Find the internal handle associated with the given client handle.
279  *
280  * @param client server's client handle to look up
281  * @return internal client handle
282  */
283 static struct TransportClient *
284 lookup_client (struct GNUNET_SERVER_Client *client)
285 {
286   return GNUNET_SERVER_client_get_user_context (client,
287                                                 struct TransportClient);
288 }
289
290
291 /**
292  * Create the internal handle for the given server client handle.
293  *
294  * @param client server's client handle to create our internal handle for
295  * @return fresh internal client handle
296  */
297 static struct TransportClient *
298 setup_client (struct GNUNET_SERVER_Client *client)
299 {
300   struct TransportClient *tc;
301
302   GNUNET_assert (NULL == lookup_client (client));
303   tc = GNUNET_new (struct TransportClient);
304   tc->client = client;
305   GNUNET_SERVER_client_set_user_context (client, tc);
306   GNUNET_CONTAINER_DLL_insert (clients_head,
307                                clients_tail,
308                                tc);
309   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310               "Client %p connected\n",
311               tc);
312   return tc;
313 }
314
315
316 /**
317  * Find the handle to the monitoring client associated with the given
318  * client handle.
319  *
320  * @param head the head of the client queue to look in
321  * @param client server's client handle to look up
322  * @return handle to the monitoring client
323  */
324 static struct MonitoringClient *
325 lookup_monitoring_client (struct MonitoringClient *head,
326                           struct GNUNET_SERVER_Client *client)
327 {
328   struct MonitoringClient *mc;
329
330   for (mc = head; NULL != mc; mc = mc->next)
331     if (mc->client == client)
332       return mc;
333   return NULL;
334 }
335
336
337 /**
338  * Setup a new monitoring client using the given server client handle and
339  * the peer identity.
340  *
341  * @param client server's client handle to create our internal handle for
342  * @param peer identity of the peer to monitor the addresses of,
343  *             zero to monitor all neighrours.
344  * @return handle to the new monitoring client
345  */
346 static struct MonitoringClient *
347 setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client,
348                               const struct GNUNET_PeerIdentity *peer)
349 {
350   struct MonitoringClient *mc;
351
352   GNUNET_assert (NULL ==
353                  lookup_monitoring_client (peer_monitoring_clients_head,
354                                            client));
355   mc = GNUNET_new (struct MonitoringClient);
356   mc->client = client;
357   mc->peer = *peer;
358   GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head,
359                                peer_monitoring_clients_tail,
360                                mc);
361   GNUNET_SERVER_client_mark_monitor (client);
362   GNUNET_SERVER_notification_context_add (peer_nc,
363                                           client);
364   if (0 != memcmp (peer,
365                    &all_zeros,
366                    sizeof (struct GNUNET_PeerIdentity)))
367     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368                 "Client %p started monitoring of the peer `%s'\n",
369                 mc,
370                 GNUNET_i2s (peer));
371   else
372     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373                 "Client %p started monitoring all peers\n",
374                 mc);
375   return mc;
376 }
377
378
379 /**
380  * Function called to notify a client about the socket being ready to
381  * queue more data.  @a buf will be NULL and @a size zero if the socket
382  * was closed for writing in the meantime.
383  *
384  * @param cls closure
385  * @param size number of bytes available in @a buf
386  * @param buf where the callee should write the message
387  * @return number of bytes written to @a buf
388  */
389 static size_t
390 transmit_to_client_callback (void *cls,
391                              size_t size,
392                              void *buf)
393 {
394   struct TransportClient *tc = cls;
395   struct ClientMessageQueueEntry *q;
396   const struct GNUNET_MessageHeader *msg;
397   char *cbuf;
398   uint16_t msize;
399   size_t tsize;
400
401   tc->th = NULL;
402   if (NULL == buf)
403   {
404     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405                 "Transmission to client failed, closing connection.\n");
406     return 0;
407   }
408   cbuf = buf;
409   tsize = 0;
410   while (NULL != (q = tc->message_queue_head))
411   {
412     msg = (const struct GNUNET_MessageHeader *) &q[1];
413     msize = ntohs (msg->size);
414     if (msize + tsize > size)
415       break;
416     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
417                 "Transmitting message of type %u to client %p.\n",
418                 ntohs (msg->type),
419                 tc);
420     GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
421                                  tc->message_queue_tail,
422                                  q);
423     tc->message_count--;
424     memcpy (&cbuf[tsize], msg, msize);
425     GNUNET_free (q);
426     tsize += msize;
427   }
428   if (NULL != q)
429   {
430     GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
431     tc->th =
432         GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
433                                              GNUNET_TIME_UNIT_FOREVER_REL,
434                                              &transmit_to_client_callback, tc);
435     GNUNET_assert (NULL != tc->th);
436   }
437   return tsize;
438 }
439
440
441 /**
442  * Queue the given message for transmission to the given client
443  *
444  * @param tc target of the message
445  * @param msg message to transmit
446  * @param may_drop #GNUNET_YES if the message can be dropped
447  */
448 static void
449 unicast (struct TransportClient *tc,
450          const struct GNUNET_MessageHeader *msg,
451          int may_drop)
452 {
453   struct ClientMessageQueueEntry *q;
454   uint16_t msize;
455
456   if (NULL == msg)
457   {
458     GNUNET_break (0);
459     return;
460   }
461   if ( (tc->message_count >= MAX_PENDING) &&
462        (GNUNET_YES == may_drop) )
463   {
464     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465                 "Dropping message of type %u and size %u, have %u/%u messages pending\n",
466                 ntohs (msg->type),
467                 ntohs (msg->size),
468                 tc->message_count,
469                 MAX_PENDING);
470     GNUNET_STATISTICS_update (GST_stats,
471                               gettext_noop
472                               ("# messages dropped due to slow client"), 1,
473                               GNUNET_NO);
474     return;
475   }
476   msize = ntohs (msg->size);
477   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
478   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
479   memcpy (&q[1], msg, msize);
480   GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
481                                     tc->message_queue_tail,
482                                     q);
483   tc->message_count++;
484   if (NULL != tc->th)
485     return;
486   tc->th =
487       GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
488                                            GNUNET_TIME_UNIT_FOREVER_REL,
489                                            &transmit_to_client_callback, tc);
490   GNUNET_assert (NULL != tc->th);
491 }
492
493
494 /**
495  * Called whenever a client is disconnected.  Frees our
496  * resources associated with that client.
497  *
498  * @param cls closure, NULL
499  * @param client identification of the client
500  */
501 static void
502 client_disconnect_notification (void *cls,
503                                 struct GNUNET_SERVER_Client *client)
504 {
505   struct TransportClient *tc;
506   struct MonitoringClient *mc;
507   struct ClientMessageQueueEntry *mqe;
508
509   if (NULL == client)
510     return;
511   mc = lookup_monitoring_client (peer_monitoring_clients_head,
512                                  client);
513   if (NULL != mc)
514   {
515     GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head,
516                                  peer_monitoring_clients_tail,
517                                  mc);
518     GNUNET_free (mc);
519   }
520   tc = lookup_client (client);
521   if (NULL == tc)
522     return;
523   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
524               "Client %p disconnected, cleaning up.\n",
525               tc);
526   while (NULL != (mqe = tc->message_queue_head))
527   {
528     GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
529                                  tc->message_queue_tail,
530                                  mqe);
531     tc->message_count--;
532     GNUNET_free (mqe);
533   }
534   GNUNET_CONTAINER_DLL_remove (clients_head,
535                                clients_tail,
536                                tc);
537   GNUNET_SERVER_client_set_user_context (client, NULL);
538   if (NULL != tc->th)
539   {
540     GNUNET_SERVER_notify_transmit_ready_cancel (tc->th);
541     tc->th = NULL;
542   }
543   GNUNET_break (0 == tc->message_count);
544   GNUNET_free (tc);
545 }
546
547
548 /**
549  * Function called for each of our connected neighbours.  Notify the
550  * client about the existing neighbour.
551  *
552  * @param cls the `struct TransportClient *` to notify
553  * @param peer identity of the neighbour
554  * @param address the address
555  * @param state the current state of the peer
556  * @param state_timeout the time out for the state
557  * @param bandwidth_in inbound bandwidth in NBO
558  * @param bandwidth_out outbound bandwidth in NBO
559  */
560 static void
561 notify_client_about_neighbour (void *cls,
562                                const struct GNUNET_PeerIdentity *peer,
563                                const struct GNUNET_HELLO_Address *address,
564                                enum GNUNET_TRANSPORT_PeerState state,
565                                struct GNUNET_TIME_Absolute state_timeout,
566                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
567                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
568 {
569   struct TransportClient *tc = cls;
570   struct ConnectInfoMessage cim;
571
572   if (GNUNET_NO == GST_neighbours_test_connected (peer))
573     return;
574   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
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   const struct GNUNET_MessageHeader *hello;
599   struct TransportClient *tc;
600   uint32_t options;
601
602   tc = lookup_client (client);
603   if (NULL != tc)
604   {
605     /* got 'start' twice from the same client, not allowed */
606     GNUNET_break (0);
607     GNUNET_SERVER_receive_done (client,
608                                 GNUNET_SYSERR);
609     return;
610   }
611   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612               "Client %p sent START\n",
613               client);
614   start = (const struct StartMessage *) message;
615   options = ntohl (start->options);
616   if ((0 != (1 & options)) &&
617       (0 !=
618        memcmp (&start->self,
619                &GST_my_identity,
620                sizeof (struct GNUNET_PeerIdentity))))
621   {
622     /* client thinks this is a different peer, reject */
623     GNUNET_break (0);
624     GNUNET_SERVER_receive_done (client,
625                                 GNUNET_SYSERR);
626     return;
627   }
628   tc = setup_client (client);
629   tc->send_payload = (0 != (2 & options));
630   hello = GST_hello_get ();
631   if (NULL != hello)
632     unicast (tc,
633              hello,
634              GNUNET_NO);
635   GST_neighbours_iterate (&notify_client_about_neighbour,
636                           tc);
637   GNUNET_SERVER_receive_done (client,
638                               GNUNET_OK);
639 }
640
641
642 /**
643  * Client sent us a HELLO.  Process the request.
644  *
645  * @param cls unused
646  * @param client the client
647  * @param message the HELLO message
648  */
649 static void
650 clients_handle_hello (void *cls,
651                       struct GNUNET_SERVER_Client *client,
652                       const struct GNUNET_MessageHeader *message)
653 {
654   GST_validation_handle_hello (message);
655   GNUNET_SERVER_receive_done (client, GNUNET_OK);
656 }
657
658
659 /**
660  * Function called after the transmission is done.  Notify the client that it is
661  * OK to send the next message.
662  *
663  * @param cls closure
664  * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected
665  * @param bytes_payload bytes payload sent
666  * @param bytes_on_wire bytes sent on wire
667  */
668 static void
669 handle_send_transmit_continuation (void *cls,
670                                    int success,
671                                    size_t bytes_payload,
672                                    size_t bytes_on_wire)
673 {
674   struct SendTransmitContinuationContext *stcc = cls;
675   struct SendOkMessage send_ok_msg;
676   struct GNUNET_TIME_Relative delay;
677   const struct GNUNET_HELLO_Address *addr;
678
679   delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
680   addr = GST_neighbour_get_current_address (&stcc->target);
681   if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
682     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683                 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
684                 GNUNET_STRINGS_relative_time_to_string (delay,
685                                                         GNUNET_YES),
686                 (unsigned int) bytes_payload,
687                 (unsigned int) bytes_on_wire,
688                 GNUNET_i2s (&stcc->target),
689                 success,
690                 (NULL != addr) ? addr->transport_name : "%");
691   else
692     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693                 "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
694                 GNUNET_STRINGS_relative_time_to_string (delay,
695                                                         GNUNET_YES),
696                 (unsigned int) bytes_payload,
697                 (unsigned int) bytes_on_wire,
698                 GNUNET_i2s (&stcc->target),
699                 success,
700                 (NULL != addr) ? addr->transport_name : "%");
701
702   if (GNUNET_NO == stcc->down)
703   {
704     /* Only send confirmation if we are still connected */
705     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706                 "Sending SEND_OK for transmission request %llu\n",
707                 stcc->uuid);
708     send_ok_msg.header.size = htons (sizeof (send_ok_msg));
709     send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
710     send_ok_msg.bytes_msg = htonl (bytes_payload);
711     send_ok_msg.bytes_physical = htonl (bytes_on_wire);
712     send_ok_msg.success = htonl (success);
713     send_ok_msg.peer = stcc->target;
714     GST_clients_unicast (stcc->client,
715                          &send_ok_msg.header,
716                          GNUNET_NO);
717   }
718   GNUNET_SERVER_client_drop (stcc->client);
719   GNUNET_assert (GNUNET_OK ==
720                  GNUNET_CONTAINER_multipeermap_remove (active_stccs,
721                                                        &stcc->target,
722                                                        stcc));
723   GNUNET_free (stcc);
724 }
725
726
727 /**
728  * Client asked for transmission to a peer.  Process the request.
729  *
730  * @param cls unused
731  * @param client the client
732  * @param message the send message that was sent
733  */
734 static void
735 clients_handle_send (void *cls,
736                      struct GNUNET_SERVER_Client *client,
737                      const struct GNUNET_MessageHeader *message)
738 {
739   static unsigned long long uuid_gen;
740   const struct OutboundMessage *obm;
741   const struct GNUNET_MessageHeader *obmm;
742   struct SendTransmitContinuationContext *stcc;
743   uint16_t size;
744   uint16_t msize;
745   struct TransportClient *tc;
746
747   tc = lookup_client (client);
748   if (NULL == tc)
749   {
750     /* client asked for transmission before 'START' */
751     GNUNET_break (0);
752     GNUNET_SERVER_receive_done (client,
753                                 GNUNET_SYSERR);
754     return;
755   }
756
757   size = ntohs (message->size);
758   if (size <
759       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
760   {
761     GNUNET_break (0);
762     GNUNET_SERVER_receive_done (client,
763                                 GNUNET_SYSERR);
764     return;
765   }
766   obm = (const struct OutboundMessage *) message;
767   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
768   msize = size - sizeof (struct OutboundMessage);
769   if (msize < sizeof (struct GNUNET_MessageHeader))
770   {
771     GNUNET_break (0);
772     GNUNET_SERVER_receive_done (client,
773                                 GNUNET_SYSERR);
774     return;
775   }
776
777   if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
778   {
779     /* not connected, not allowed to send; can happen due to asynchronous operations */
780     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781                 "Could not send message to peer `%s': not connected\n",
782                 GNUNET_i2s (&obm->peer));
783     GNUNET_STATISTICS_update (GST_stats,
784                               gettext_noop
785                               ("# bytes payload dropped (other peer was not connected)"),
786                               msize, GNUNET_NO);
787     GNUNET_SERVER_receive_done (client,
788                                 GNUNET_OK);
789     return;
790   }
791   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792               "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
793               uuid_gen,
794               GNUNET_i2s (&obm->peer),
795               ntohs (obmm->type),
796               msize);
797   GNUNET_SERVER_receive_done (client,
798                               GNUNET_OK);
799   stcc = GNUNET_new (struct SendTransmitContinuationContext);
800   stcc->target = obm->peer;
801   stcc->client = client;
802   stcc->send_time = GNUNET_TIME_absolute_get ();
803   stcc->uuid = uuid_gen++;
804   (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
805                                             &stcc->target,
806                                             stcc,
807                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
808   GNUNET_SERVER_client_keep (client);
809   GST_manipulation_send (&obm->peer,
810                          obmm,
811                          msize,
812                          GNUNET_TIME_relative_ntoh (obm->timeout),
813                          &handle_send_transmit_continuation,
814                          stcc);
815 }
816
817
818 /**
819  * Take the given address and append it to the set of results sent back to
820  * the client.  This function may be called serveral times for a single
821  * conversion.   The last invocation will be with a @a address of
822  * NULL and a @a res of #GNUNET_OK.  Thus, to indicate conversion
823  * errors, the callback might be called first with @a address NULL and
824  * @a res being #GNUNET_SYSERR.  In that case, there will still be a
825  * subsequent call later with @a address NULL and @a res #GNUNET_OK.
826  *
827  * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
828  * @param buf text to transmit (contains the human-readable address, or NULL)
829  * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
830  *            never #GNUNET_NO
831  */
832 static void
833 transmit_address_to_client (void *cls,
834                             const char *buf,
835                             int res)
836 {
837   struct AddressToStringContext *actx = cls;
838   struct AddressToStringResultMessage *atsm;
839   size_t len;
840   size_t slen;
841
842   GNUNET_assert ( (GNUNET_OK == res) ||
843                   (GNUNET_SYSERR == res) );
844   if (NULL == buf)
845   {
846     len = sizeof (struct AddressToStringResultMessage);
847     atsm = GNUNET_malloc (len);
848     atsm->header.size = ntohs (len);
849     atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
850     if (GNUNET_OK == res)
851     {
852       /* this was the last call, transmit */
853       atsm->res = htonl (GNUNET_OK);
854       atsm->addr_len = htonl (0);
855       GNUNET_SERVER_transmit_context_append_message (actx->tc,
856                                                      (const struct GNUNET_MessageHeader *) atsm);
857       GNUNET_SERVER_transmit_context_run (actx->tc,
858                                           GNUNET_TIME_UNIT_FOREVER_REL);
859       GNUNET_CONTAINER_DLL_remove (a2s_head,
860                                    a2s_tail,
861                                    actx);
862       GNUNET_free (atsm);
863       GNUNET_free (actx);
864       return;
865     }
866     if (GNUNET_SYSERR == res)
867     {
868       /* address conversion failed, but there will be more callbacks */
869       atsm->res = htonl (GNUNET_SYSERR);
870       atsm->addr_len = htonl (0);
871       GNUNET_SERVER_transmit_context_append_message (actx->tc,
872                                                      (const struct GNUNET_MessageHeader *) atsm);
873       GNUNET_free (atsm);
874       return;
875     }
876   }
877   GNUNET_assert (GNUNET_OK == res);
878   /* succesful conversion, append*/
879   slen = strlen (buf) + 1;
880   len = sizeof (struct AddressToStringResultMessage) + slen;
881   atsm = GNUNET_malloc (len);
882   atsm->header.size = ntohs (len);
883   atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
884   atsm->res = htonl (GNUNET_YES);
885   atsm->addr_len = htonl (slen);
886   memcpy (&atsm[1],
887           buf,
888           slen);
889   GNUNET_SERVER_transmit_context_append_message (actx->tc,
890                                                  (const struct GNUNET_MessageHeader *) atsm);
891   GNUNET_free (atsm);
892 }
893
894
895 /**
896  * Client asked to resolve an address.  Process the request.
897  *
898  * @param cls unused
899  * @param client the client
900  * @param message the resolution request
901  */
902 static void
903 clients_handle_address_to_string (void *cls,
904                                   struct GNUNET_SERVER_Client *client,
905                                   const struct GNUNET_MessageHeader *message)
906 {
907   const struct AddressLookupMessage *alum;
908   struct GNUNET_TRANSPORT_PluginFunctions *papi;
909   const char *plugin_name;
910   const char *address;
911   uint32_t address_len;
912   uint16_t size;
913   struct GNUNET_SERVER_TransmitContext *tc;
914   struct AddressToStringContext *actx;
915   struct AddressToStringResultMessage atsm;
916   struct GNUNET_TIME_Relative rtimeout;
917   int32_t numeric;
918
919   size = ntohs (message->size);
920   if (size < sizeof (struct AddressLookupMessage))
921   {
922     GNUNET_break (0);
923     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
924     return;
925   }
926   alum = (const struct AddressLookupMessage *) message;
927   address_len = ntohs (alum->addrlen);
928   if (size <= sizeof (struct AddressLookupMessage) + address_len)
929   {
930     GNUNET_break (0);
931     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
932     return;
933   }
934   address = (const char *) &alum[1];
935   plugin_name = (const char *) &address[address_len];
936   if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
937   {
938     GNUNET_break (0);
939     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
940     return;
941   }
942   rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
943   numeric = ntohs (alum->numeric_only);
944   tc = GNUNET_SERVER_transmit_context_create (client);
945   papi = GST_plugins_printer_find (plugin_name);
946   if (NULL == papi)
947   {
948     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
949                 "Failed to find plugin `%s'\n",
950                 plugin_name);
951     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
952     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
953     atsm.res = htonl (GNUNET_SYSERR);
954     atsm.addr_len = htonl (0);
955     GNUNET_SERVER_transmit_context_append_message (tc,
956                                                    &atsm.header);
957     atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
958     atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
959     atsm.res = htonl (GNUNET_OK);
960     atsm.addr_len = htonl (0);
961     GNUNET_SERVER_transmit_context_append_message (tc,
962                                                    &atsm.header);
963     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
964     return;
965   }
966   actx = GNUNET_new (struct AddressToStringContext);
967   actx->tc = tc;
968   GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
969   GNUNET_SERVER_disable_receive_done_warning (client);
970   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971               "Pretty-printing address of %u bytes using plugin `%s'\n",
972               address_len,
973               plugin_name);
974   papi->address_pretty_printer (papi->cls,
975                                 plugin_name,
976                                 address, address_len,
977                                 numeric,
978                                 rtimeout,
979                                 &transmit_address_to_client,
980                                 actx);
981 }
982
983
984 /**
985  * Compose #PeerIterateResponseMessage using the given peer and address.
986  *
987  * @param peer identity of the peer
988  * @param address the address, NULL on disconnect
989  * @return composed message
990  */
991 static struct PeerIterateResponseMessage *
992 compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
993                                           const struct GNUNET_HELLO_Address *address)
994 {
995   struct PeerIterateResponseMessage *msg;
996   size_t size;
997   size_t tlen;
998   size_t alen;
999   char *addr;
1000
1001   GNUNET_assert (NULL != peer);
1002   if (NULL != address)
1003   {
1004     tlen = strlen (address->transport_name) + 1;
1005     alen = address->address_length;
1006   }
1007   else
1008   {
1009     tlen = 0;
1010     alen = 0;
1011   }
1012   size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
1013   msg = GNUNET_malloc (size);
1014   msg->header.size = htons (size);
1015   msg->header.type =
1016       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
1017   msg->reserved = htonl (0);
1018   msg->peer = *peer;
1019   msg->addrlen = htonl (alen);
1020   msg->pluginlen = htonl (tlen);
1021
1022   if (NULL != address)
1023   {
1024     msg->local_address_info = htonl((uint32_t) address->local_info);
1025     addr = (char *) &msg[1];
1026     memcpy (addr, address->address, alen);
1027     memcpy (&addr[alen], address->transport_name, tlen);
1028   }
1029   return msg;
1030 }
1031
1032
1033 /**
1034  * Context for #send_validation_information() and
1035  * #send_peer_information().
1036  */
1037 struct IterationContext
1038 {
1039   /**
1040    * Context to use for the transmission.
1041    */
1042   struct GNUNET_SERVER_TransmitContext *tc;
1043
1044   /**
1045    * Which peers do we care about?
1046    */
1047   struct GNUNET_PeerIdentity id;
1048
1049   /**
1050    * #GNUNET_YES if @e id should be ignored because we want all peers.
1051    */
1052   int all;
1053 };
1054
1055
1056 /**
1057  * Output information of neighbours to the given client.
1058  *
1059  * @param cls the `struct PeerIterationContext *`
1060  * @param peer identity of the neighbour
1061  * @param address the address
1062  * @param state current state this peer is in
1063  * @param state_timeout timeout for the current state of the peer
1064  * @param bandwidth_in inbound quota in NBO
1065  * @param bandwidth_out outbound quota in NBO
1066  */
1067 static void
1068 send_peer_information (void *cls,
1069                        const struct GNUNET_PeerIdentity *peer,
1070                        const struct GNUNET_HELLO_Address *address,
1071                        enum GNUNET_TRANSPORT_PeerState state,
1072                        struct GNUNET_TIME_Absolute state_timeout,
1073                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1074                        struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1075 {
1076   struct IterationContext *pc = cls;
1077   struct PeerIterateResponseMessage *msg;
1078
1079   if ( (GNUNET_YES != pc->all) &&
1080        (0 != memcmp (peer, &pc->id, sizeof (pc->id))) )
1081     return;
1082   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1083               "Sending information about `%s' using address `%s' in state `%s'\n",
1084               GNUNET_i2s(peer),
1085               (NULL != address) ? GST_plugins_a2s (address) : "<none>",
1086               GNUNET_TRANSPORT_ps2s (state));
1087   msg = compose_address_iterate_response_message (peer, address);
1088   msg->state = htonl (state);
1089   msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
1090   GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
1091   GNUNET_free (msg);
1092 }
1093
1094
1095 /**
1096  * Client asked to obtain information about a specific or all peers
1097  * Process the request.
1098  *
1099  * @param cls unused
1100  * @param client the client
1101  * @param message the peer address information request
1102  */
1103 static void
1104 clients_handle_monitor_peers (void *cls,
1105                               struct GNUNET_SERVER_Client *client,
1106                               const struct GNUNET_MessageHeader *message)
1107 {
1108   struct GNUNET_SERVER_TransmitContext *tc;
1109   const struct PeerMonitorMessage *msg;
1110   struct IterationContext pc;
1111
1112   msg = (const struct PeerMonitorMessage *) message;
1113   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
1114        (NULL != lookup_monitoring_client (peer_monitoring_clients_head,
1115                                           client)) )
1116   {
1117     GNUNET_break (0);
1118     GNUNET_SERVER_receive_done (client,
1119                                 GNUNET_SYSERR);
1120     return;
1121   }
1122   GNUNET_SERVER_disable_receive_done_warning (client);
1123   GNUNET_SERVER_client_mark_monitor (client);
1124   pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
1125
1126   /* Send initial list */
1127   if (0 == memcmp (&msg->peer,
1128                    &all_zeros,
1129                    sizeof (struct GNUNET_PeerIdentity)))
1130   {
1131     /* iterate over all neighbours */
1132     pc.all = GNUNET_YES;
1133     pc.id = msg->peer;
1134   }
1135   else
1136   {
1137     /* just return one neighbour */
1138     pc.all = GNUNET_NO;
1139     pc.id = msg->peer;
1140   }
1141   GST_neighbours_iterate (&send_peer_information,
1142                           &pc);
1143
1144   if (GNUNET_YES != ntohl (msg->one_shot))
1145   {
1146     setup_peer_monitoring_client (client,
1147                                   &msg->peer);
1148   }
1149   else
1150   {
1151     GNUNET_SERVER_transmit_context_append_data (tc,
1152                                                 NULL,
1153                                                 0,
1154                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END);
1155   }
1156   GNUNET_SERVER_transmit_context_run (tc,
1157                                       GNUNET_TIME_UNIT_FOREVER_REL);
1158 }
1159
1160
1161 /**
1162  * Function called by the plugin with information about the
1163  * current sessions managed by the plugin (for monitoring).
1164  *
1165  * @param cls closure
1166  * @param session session handle this information is about,
1167  *        NULL to indicate that we are "in sync" (initial
1168  *        iteration complete)
1169  * @param info information about the state of the session,
1170  *        NULL if @a session is also NULL and we are
1171  *        merely signalling that the initial iteration is over
1172  */
1173 static void
1174 plugin_session_info_cb (void *cls,
1175                         struct GNUNET_ATS_Session *session,
1176                         const struct GNUNET_TRANSPORT_SessionInfo *info)
1177 {
1178   struct TransportPluginMonitorMessage *msg;
1179   struct GNUNET_MessageHeader sync;
1180   size_t size;
1181   size_t slen;
1182   uint16_t alen;
1183   char *name;
1184   char *addr;
1185
1186   if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc))
1187   {
1188     GST_plugins_monitor_subscribe (NULL,
1189                                    NULL);
1190     return;
1191   }
1192   if ( (NULL == info) &&
1193        (NULL == session) )
1194   {
1195     /* end of initial iteration */
1196     if (NULL != sync_client)
1197     {
1198       sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1199       sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC);
1200       GNUNET_SERVER_notification_context_unicast (plugin_nc,
1201                                                   sync_client,
1202                                                   &sync,
1203                                                   GNUNET_NO);
1204       sync_client = NULL;
1205     }
1206     return;
1207   }
1208   GNUNET_assert (NULL != info);
1209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210               "Plugin event for peer %s on transport %s\n",
1211               GNUNET_i2s (&info->address->peer),
1212               info->address->transport_name);
1213   slen = strlen (info->address->transport_name) + 1;
1214   alen = info->address->address_length;
1215   size = sizeof (struct TransportPluginMonitorMessage) + slen + alen;
1216   if (size > UINT16_MAX)
1217   {
1218     GNUNET_break (0);
1219     return;
1220   }
1221   msg = GNUNET_malloc (size);
1222   msg->header.size = htons (size);
1223   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT);
1224   msg->session_state = htons ((uint16_t) info->state);
1225   msg->is_inbound = htons ((int16_t) info->is_inbound);
1226   msg->msgs_pending = htonl (info->num_msg_pending);
1227   msg->bytes_pending = htonl (info->num_bytes_pending);
1228   msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout);
1229   msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay);
1230   msg->peer = info->address->peer;
1231   msg->session_id = (uint64_t) (intptr_t) session;
1232   msg->plugin_name_len = htons (slen);
1233   msg->plugin_address_len = htons (alen);
1234   name = (char *) &msg[1];
1235   memcpy (name,
1236           info->address->transport_name,
1237           slen);
1238   addr = &name[slen];
1239   memcpy (addr,
1240           info->address->address,
1241           alen);
1242   if (NULL != sync_client)
1243     GNUNET_SERVER_notification_context_unicast (plugin_nc,
1244                                                 sync_client,
1245                                                 &msg->header,
1246                                                 GNUNET_NO);
1247   else
1248     GNUNET_SERVER_notification_context_broadcast (plugin_nc,
1249                                                   &msg->header,
1250                                                   GNUNET_NO);
1251   GNUNET_free (msg);
1252 }
1253
1254
1255 /**
1256  * Client asked to obtain information about all plugin connections.
1257  *
1258  * @param cls unused
1259  * @param client the client
1260  * @param message the peer address information request
1261  */
1262 static void
1263 clients_handle_monitor_plugins (void *cls,
1264                                 struct GNUNET_SERVER_Client *client,
1265                                 const struct GNUNET_MessageHeader *message)
1266 {
1267   GNUNET_SERVER_client_mark_monitor (client);
1268   GNUNET_SERVER_disable_receive_done_warning (client);
1269   GNUNET_SERVER_notification_context_add (plugin_nc,
1270                                           client);
1271   GNUNET_assert (NULL == sync_client);
1272   sync_client = client;
1273   GST_plugins_monitor_subscribe (&plugin_session_info_cb,
1274                                  NULL);
1275 }
1276
1277
1278 /**
1279  * Start handling requests from clients.
1280  *
1281  * @param server server used to accept clients from.
1282  */
1283 void
1284 GST_clients_start (struct GNUNET_SERVER_Handle *server)
1285 {
1286   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1287     {&clients_handle_start, NULL,
1288      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
1289     {&clients_handle_hello, NULL,
1290      GNUNET_MESSAGE_TYPE_HELLO, 0},
1291     {&clients_handle_send, NULL,
1292      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
1293     {&clients_handle_address_to_string, NULL,
1294      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
1295     {&clients_handle_monitor_peers, NULL,
1296      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
1297      sizeof (struct PeerMonitorMessage)},
1298     {&GST_blacklist_handle_init, NULL,
1299      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
1300      sizeof (struct GNUNET_MessageHeader)},
1301     {&GST_blacklist_handle_reply, NULL,
1302      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
1303      sizeof (struct BlacklistMessage)},
1304     {&GST_manipulation_set_metric, NULL,
1305      GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
1306      sizeof (struct TrafficMetricMessage) },
1307     {&clients_handle_monitor_plugins, NULL,
1308      GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
1309      sizeof (struct GNUNET_MessageHeader) },
1310     {NULL, NULL, 0, 0}
1311   };
1312   active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
1313                                                        GNUNET_YES);
1314   peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
1315   val_nc = GNUNET_SERVER_notification_context_create (server, 0);
1316   plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
1317   GNUNET_SERVER_add_handlers (server, handlers);
1318   GNUNET_SERVER_disconnect_notify (server,
1319                                    &client_disconnect_notification,
1320                                    NULL);
1321 }
1322
1323
1324 /**
1325  * Stop processing clients.
1326  */
1327 void
1328 GST_clients_stop ()
1329 {
1330   struct AddressToStringContext *cur;
1331
1332   while (NULL != (cur = a2s_head))
1333   {
1334     GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO);
1335     GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
1336     GNUNET_free (cur);
1337   }
1338   if (NULL != peer_nc)
1339   {
1340     GNUNET_SERVER_notification_context_destroy (peer_nc);
1341     peer_nc = NULL;
1342   }
1343   if (NULL != val_nc)
1344   {
1345     GNUNET_SERVER_notification_context_destroy (val_nc);
1346     val_nc = NULL;
1347   }
1348   if (NULL != plugin_nc)
1349   {
1350     GNUNET_SERVER_notification_context_destroy (plugin_nc);
1351     plugin_nc = NULL;
1352   }
1353   GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
1354   active_stccs = NULL;
1355 }
1356
1357
1358 /**
1359  * Broadcast the given message to all of our clients.
1360  *
1361  * @param msg message to broadcast
1362  * @param may_drop #GNUNET_YES if the message can be dropped / is payload
1363  */
1364 void
1365 GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
1366                        int may_drop)
1367 {
1368   struct TransportClient *tc;
1369
1370   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371               "Asked to broadcast message of type %u with %u bytes\n",
1372               (unsigned int) ntohs (msg->type),
1373               (unsigned int) ntohs (msg->size));
1374   for (tc = clients_head; NULL != tc; tc = tc->next)
1375   {
1376     if ( (GNUNET_YES == may_drop) &&
1377          (GNUNET_YES != tc->send_payload) )
1378       continue; /* skip, this client does not care about payload */
1379     unicast (tc, msg, may_drop);
1380   }
1381 }
1382
1383
1384 /**
1385  * Send the given message to a particular client
1386  *
1387  * @param client target of the message
1388  * @param msg message to transmit
1389  * @param may_drop #GNUNET_YES if the message can be dropped
1390  */
1391 void
1392 GST_clients_unicast (struct GNUNET_SERVER_Client *client,
1393                      const struct GNUNET_MessageHeader *msg,
1394                      int may_drop)
1395 {
1396   struct TransportClient *tc;
1397
1398   tc = lookup_client (client);
1399   if (NULL == tc)
1400     return;                     /* client got disconnected in the meantime, drop message */
1401   unicast (tc, msg, may_drop);
1402 }
1403
1404
1405 /**
1406  * Broadcast the new active address to all clients monitoring the peer.
1407  *
1408  * @param peer peer this update is about (never NULL)
1409  * @param address address, NULL on disconnect
1410  * @param state the current state of the peer
1411  * @param state_timeout the time out for the state
1412  */
1413 void
1414 GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
1415                                          const struct GNUNET_HELLO_Address *address,
1416                                          enum GNUNET_TRANSPORT_PeerState state,
1417                                          struct GNUNET_TIME_Absolute state_timeout)
1418 {
1419   struct PeerIterateResponseMessage *msg;
1420   struct MonitoringClient *mc;
1421
1422   msg = compose_address_iterate_response_message (peer, address);
1423   msg->state = htonl (state);
1424   msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
1425   for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next)
1426     if ((0 == memcmp (&mc->peer, &all_zeros,
1427                       sizeof (struct GNUNET_PeerIdentity))) ||
1428         (0 == memcmp (&mc->peer, peer,
1429                       sizeof (struct GNUNET_PeerIdentity))))
1430       GNUNET_SERVER_notification_context_unicast (peer_nc,
1431                                                   mc->client,
1432                                                   &msg->header,
1433                                                   GNUNET_NO);
1434   GNUNET_free (msg);
1435 }
1436
1437
1438 /**
1439  * Mark the peer as down so we don't call the continuation
1440  * context in the future.
1441  *
1442  * @param cls NULL
1443  * @param peer peer that got disconnected
1444  * @param value a `struct SendTransmitContinuationContext` to mark
1445  * @return #GNUNET_OK (continue to iterate)
1446  */
1447 static int
1448 mark_peer_down (void *cls,
1449                 const struct GNUNET_PeerIdentity *peer,
1450                 void *value)
1451 {
1452   struct SendTransmitContinuationContext *stcc = value;
1453
1454   stcc->down = GNUNET_YES;
1455   return GNUNET_OK;
1456 }
1457
1458
1459 /**
1460  * Notify all clients about a disconnect, and cancel
1461  * pending SEND_OK messages for this peer.
1462  *
1463  * @param peer peer that disconnected
1464  */
1465 void
1466 GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
1467 {
1468   struct DisconnectInfoMessage disconnect_msg;
1469
1470   GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
1471                                               peer,
1472                                               &mark_peer_down,
1473                                               NULL);
1474   disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
1475   disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1476   disconnect_msg.reserved = htonl (0);
1477   disconnect_msg.peer = *peer;
1478   GST_clients_broadcast (&disconnect_msg.header,
1479                          GNUNET_NO);
1480
1481 }
1482
1483
1484 /* end of file gnunet-service-transport_clients.c */