aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_signatures.h5
-rw-r--r--src/transport/Makefile.am9
-rw-r--r--src/transport/gnunet-communicator-tcp.c1093
3 files changed, 1107 insertions, 0 deletions
diff --git a/src/include/gnunet_signatures.h b/src/include/gnunet_signatures.h
index 3c2413d99..738a414ab 100644
--- a/src/include/gnunet_signatures.h
+++ b/src/include/gnunet_signatures.h
@@ -202,6 +202,11 @@ extern "C"
202 */ 202 */
203#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL 30 203#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL 30
204 204
205/**
206 * Signature used by TCP communicator handshake,
207 */
208#define GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE 31
209
205#if 0 /* keep Emacsens' auto-indent happy */ 210#if 0 /* keep Emacsens' auto-indent happy */
206{ 211{
207#endif 212#endif
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index ab4ef4bfa..0df3e4e27 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -142,6 +142,7 @@ endif
142noinst_PROGRAMS = \ 142noinst_PROGRAMS = \
143 gnunet-transport-profiler \ 143 gnunet-transport-profiler \
144 gnunet-communicator-unix \ 144 gnunet-communicator-unix \
145 gnunet-communicator-tcp \
145 gnunet-service-tng \ 146 gnunet-service-tng \
146 $(WLAN_BIN_SENDER) \ 147 $(WLAN_BIN_SENDER) \
147 $(WLAN_BIN_RECEIVER) 148 $(WLAN_BIN_RECEIVER)
@@ -251,6 +252,14 @@ gnunet_communicator_unix_LDADD = \
251 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 252 $(top_builddir)/src/statistics/libgnunetstatistics.la \
252 $(top_builddir)/src/util/libgnunetutil.la 253 $(top_builddir)/src/util/libgnunetutil.la
253 254
255gnunet_communicator_tcp_SOURCES = \
256 gnunet-communicator-tcp.c
257gnunet_communicator_tcp_LDADD = \
258 libgnunettransportcommunicator.la \
259 $(top_builddir)/src/statistics/libgnunetstatistics.la \
260 $(top_builddir)/src/util/libgnunetutil.la \
261 $(LIBGCRYPT_LIBS)
262
254 263
255gnunet_helper_transport_wlan_SOURCES = \ 264gnunet_helper_transport_wlan_SOURCES = \
256 gnunet-helper-transport-wlan.c 265 gnunet-helper-transport-wlan.c
diff --git a/src/transport/gnunet-communicator-tcp.c b/src/transport/gnunet-communicator-tcp.c
new file mode 100644
index 000000000..6e3faa44a
--- /dev/null
+++ b/src/transport/gnunet-communicator-tcp.c
@@ -0,0 +1,1093 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @file transport/gnunet-communicator-tcp.c
23 * @brief Transport plugin using TCP.
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - lots of basic adaptations (see FIXMEs)
28 * - better message queue management
29 * - actually encrypt, hmac, decrypt
30 * - actually transmit
31 * -
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_protocols.h"
36#include "gnunet_constants.h"
37#include "gnunet_nt_lib.h"
38#include "gnunet_statistics_service.h"
39#include "gnunet_transport_communication_service.h"
40
41/**
42 * How many messages do we keep at most in the queue to the
43 * transport service before we start to drop (default,
44 * can be changed via the configuration file).
45 * Should be _below_ the level of the communicator API, as
46 * otherwise we may read messages just to have them dropped
47 * by the communicator API.
48 */
49#define DEFAULT_MAX_QUEUE_LENGTH 8
50
51/**
52 * Address prefix used by the communicator.
53 */
54#define COMMUNICATOR_ADDRESS_PREFIX "tcp"
55
56/**
57 * Configuration section used by the communicator.
58 */
59#define COMMUNICATOR_CONFIG_SECTION "communicator-tcp"
60
61GNUNET_NETWORK_STRUCT_BEGIN
62
63/**
64 * TCP initial bytes on the wire (in either direction), used to
65 * establish a shared secret.
66 */
67struct TCPHandshake
68{
69 /**
70 * First bytes: ephemeral key for KX.
71 */
72 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
73
74};
75
76
77/**
78 * Signature we use to verify that the ephemeral key was really chosen by
79 * the specified sender.
80 */
81struct TcpHandshakeSignature
82{
83 /**
84 * Purpose must be #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
85 */
86 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
87
88 /**
89 * Identity of the inititor of the TCP connection (TCP client).
90 */
91 struct GNUNET_PeerIdentity sender;
92
93 /**
94 * Presumed identity of the target of the TCP connection (TCP server)
95 */
96 struct GNUNET_PeerIdentity receiver;
97
98 /**
99 * Ephemeral key used by the @e sender.
100 */
101 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
102
103 /**
104 * Monotonic time of @e sender, to possibly help detect replay attacks
105 * (if receiver persists times by sender).
106 */
107 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
108};
109
110
111/**
112 * Encrypted continuation of TCP initial handshake.
113 */
114struct TCPConfirmation
115{
116 /**
117 * Sender's identity
118 */
119 struct GNUNET_PeerIdentity sender;
120
121 /**
122 * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
123 */
124 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
125
126 /**
127 * Monotonic time of @e sender, to possibly help detect replay attacks
128 * (if receiver persists times by sender).
129 */
130 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
131
132};
133
134
135/**
136 * TCP message box. Always sent encrypted!
137 */
138struct TCPBox
139{
140
141 /**
142 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX.
143 */
144 struct GNUNET_MessageHeader header;
145
146 /**
147 * HMAC for the following encrypted message. Yes, we MUST use
148 * mac-then-encrypt here, as we want to hide the message sizes on
149 * the wire (zero plaintext design!). Using CTR mode padding oracle
150 * attacks do not apply. Besides, due to the use of ephemeral keys
151 * (hopefully with effective replay protection from monotonic time!)
152 * the attacker is limited in using the oracle.
153 */
154 struct GNUNET_ShortHashCode hmac;
155
156 /* followed by as may bytes of payload as indicated in @e header */
157
158};
159
160
161/**
162 * TCP rekey message box. Always sent encrypted! Data after
163 * this message will use the new key.
164 */
165struct TCPRekey
166{
167
168 /**
169 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY.
170 */
171 struct GNUNET_MessageHeader header;
172
173 /**
174 * HMAC for the following encrypted message. Yes, we MUST use
175 * mac-then-encrypt here, as we want to hide the message sizes on
176 * the wire (zero plaintext design!). Using CTR mode padding oracle
177 * attacks do not apply. Besides, due to the use of ephemeral keys
178 * (hopefully with effective replay protection from monotonic time!)
179 * the attacker is limited in using the oracle.
180 */
181 struct GNUNET_ShortHashCode hmac;
182
183 /**
184 * New ephemeral key.
185 */
186 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
187
188 /**
189 * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
190 */
191 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
192
193 /**
194 * Monotonic time of @e sender, to possibly help detect replay attacks
195 * (if receiver persists times by sender).
196 */
197 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
198
199};
200
201
202/**
203 * TCP finish. Sender asks for the connection to be closed.
204 * Needed/useful in case we drop RST/FIN packets on the GNUnet
205 * port due to the possibility of malicious RST/FIN injection.
206 */
207struct TCPFinish
208{
209
210 /**
211 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH.
212 */
213 struct GNUNET_MessageHeader header;
214
215 /**
216 * HMAC for the following encrypted message. Yes, we MUST use
217 * mac-then-encrypt here, as we want to hide the message sizes on
218 * the wire (zero plaintext design!). Using CTR mode padding oracle
219 * attacks do not apply. Besides, due to the use of ephemeral keys
220 * (hopefully with effective replay protection from monotonic time!)
221 * the attacker is limited in using the oracle.
222 */
223 struct GNUNET_ShortHashCode hmac;
224
225};
226
227
228GNUNET_NETWORK_STRUCT_END
229
230
231/**
232 * Handle for a queue.
233 */
234struct Queue
235{
236
237 /**
238 * To whom are we talking to.
239 */
240 struct GNUNET_PeerIdentity target;
241
242 /**
243 * socket that we transmit all data with on this queue
244 */
245 struct GNUNET_NETWORK_Handle *sock;
246
247 /**
248 * cipher for decryption of incoming data.
249 */
250 gcry_cipher_hd_t in_cipher;
251
252 /**
253 * cipher for encryption of outgoing data.
254 */
255 gcry_cipher_hd_t out_cipher;
256
257 /**
258 * Shared secret for HMAC verification on incoming data.
259 */
260 struct GNUNET_HashCode in_hmac;
261
262 /**
263 * Shared secret for HMAC generation on outgoing data.
264 */
265 struct GNUNET_HashCode out_hmac;
266
267 /**
268 * ID of read task for this connection.
269 */
270 struct GNUNET_SCHEDULER_Task *read_task;
271
272 /**
273 * ID of write task for this connection.
274 */
275 struct GNUNET_SCHEDULER_Task *write_task;
276
277 /**
278 * Address of the other peer.
279 */
280 struct sockaddr *address;
281
282 /**
283 * How many more bytes may we sent with the current @e out_cipher
284 * before we should rekey?
285 */
286 uint64_t rekey_left_bytes;
287
288 /**
289 * Until what time may we sent with the current @e out_cipher
290 * before we should rekey?
291 */
292 struct GNUNET_TIME_Absolute rekey_time;
293
294 /**
295 * Length of the address.
296 */
297 socklen_t address_len;
298
299 /**
300 * Message currently scheduled for transmission, non-NULL if and only
301 * if this queue is in the #queue_head DLL.
302 */
303 const struct GNUNET_MessageHeader *msg;
304
305 /**
306 * Message queue we are providing for the #ch.
307 */
308 struct GNUNET_MQ_Handle *mq;
309
310 /**
311 * handle for this queue with the #ch.
312 */
313 struct GNUNET_TRANSPORT_QueueHandle *qh;
314
315 /**
316 * Number of bytes we currently have in our write queue.
317 */
318 unsigned long long bytes_in_queue;
319
320 /**
321 * Timeout for this queue.
322 */
323 struct GNUNET_TIME_Absolute timeout;
324
325 /**
326 * Which network type does this queue use?
327 */
328 enum GNUNET_NetworkType nt;
329
330};
331
332
333/**
334 * ID of listen task
335 */
336static struct GNUNET_SCHEDULER_Task *listen_task;
337
338/**
339 * Number of messages we currently have in our queues towards the transport service.
340 */
341static unsigned long long delivering_messages;
342
343/**
344 * Maximum queue length before we stop reading towards the transport service.
345 */
346static unsigned long long max_queue_length;
347
348/**
349 * For logging statistics.
350 */
351static struct GNUNET_STATISTICS_Handle *stats;
352
353/**
354 * Our environment.
355 */
356static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
357
358/**
359 * Queues (map from peer identity to `struct Queue`)
360 */
361static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
362
363/**
364 * Listen socket.
365 */
366static struct GNUNET_NETWORK_Handle *listen_sock;
367
368/**
369 * Handle to the operation that publishes our address.
370 */
371static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
372
373
374/**
375 * We have been notified that our listen socket has something to
376 * read. Do the read and reschedule this function to be called again
377 * once more is available.
378 *
379 * @param cls NULL
380 */
381static void
382listen_cb (void *cls);
383
384
385/**
386 * Functions with this signature are called whenever we need
387 * to close a queue due to a disconnect or failure to
388 * establish a connection.
389 *
390 * @param queue queue to close down
391 */
392static void
393queue_destroy (struct Queue *queue)
394{
395 struct GNUNET_MQ_Handle *mq;
396
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Disconnecting queue for peer `%s'\n",
399 GNUNET_i2s (&queue->target));
400 if (NULL != (mq = queue->mq))
401 {
402 queue->mq = NULL;
403 GNUNET_MQ_destroy (mq);
404 }
405 GNUNET_assert (GNUNET_YES ==
406 GNUNET_CONTAINER_multipeermap_remove (queue_map,
407 &queue->target,
408 queue));
409 GNUNET_STATISTICS_set (stats,
410 "# UNIX queues active",
411 GNUNET_CONTAINER_multipeermap_size (queue_map),
412 GNUNET_NO);
413 if (NULL != queue->read_task)
414 {
415 GNUNET_SCHEDULER_cancel (queue->read_task);
416 queue->read_task = NULL;
417 }
418 if (NULL != queue->write_task)
419 {
420 GNUNET_SCHEDULER_cancel (queue->write_task);
421 queue->write_task = NULL;
422 }
423 GNUNET_NETWORK_socket_close (queue->sock);
424 gcry_cipher_close (queue->in_cipher);
425 gcry_cipher_close (queue->out_cipher);
426 GNUNET_free (queue->address);
427 GNUNET_free (queue);
428 if (NULL == listen_task)
429 listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
430 listen_sock,
431 &listen_cb,
432 NULL);
433
434}
435
436
437/**
438 * Queue read task. If we hit the timeout, disconnect it
439 *
440 * @param cls the `struct Queue *` to disconnect
441 */
442static void
443queue_read (void *cls)
444{
445 struct Queue *queue = cls;
446 struct GNUNET_TIME_Relative left;
447
448 queue->read_task = NULL;
449 /* CHECK IF READ-ready, then perform read! */
450
451 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
452 if (0 != left.rel_value_us)
453 {
454 /* not actually our turn yet, but let's at least update
455 the monitor, it may think we're about to die ... */
456 queue->read_task
457 = GNUNET_SCHEDULER_add_read_net (left,
458 queue->sock,
459 &queue_read,
460 queue);
461 return;
462 }
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Queue %p was idle for %s, disconnecting\n",
465 queue,
466 GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
467 GNUNET_YES));
468 // FIXME: try to send 'finish' message first!?
469 queue_destroy (queue);
470}
471
472
473/**
474 * Increment queue timeout due to activity. We do not immediately
475 * notify the monitor here as that might generate excessive
476 * signalling.
477 *
478 * @param queue queue for which the timeout should be rescheduled
479 */
480static void
481reschedule_queue_timeout (struct Queue *queue)
482{
483 GNUNET_assert (NULL != queue->read_task);
484 queue->timeout
485 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
486}
487
488
489/**
490 * Convert TCP bind specification to a `struct sockaddr *`
491 *
492 * @param bindto bind specification to convert
493 * @param[out] sock_len set to the length of the address
494 * @return converted bindto specification
495 */
496static struct sockaddr *
497tcp_address_to_sockaddr (const char *bindto,
498 socklen_t *sock_len)
499{
500 struct sockaddr *in;
501 size_t slen;
502
503 /* FIXME: parse, allocate, return! */
504 return NULL;
505}
506
507
508/**
509 * We have been notified that our socket is ready to write.
510 * Then reschedule this function to be called again once more is available.
511 *
512 * @param cls a `struct Queue`
513 */
514static void
515queue_write (void *cls)
516{
517 struct Queue *queue = cls;
518 const struct GNUNET_MessageHeader *msg = queue->msg;
519 size_t msg_size = ntohs (msg->size);
520
521 queue->write_task = NULL;
522 /* FIXME: send 'msg' */
523 /* FIXME: check if we have more messages pending */
524 queue->write_task
525 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
526 queue->sock,
527 &queue_write,
528 queue);
529}
530
531
532/**
533 * Signature of functions implementing the sending functionality of a
534 * message queue.
535 *
536 * @param mq the message queue
537 * @param msg the message to send
538 * @param impl_state our `struct Queue`
539 */
540static void
541mq_send (struct GNUNET_MQ_Handle *mq,
542 const struct GNUNET_MessageHeader *msg,
543 void *impl_state)
544{
545 struct Queue *queue = impl_state;
546
547 GNUNET_assert (mq == queue->mq);
548 GNUNET_assert (NULL == queue->msg);
549 queue->msg = msg;
550 GNUNET_assert (NULL != queue->sock);
551 if (NULL == queue->write_task)
552 queue->write_task =
553 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
554 queue->sock,
555 &queue_write,
556 queue);
557}
558
559
560/**
561 * Signature of functions implementing the destruction of a message
562 * queue. Implementations must not free @a mq, but should take care
563 * of @a impl_state.
564 *
565 * @param mq the message queue to destroy
566 * @param impl_state our `struct Queue`
567 */
568static void
569mq_destroy (struct GNUNET_MQ_Handle *mq,
570 void *impl_state)
571{
572 struct Queue *queue = impl_state;
573
574 if (mq == queue->mq)
575 {
576 queue->mq = NULL;
577 queue_destroy (queue);
578 }
579}
580
581
582/**
583 * Implementation function that cancels the currently sent message.
584 *
585 * @param mq message queue
586 * @param impl_state our `struct Queue`
587 */
588static void
589mq_cancel (struct GNUNET_MQ_Handle *mq,
590 void *impl_state)
591{
592 struct Queue *queue = impl_state;
593
594 GNUNET_assert (NULL != queue->msg);
595 queue->msg = NULL;
596 GNUNET_assert (NULL != queue->write_task);
597 if (1) // FIXME?
598 {
599 GNUNET_SCHEDULER_cancel (queue->write_task);
600 queue->write_task = NULL;
601 }
602}
603
604
605/**
606 * Generic error handler, called with the appropriate
607 * error code and the same closure specified at the creation of
608 * the message queue.
609 * Not every message queue implementation supports an error handler.
610 *
611 * @param cls our `struct Queue`
612 * @param error error code
613 */
614static void
615mq_error (void *cls,
616 enum GNUNET_MQ_Error error)
617{
618 struct Queue *queue = cls;
619
620 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
621 "TCP MQ error in queue to %s: %d\n",
622 GNUNET_i2s (&queue->target),
623 (int) error);
624 queue_destroy (queue);
625}
626
627
628/**
629 * Creates a new outbound queue the transport service will use to send
630 * data to another peer.
631 *
632 * @param peer the target peer
633 * @param cs inbound or outbound queue
634 * @param in the address
635 * @param in_len number of bytes in @a in
636 * @return the queue or NULL of max connections exceeded
637 */
638static struct Queue *
639setup_queue (struct GNUNET_NETWORK_Handle *sock,
640 enum GNUNET_TRANSPORT_ConnectionStatus cs,
641 const struct sockaddr *in,
642 socklen_t in_len)
643{
644 struct Queue *queue;
645
646 queue = GNUNET_new (struct Queue);
647 // queue->target = *target; // FIXME: handle case that we don't know the target yet!
648 queue->address = GNUNET_memdup (in,
649 in_len);
650 queue->address_len = in_len;
651 queue->sock = sock;
652 queue->nt = 0; // FIXME: determine NT!
653 (void) GNUNET_CONTAINER_multipeermap_put (queue_map,
654 &queue->target,
655 queue,
656 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
657 GNUNET_STATISTICS_set (stats,
658 "# queues active",
659 GNUNET_CONTAINER_multipeermap_size (queue_map),
660 GNUNET_NO);
661 queue->timeout
662 = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
663 queue->read_task
664 = GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
665 queue->sock,
666 &queue_read,
667 queue);
668 queue->mq
669 = GNUNET_MQ_queue_for_callbacks (&mq_send,
670 &mq_destroy,
671 &mq_cancel,
672 queue,
673 NULL,
674 &mq_error,
675 queue);
676 {
677 char *foreign_addr;
678
679 switch (queue->address->sa_family)
680 {
681 case AF_INET:
682 GNUNET_asprintf (&foreign_addr,
683 "%s-%s:%d",
684 COMMUNICATOR_ADDRESS_PREFIX,
685 "inet-ntop-fixme",
686 4242);
687 break;
688 case AF_INET6:
689 GNUNET_asprintf (&foreign_addr,
690 "%s-%s:%d",
691 COMMUNICATOR_ADDRESS_PREFIX,
692 "inet-ntop-fixme",
693 4242);
694 break;
695 default:
696 GNUNET_assert (0);
697 }
698 queue->qh
699 = GNUNET_TRANSPORT_communicator_mq_add (ch,
700 &queue->target,
701 foreign_addr,
702 0 /* no MTU */,
703 queue->nt,
704 cs,
705 queue->mq);
706 GNUNET_free (foreign_addr);
707 }
708 return queue;
709}
710
711
712/**
713 * We have been notified that our listen socket has something to
714 * read. Do the read and reschedule this function to be called again
715 * once more is available.
716 *
717 * @param cls NULL
718 */
719static void
720listen_cb (void *cls);
721
722
723/**
724 * We have been notified that our listen socket has something to
725 * read. Do the read and reschedule this function to be called again
726 * once more is available.
727 *
728 * @param cls NULL
729 */
730static void
731listen_cb (void *cls)
732{
733 char buf[65536] GNUNET_ALIGN;
734 struct Queue *queue;
735 struct sockaddr_storage in;
736 socklen_t addrlen;
737 ssize_t ret;
738 uint16_t msize;
739 struct GNUNET_NETWORK_Handle *sock;
740
741 listen_task = NULL;
742 GNUNET_assert (NULL != listen_sock);
743 addrlen = sizeof (in);
744 memset (&in,
745 0,
746 sizeof (in));
747 sock = GNUNET_NETWORK_socket_accept (listen_sock,
748 (struct sockaddr *) &in,
749 &addrlen);
750 if ( (NULL == sock) &&
751 ( (EMFILE == errno) ||
752 (ENFILE == errno) ) )
753 return; /* system limit reached, wait until connection goes down */
754 listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
755 listen_sock,
756 &listen_cb,
757 NULL);
758 if ( (NULL == sock) &&
759 ( (EAGAIN == errno) ||
760 (ENOBUFS == errno) ) )
761 return;
762 if (NULL == sock)
763 {
764 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
765 "accept");
766 return;
767 }
768 queue = setup_queue (sock,
769 GNUNET_TRANSPORT_CS_INBOUND,
770 (struct sockaddr *) &in,
771 addrlen);
772 if (NULL == queue)
773 {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 _("Maximum number of TCP connections exceeded, dropping incoming connection\n"));
776 return;
777 }
778}
779
780
781/**
782 * Function called by the transport service to initialize a
783 * message queue given address information about another peer.
784 * If and when the communication channel is established, the
785 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
786 * to notify the service that the channel is now up. It is
787 * the responsibility of the communicator to manage sane
788 * retries and timeouts for any @a peer/@a address combination
789 * provided by the transport service. Timeouts and retries
790 * do not need to be signalled to the transport service.
791 *
792 * @param cls closure
793 * @param peer identity of the other peer
794 * @param address where to send the message, human-readable
795 * communicator-specific format, 0-terminated, UTF-8
796 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
797 */
798static int
799mq_init (void *cls,
800 const struct GNUNET_PeerIdentity *peer,
801 const char *address)
802{
803 struct Queue *queue;
804 const char *path;
805 struct sockaddr *in;
806 socklen_t in_len;
807
808 if (0 != strncmp (address,
809 COMMUNICATOR_ADDRESS_PREFIX "-",
810 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
811 {
812 GNUNET_break_op (0);
813 return GNUNET_SYSERR;
814 }
815 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
816 in = tcp_address_to_sockaddr (path,
817 &in_len);
818#if FIXME
819 queue = setup_queue (peer,
820 GNUNET_TRANSPORT_CS_OUTBOUND,
821 in,
822 in_len);
823#endif
824 GNUNET_free (in);
825 if (NULL == queue)
826 {
827 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
828 "Failed to setup queue to %s at `%s'\n",
829 GNUNET_i2s (peer),
830 path);
831 return GNUNET_NO;
832 }
833 return GNUNET_OK;
834}
835
836
837/**
838 * Iterator over all message queues to clean up.
839 *
840 * @param cls NULL
841 * @param target unused
842 * @param value the queue to destroy
843 * @return #GNUNET_OK to continue to iterate
844 */
845static int
846get_queue_delete_it (void *cls,
847 const struct GNUNET_PeerIdentity *target,
848 void *value)
849{
850 struct Queue *queue = value;
851
852 (void) cls;
853 (void) target;
854 queue_destroy (queue);
855 return GNUNET_OK;
856}
857
858
859/**
860 * Shutdown the UNIX communicator.
861 *
862 * @param cls NULL (always)
863 */
864static void
865do_shutdown (void *cls)
866{
867 if (NULL != listen_task)
868 {
869 GNUNET_SCHEDULER_cancel (listen_task);
870 listen_task = NULL;
871 }
872 if (NULL != listen_sock)
873 {
874 GNUNET_break (GNUNET_OK ==
875 GNUNET_NETWORK_socket_close (listen_sock));
876 listen_sock = NULL;
877 }
878 GNUNET_CONTAINER_multipeermap_iterate (queue_map,
879 &get_queue_delete_it,
880 NULL);
881 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
882 if (NULL != ai)
883 {
884 GNUNET_TRANSPORT_communicator_address_remove (ai);
885 ai = NULL;
886 }
887 if (NULL != ch)
888 {
889 GNUNET_TRANSPORT_communicator_disconnect (ch);
890 ch = NULL;
891 }
892 if (NULL != stats)
893 {
894 GNUNET_STATISTICS_destroy (stats,
895 GNUNET_NO);
896 stats = NULL;
897 }
898}
899
900
901/**
902 * Function called when the transport service has received an
903 * acknowledgement for this communicator (!) via a different return
904 * path.
905 *
906 * Not applicable for UNIX.
907 *
908 * @param cls closure
909 * @param sender which peer sent the notification
910 * @param msg payload
911 */
912static void
913enc_notify_cb (void *cls,
914 const struct GNUNET_PeerIdentity *sender,
915 const struct GNUNET_MessageHeader *msg)
916{
917 (void) cls;
918 (void) sender;
919 (void) msg;
920 GNUNET_break_op (0);
921}
922
923
924/**
925 * Setup communicator and launch network interactions.
926 *
927 * @param cls NULL (always)
928 * @param args remaining command-line arguments
929 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
930 * @param cfg configuration
931 */
932static void
933run (void *cls,
934 char *const *args,
935 const char *cfgfile,
936 const struct GNUNET_CONFIGURATION_Handle *cfg)
937{
938 char *bindto;
939 struct sockaddr *in;
940 socklen_t in_len;
941 char *my_addr;
942 (void) cls;
943
944 if (GNUNET_OK !=
945 GNUNET_CONFIGURATION_get_value_filename (cfg,
946 COMMUNICATOR_CONFIG_SECTION,
947 "BINDTO",
948 &bindto))
949 {
950 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
951 COMMUNICATOR_CONFIG_SECTION,
952 "BINDTO");
953 return;
954 }
955 if (GNUNET_OK !=
956 GNUNET_CONFIGURATION_get_value_number (cfg,
957 COMMUNICATOR_CONFIG_SECTION,
958 "MAX_QUEUE_LENGTH",
959 &max_queue_length))
960 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
961
962 in = tcp_address_to_sockaddr (bindto,
963 &in_len);
964 if (NULL == in)
965 {
966 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
967 "Failed to setup TCP socket address with path `%s'\n",
968 bindto);
969 GNUNET_free (bindto);
970 return;
971 }
972 listen_sock = GNUNET_NETWORK_socket_create (in->sa_family,
973 SOCK_STREAM,
974 IPPROTO_TCP);
975 if (NULL == listen_sock)
976 {
977 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
978 "socket");
979 GNUNET_free (in);
980 GNUNET_free (bindto);
981 return;
982 }
983 if (GNUNET_OK !=
984 GNUNET_NETWORK_socket_bind (listen_sock,
985 in,
986 in_len))
987 {
988 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
989 "bind",
990 bindto);
991 GNUNET_NETWORK_socket_close (listen_sock);
992 listen_sock = NULL;
993 GNUNET_free (in);
994 GNUNET_free (bindto);
995 return;
996 }
997 GNUNET_free (in);
998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999 "Bound to `%s'\n",
1000 bindto);
1001 stats = GNUNET_STATISTICS_create ("C-TCP",
1002 cfg);
1003 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1004 NULL);
1005 listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1006 listen_sock,
1007 &listen_cb,
1008 NULL);
1009 queue_map = GNUNET_CONTAINER_multipeermap_create (10,
1010 GNUNET_NO);
1011 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1012 COMMUNICATOR_CONFIG_SECTION,
1013 COMMUNICATOR_ADDRESS_PREFIX,
1014 GNUNET_TRANSPORT_CC_RELIABLE,
1015 &mq_init,
1016 NULL,
1017 &enc_notify_cb,
1018 NULL);
1019 if (NULL == ch)
1020 {
1021 GNUNET_break (0);
1022 GNUNET_SCHEDULER_shutdown ();
1023 GNUNET_free (bindto);
1024 return;
1025 }
1026 // FIXME: bindto is wrong here, we MUST get our external
1027 // IP address and really look at 'in' here as we might
1028 // be bound to loopback or some other specific IP address!
1029 GNUNET_asprintf (&my_addr,
1030 "%s-%s",
1031 COMMUNICATOR_ADDRESS_PREFIX,
1032 bindto);
1033 GNUNET_free (bindto);
1034 // FIXME: based on our bindto, we might not be able to tell the
1035 // network type yet! What to do here!?
1036 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1037 my_addr,
1038 GNUNET_NT_LOOPBACK, // FIXME: wrong NT!
1039 GNUNET_TIME_UNIT_FOREVER_REL);
1040 GNUNET_free (my_addr);
1041}
1042
1043
1044/**
1045 * The main function for the UNIX communicator.
1046 *
1047 * @param argc number of arguments from the command line
1048 * @param argv command line arguments
1049 * @return 0 ok, 1 on error
1050 */
1051int
1052main (int argc,
1053 char *const *argv)
1054{
1055 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1056 GNUNET_GETOPT_OPTION_END
1057 };
1058 int ret;
1059
1060 if (GNUNET_OK !=
1061 GNUNET_STRINGS_get_utf8_args (argc, argv,
1062 &argc, &argv))
1063 return 2;
1064
1065 ret =
1066 (GNUNET_OK ==
1067 GNUNET_PROGRAM_run (argc, argv,
1068 "gnunet-communicator-tcp",
1069 _("GNUnet TCP communicator"),
1070 options,
1071 &run,
1072 NULL)) ? 0 : 1;
1073 GNUNET_free ((void*) argv);
1074 return ret;
1075}
1076
1077
1078#if defined(LINUX) && defined(__GLIBC__)
1079#include <malloc.h>
1080
1081/**
1082 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1083 */
1084void __attribute__ ((constructor))
1085GNUNET_ARM_memory_init ()
1086{
1087 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1088 mallopt (M_TOP_PAD, 1 * 1024);
1089 malloc_trim (0);
1090}
1091#endif
1092
1093/* end of gnunet-communicator-tcp.c */