diff options
Diffstat (limited to 'src/transport/gnunet-service-transport_clients.c')
-rw-r--r-- | src/transport/gnunet-service-transport_clients.c | 1491 |
1 files changed, 0 insertions, 1491 deletions
diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c deleted file mode 100644 index 036fc5637..000000000 --- a/src/transport/gnunet-service-transport_clients.c +++ /dev/null | |||
@@ -1,1491 +0,0 @@ | |||
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 | GNUNET_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 | GNUNET_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 (¬ify_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 | GNUNET_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 | GNUNET_memcpy (addr, address->address, alen); | ||
1027 | GNUNET_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 | GNUNET_memcpy (name, | ||
1236 | info->address->transport_name, | ||
1237 | slen); | ||
1238 | addr = &name[slen]; | ||
1239 | GNUNET_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 | int done; | ||
1370 | |||
1371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1372 | "Asked to broadcast message of type %u with %u bytes\n", | ||
1373 | (unsigned int) ntohs (msg->type), | ||
1374 | (unsigned int) ntohs (msg->size)); | ||
1375 | done = GNUNET_NO; | ||
1376 | for (tc = clients_head; NULL != tc; tc = tc->next) | ||
1377 | { | ||
1378 | if ( (GNUNET_YES == may_drop) && | ||
1379 | (GNUNET_YES != tc->send_payload) ) | ||
1380 | continue; /* skip, this client does not care about payload */ | ||
1381 | unicast (tc, msg, may_drop); | ||
1382 | done = GNUNET_YES; | ||
1383 | } | ||
1384 | if (GNUNET_NO == done) | ||
1385 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1386 | "Message of type %u not delivered, is CORE service up?\n", | ||
1387 | ntohs (msg->type)); | ||
1388 | } | ||
1389 | |||
1390 | |||
1391 | /** | ||
1392 | * Send the given message to a particular client | ||
1393 | * | ||
1394 | * @param client target of the message | ||
1395 | * @param msg message to transmit | ||
1396 | * @param may_drop #GNUNET_YES if the message can be dropped | ||
1397 | */ | ||
1398 | void | ||
1399 | GST_clients_unicast (struct GNUNET_SERVER_Client *client, | ||
1400 | const struct GNUNET_MessageHeader *msg, | ||
1401 | int may_drop) | ||
1402 | { | ||
1403 | struct TransportClient *tc; | ||
1404 | |||
1405 | tc = lookup_client (client); | ||
1406 | if (NULL == tc) | ||
1407 | return; /* client got disconnected in the meantime, drop message */ | ||
1408 | unicast (tc, msg, may_drop); | ||
1409 | } | ||
1410 | |||
1411 | |||
1412 | /** | ||
1413 | * Broadcast the new active address to all clients monitoring the peer. | ||
1414 | * | ||
1415 | * @param peer peer this update is about (never NULL) | ||
1416 | * @param address address, NULL on disconnect | ||
1417 | * @param state the current state of the peer | ||
1418 | * @param state_timeout the time out for the state | ||
1419 | */ | ||
1420 | void | ||
1421 | GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, | ||
1422 | const struct GNUNET_HELLO_Address *address, | ||
1423 | enum GNUNET_TRANSPORT_PeerState state, | ||
1424 | struct GNUNET_TIME_Absolute state_timeout) | ||
1425 | { | ||
1426 | struct PeerIterateResponseMessage *msg; | ||
1427 | struct MonitoringClient *mc; | ||
1428 | |||
1429 | msg = compose_address_iterate_response_message (peer, address); | ||
1430 | msg->state = htonl (state); | ||
1431 | msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout); | ||
1432 | for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next) | ||
1433 | if ((0 == memcmp (&mc->peer, &all_zeros, | ||
1434 | sizeof (struct GNUNET_PeerIdentity))) || | ||
1435 | (0 == memcmp (&mc->peer, peer, | ||
1436 | sizeof (struct GNUNET_PeerIdentity)))) | ||
1437 | GNUNET_SERVER_notification_context_unicast (peer_nc, | ||
1438 | mc->client, | ||
1439 | &msg->header, | ||
1440 | GNUNET_NO); | ||
1441 | GNUNET_free (msg); | ||
1442 | } | ||
1443 | |||
1444 | |||
1445 | /** | ||
1446 | * Mark the peer as down so we don't call the continuation | ||
1447 | * context in the future. | ||
1448 | * | ||
1449 | * @param cls NULL | ||
1450 | * @param peer peer that got disconnected | ||
1451 | * @param value a `struct SendTransmitContinuationContext` to mark | ||
1452 | * @return #GNUNET_OK (continue to iterate) | ||
1453 | */ | ||
1454 | static int | ||
1455 | mark_peer_down (void *cls, | ||
1456 | const struct GNUNET_PeerIdentity *peer, | ||
1457 | void *value) | ||
1458 | { | ||
1459 | struct SendTransmitContinuationContext *stcc = value; | ||
1460 | |||
1461 | stcc->down = GNUNET_YES; | ||
1462 | return GNUNET_OK; | ||
1463 | } | ||
1464 | |||
1465 | |||
1466 | /** | ||
1467 | * Notify all clients about a disconnect, and cancel | ||
1468 | * pending SEND_OK messages for this peer. | ||
1469 | * | ||
1470 | * @param peer peer that disconnected | ||
1471 | */ | ||
1472 | void | ||
1473 | GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer) | ||
1474 | { | ||
1475 | struct DisconnectInfoMessage disconnect_msg; | ||
1476 | |||
1477 | GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs, | ||
1478 | peer, | ||
1479 | &mark_peer_down, | ||
1480 | NULL); | ||
1481 | disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage)); | ||
1482 | disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); | ||
1483 | disconnect_msg.reserved = htonl (0); | ||
1484 | disconnect_msg.peer = *peer; | ||
1485 | GST_clients_broadcast (&disconnect_msg.header, | ||
1486 | GNUNET_NO); | ||
1487 | |||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /* end of file gnunet-service-transport_clients.c */ | ||