skeleton for TCP communicator
[oweals/gnunet.git] / src / transport / gnunet-communicator-tcp.c
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
61 GNUNET_NETWORK_STRUCT_BEGIN
62
63 /**
64  * TCP initial bytes on the wire (in either direction), used to 
65  * establish a shared secret.
66  */
67 struct 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  */
81 struct 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  */
114 struct 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  */ 
138 struct 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  */ 
165 struct 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  */ 
207 struct 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
228 GNUNET_NETWORK_STRUCT_END
229
230
231 /**
232  * Handle for a queue.
233  */
234 struct 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  */
336 static struct GNUNET_SCHEDULER_Task *listen_task;
337
338 /**
339  * Number of messages we currently have in our queues towards the transport service.
340  */
341 static unsigned long long delivering_messages;
342
343 /**
344  * Maximum queue length before we stop reading towards the transport service.
345  */
346 static unsigned long long max_queue_length;
347
348 /**
349  * For logging statistics.
350  */
351 static struct GNUNET_STATISTICS_Handle *stats;
352
353 /**
354  * Our environment.
355  */
356 static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
357
358 /**
359  * Queues (map from peer identity to `struct Queue`)
360  */
361 static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
362
363 /**
364  * Listen socket.
365  */
366 static struct GNUNET_NETWORK_Handle *listen_sock;
367
368 /**
369  * Handle to the operation that publishes our address.
370  */
371 static 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  */
381 static void
382 listen_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  */
392 static void
393 queue_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  */
442 static void
443 queue_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  */
480 static void
481 reschedule_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  */
496 static struct sockaddr *
497 tcp_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  */
514 static void
515 queue_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  */
540 static void
541 mq_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  */
568 static void
569 mq_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  */
588 static void
589 mq_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  */
614 static void
615 mq_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  */
638 static struct Queue *
639 setup_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  */
719 static void
720 listen_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  */
730 static void
731 listen_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  */
798 static int
799 mq_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  */
845 static int
846 get_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  */
864 static void
865 do_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  */
912 static void
913 enc_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  */
932 static void
933 run (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  */
1051 int
1052 main (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  */
1084 void __attribute__ ((constructor))
1085 GNUNET_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 */