more work on 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, 2019 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_signatures.h"
37 #include "gnunet_constants.h"
38 #include "gnunet_nt_lib.h"
39 #include "gnunet_statistics_service.h"
40 #include "gnunet_transport_communication_service.h"
41
42 /**
43  * How many messages do we keep at most in the queue to the
44  * transport service before we start to drop (default,
45  * can be changed via the configuration file).
46  * Should be _below_ the level of the communicator API, as
47  * otherwise we may read messages just to have them dropped
48  * by the communicator API.
49  */
50 #define DEFAULT_MAX_QUEUE_LENGTH 8
51
52 /**
53  * Size of our IO buffers for ciphertext data. Must be at
54  * least UINT_MAX + sizeof (struct TCPBox).
55  */
56 #define BUF_SIZE (2 * 64 * 1024 + sizeof (struct TCPBox))
57
58 /**
59  * How often do we rekey based on time (at least)
60  */ 
61 #define REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS
62
63 /**
64  * How often do we rekey based on number of bytes transmitted?
65  * (additionally randomized).
66  */ 
67 #define REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
68
69 /**
70  * Address prefix used by the communicator.
71  */
72 #define COMMUNICATOR_ADDRESS_PREFIX "tcp"
73
74 /**
75  * Configuration section used by the communicator.
76  */
77 #define COMMUNICATOR_CONFIG_SECTION "communicator-tcp"
78
79 GNUNET_NETWORK_STRUCT_BEGIN
80
81
82 /**
83  * Signature we use to verify that the ephemeral key was really chosen by
84  * the specified sender.
85  */
86 struct TcpHandshakeSignature
87 {
88   /**
89    * Purpose must be #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
90    */
91   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
92
93   /**
94    * Identity of the inititor of the TCP connection (TCP client).
95    */ 
96   struct GNUNET_PeerIdentity sender;
97
98   /**
99    * Presumed identity of the target of the TCP connection (TCP server)
100    */ 
101   struct GNUNET_PeerIdentity receiver;
102
103   /**
104    * Ephemeral key used by the @e sender.
105    */ 
106   struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
107
108   /**
109    * Monotonic time of @e sender, to possibly help detect replay attacks
110    * (if receiver persists times by sender).
111    */ 
112   struct GNUNET_TIME_AbsoluteNBO monotonic_time;
113 };
114
115
116 /**
117  * Encrypted continuation of TCP initial handshake.
118  */
119 struct TCPConfirmation
120 {
121   /**
122    * Sender's identity
123    */
124   struct GNUNET_PeerIdentity sender;
125
126   /**
127    * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
128    */
129   struct GNUNET_CRYPTO_EddsaSignature sender_sig;
130
131   /**
132    * Monotonic time of @e sender, to possibly help detect replay attacks
133    * (if receiver persists times by sender).
134    */ 
135   struct GNUNET_TIME_AbsoluteNBO monotonic_time;
136
137 };
138
139
140 /**
141  * TCP message box.  Always sent encrypted!
142  */ 
143 struct TCPBox
144 {
145   
146   /**
147    * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX.  Warning: the
148    * header size EXCLUDES the size of the `struct TCPBox`. We usually
149    * never do this, but here the payload may truly be 64k *after* the
150    * TCPBox (as we have no MTU)!!
151    */ 
152   struct GNUNET_MessageHeader header;
153
154   /**
155    * HMAC for the following encrypted message.  Yes, we MUST use
156    * mac-then-encrypt here, as we want to hide the message sizes on
157    * the wire (zero plaintext design!).  Using CTR mode padding oracle
158    * attacks do not apply.  Besides, due to the use of ephemeral keys
159    * (hopefully with effective replay protection from monotonic time!)
160    * the attacker is limited in using the oracle.
161    */ 
162   struct GNUNET_ShortHashCode hmac;
163
164   /* followed by as may bytes of payload as indicated in @e header,
165      excluding the TCPBox itself! */
166   
167 };
168
169
170 /**
171  * TCP rekey message box.  Always sent encrypted!  Data after
172  * this message will use the new key.
173  */ 
174 struct TCPRekey
175 {
176
177   /**
178    * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY.
179    */ 
180   struct GNUNET_MessageHeader header;
181
182   /**
183    * HMAC for the following encrypted message.  Yes, we MUST use
184    * mac-then-encrypt here, as we want to hide the message sizes on
185    * the wire (zero plaintext design!).  Using CTR mode padding oracle
186    * attacks do not apply.  Besides, due to the use of ephemeral keys
187    * (hopefully with effective replay protection from monotonic time!)
188    * the attacker is limited in using the oracle.
189    */ 
190   struct GNUNET_ShortHashCode hmac;
191
192   /**
193    * New ephemeral key.
194    */ 
195   struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
196   
197   /**
198    * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY
199    */
200   struct GNUNET_CRYPTO_EddsaSignature sender_sig;
201
202   /**
203    * Monotonic time of @e sender, to possibly help detect replay attacks
204    * (if receiver persists times by sender).
205    */ 
206   struct GNUNET_TIME_AbsoluteNBO monotonic_time;
207
208 };
209
210
211 /**
212  * TCP finish. Sender asks for the connection to be closed.
213  * Needed/useful in case we drop RST/FIN packets on the GNUnet
214  * port due to the possibility of malicious RST/FIN injection.
215  */ 
216 struct TCPFinish
217 {
218
219   /**
220    * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH.
221    */ 
222   struct GNUNET_MessageHeader header;
223
224   /**
225    * HMAC for the following encrypted message.  Yes, we MUST use
226    * mac-then-encrypt here, as we want to hide the message sizes on
227    * the wire (zero plaintext design!).  Using CTR mode padding oracle
228    * attacks do not apply.  Besides, due to the use of ephemeral keys
229    * (hopefully with effective replay protection from monotonic time!)
230    * the attacker is limited in using the oracle.
231    */ 
232   struct GNUNET_ShortHashCode hmac;
233
234 };
235
236
237 GNUNET_NETWORK_STRUCT_END
238
239
240 /**
241  * Handle for a queue.
242  */
243 struct Queue
244 {
245
246   /**
247    * To whom are we talking to.
248    */
249   struct GNUNET_PeerIdentity target;
250
251   /**
252    * socket that we transmit all data with on this queue
253    */
254   struct GNUNET_NETWORK_Handle *sock;
255
256   /**
257    * cipher for decryption of incoming data.
258    */ 
259   gcry_cipher_hd_t in_cipher;
260
261   /**
262    * cipher for encryption of outgoing data.
263    */
264   gcry_cipher_hd_t out_cipher;
265
266   /**
267    * Shared secret for HMAC verification on incoming data.
268    */ 
269   struct GNUNET_HashCode in_hmac;
270
271   /**
272    * Shared secret for HMAC generation on outgoing data, ratcheted after
273    * each operation.
274    */ 
275   struct GNUNET_HashCode out_hmac;
276
277   /**
278    * Our ephemeral key. Stored here temporarily during rekeying / key generation.
279    */
280   struct GNUNET_CRYPTO_EcdhePrivateKey ephemeral;
281   
282   /**
283    * ID of read task for this connection.
284    */
285   struct GNUNET_SCHEDULER_Task *read_task;
286
287   /**
288    * ID of write task for this connection.
289    */
290   struct GNUNET_SCHEDULER_Task *write_task;
291
292   /**
293    * Address of the other peer.
294    */
295   struct sockaddr *address;
296   
297   /**
298    * How many more bytes may we sent with the current @e out_cipher
299    * before we should rekey?
300    */
301   uint64_t rekey_left_bytes;
302
303   /**
304    * Until what time may we sent with the current @e out_cipher
305    * before we should rekey?
306    */
307   struct GNUNET_TIME_Absolute rekey_time;
308   
309   /**
310    * Length of the address.
311    */
312   socklen_t address_len;
313
314   /**
315    * Message queue we are providing for the #ch.
316    */
317   struct GNUNET_MQ_Handle *mq;
318
319   /**
320    * handle for this queue with the #ch.
321    */
322   struct GNUNET_TRANSPORT_QueueHandle *qh;
323
324   /**
325    * Number of bytes we currently have in our write queue.
326    */
327   unsigned long long bytes_in_queue;
328
329   /**
330    * Buffer for reading ciphertext from network into.
331    */
332   char cread_buf[BUF_SIZE];
333
334   /**
335    * buffer for writing ciphertext to network.
336    */
337   char cwrite_buf[BUF_SIZE];
338
339   /**
340    * Plaintext buffer for decrypted plaintext.
341    */
342   char pread_buf[UINT16_MAX + 1 + sizeof (struct TCPBox)];
343
344   /**
345    * Plaintext buffer for messages to be encrypted.
346    */
347   char pwrite_buf[UINT16_MAX + 1 + sizeof (struct TCPBox)];
348   
349   /**
350    * At which offset in the ciphertext read buffer should we
351    * append more ciphertext for transmission next?
352    */
353   size_t cread_off;
354
355   /**
356    * At which offset in the ciphertext write buffer should we
357    * append more ciphertext from reading next?
358    */
359   size_t cwrite_off;
360   
361   /**
362    * At which offset in the plaintext input buffer should we
363    * append more plaintext from decryption next?
364    */
365   size_t pread_off;
366   
367   /**
368    * At which offset in the plaintext output buffer should we
369    * append more plaintext for encryption next?
370    */
371   size_t pwrite_off;
372
373   /**
374    * Timeout for this queue.
375    */
376   struct GNUNET_TIME_Absolute timeout;
377
378   /**
379    * Which network type does this queue use?
380    */
381   enum GNUNET_NetworkType nt;
382
383   /**
384    * Is MQ awaiting a #GNUNET_MQ_impl_send_continue() call?
385    */
386   int mq_awaits_continue;
387   
388   /**
389    * Did we enqueue a finish message and are closing down the queue?
390    */
391   int finishing;
392
393   /**
394    * #GNUNET_YES after #inject_key() placed the rekey message into the
395    * plaintext buffer. Once the plaintext buffer is drained, this
396    * means we must switch to the new key material.
397    */
398   int rekey_state;
399 };
400
401
402 /**
403  * ID of listen task
404  */
405 static struct GNUNET_SCHEDULER_Task *listen_task;
406
407 /**
408  * Number of messages we currently have in our queues towards the transport service.
409  */
410 static unsigned long long delivering_messages;
411
412 /**
413  * Maximum queue length before we stop reading towards the transport service.
414  */
415 static unsigned long long max_queue_length;
416
417 /**
418  * For logging statistics.
419  */
420 static struct GNUNET_STATISTICS_Handle *stats;
421
422 /**
423  * Our environment.
424  */
425 static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
426
427 /**
428  * Queues (map from peer identity to `struct Queue`)
429  */
430 static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
431
432 /**
433  * Listen socket.
434  */
435 static struct GNUNET_NETWORK_Handle *listen_sock;
436
437 /**
438  * Handle to the operation that publishes our address.
439  */
440 static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
441
442 /**
443  * Our public key.
444  */
445 static struct GNUNET_PeerIdentity my_identity;
446
447 /**
448  * Our private key.
449  */
450 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
451
452 /**
453  * Our configuration.
454  */
455 static const struct GNUNET_CONFIGURATION_Handle *cfg;
456
457
458 /**
459  * We have been notified that our listen socket has something to
460  * read. Do the read and reschedule this function to be called again
461  * once more is available.
462  *
463  * @param cls NULL
464  */
465 static void
466 listen_cb (void *cls);
467
468
469 /**
470  * Functions with this signature are called whenever we need
471  * to close a queue due to a disconnect or failure to
472  * establish a connection.
473  *
474  * @param queue queue to close down
475  */
476 static void
477 queue_destroy (struct Queue *queue)
478 {
479   struct GNUNET_MQ_Handle *mq;
480
481   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482               "Disconnecting queue for peer `%s'\n",
483               GNUNET_i2s (&queue->target));
484   if (NULL != (mq = queue->mq))
485   {
486     queue->mq = NULL;
487     GNUNET_MQ_destroy (mq);
488   }
489   GNUNET_assert (GNUNET_YES ==
490                  GNUNET_CONTAINER_multipeermap_remove (queue_map,
491                                                        &queue->target,
492                                                        queue));
493   GNUNET_STATISTICS_set (stats,
494                          "# queues active",
495                          GNUNET_CONTAINER_multipeermap_size (queue_map),
496                          GNUNET_NO);
497   if (NULL != queue->read_task)
498   {
499     GNUNET_SCHEDULER_cancel (queue->read_task);
500     queue->read_task = NULL;
501   }
502   if (NULL != queue->write_task)
503   {
504     GNUNET_SCHEDULER_cancel (queue->write_task);
505     queue->write_task = NULL;
506   }
507   GNUNET_NETWORK_socket_close (queue->sock);
508   gcry_cipher_close (queue->in_cipher);
509   gcry_cipher_close (queue->out_cipher);
510   GNUNET_free (queue->address);
511   GNUNET_free (queue);
512   if (NULL == listen_task)
513     listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
514                                                  listen_sock,
515                                                  &listen_cb,
516                                                  NULL);
517
518 }
519
520
521 /**
522  * Compute @a mac over @a buf, and ratched the @a hmac_secret.
523  *
524  * @param[in,out] hmac_secret secret for HMAC calculation
525  * @param buf buffer to MAC
526  * @param buf_size number of bytes in @a buf
527  * @param smac[out] where to write the HMAC
528  */
529 static void
530 hmac (struct GNUNET_HashCode *hmac_secret,
531       const void *buf,
532       size_t buf_size,
533       struct GNUNET_ShortHashCode *smac)
534 {
535   struct GNUNET_HashCode mac;
536
537   GNUNET_CRYPTO_hmac_raw (hmac_secret,
538                           sizeof (struct GNUNET_HashCode),
539                           buf,
540                           buf_size,
541                           &mac);
542   /* truncate to `struct GNUNET_ShortHashCode` */
543   memcpy (smac,
544           &mac,
545           sizeof (struct GNUNET_ShortHashCode));
546   /* ratchet hmac key */
547   GNUNET_CRYPTO_hash (hmac_secret,
548                       sizeof (struct GNUNET_HashCode),
549                       hmac_secret);
550 }
551
552
553 /**
554  * Append a 'finish' message to the outgoing transmission. Once the
555  * finish has been transmitted, destroy the queue.
556  *
557  * @param queue queue to shut down nicely
558  */
559 static void
560 queue_finish (struct Queue *queue)
561 {
562   // FIXME: try to send 'finish' message first!?
563   queue_destroy (queue);
564 }
565
566
567 /**
568  * Queue read task. If we hit the timeout, disconnect it
569  *
570  * @param cls the `struct Queue *` to disconnect
571  */
572 static void
573 queue_read (void *cls)
574 {
575   struct Queue *queue = cls;
576   struct GNUNET_TIME_Relative left;
577   ssize_t rcvd;
578
579   queue->read_task = NULL;
580   /* FIXME: perform read! */
581   rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
582                                      &queue->cread_buf[queue->cread_off],
583                                      BUF_SIZE - queue->cread_off);
584   if (-1 == rcvd)
585   {
586     // FIXME: error handling...
587   }
588   if (0 != rcvd)
589     /* update queue timeout */
590   queue->cread_off += rcvd;
591   if (queue->pread_off < sizeof (queue->pread_buf))
592   {
593     /* FIXME: decrypt */
594   
595     /* FIXME: check plaintext for complete messages, if complete, hand to CORE */
596     /* FIXME: CORE flow control: suspend doing more until CORE has ACKed */
597   }
598   
599   if (BUF_SIZE == queue->cread_off)
600     return; /* buffer full, suspend reading */
601   left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
602   if (0 != left.rel_value_us) 
603   {
604     /* not actually our turn yet, but let's at least update
605        the monitor, it may think we're about to die ... */
606     queue->read_task
607       = GNUNET_SCHEDULER_add_read_net (left,
608                                        queue->sock,
609                                        &queue_read,
610                                        queue);
611
612     return;
613   }
614   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615               "Queue %p was idle for %s, disconnecting\n",
616               queue,
617               GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
618                                                       GNUNET_YES));
619   queue_finish (queue);
620 }
621
622
623 /**
624  * Increment queue timeout due to activity.  We do not immediately
625  * notify the monitor here as that might generate excessive
626  * signalling.
627  *
628  * @param queue queue for which the timeout should be rescheduled
629  */
630 static void
631 reschedule_queue_timeout (struct Queue *queue)
632 {
633   GNUNET_assert (NULL != queue->read_task);
634   queue->timeout
635     = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
636 }
637
638
639 /**
640  * Convert TCP bind specification to a `struct sockaddr *`
641  *
642  * @param bindto bind specification to convert
643  * @param[out] sock_len set to the length of the address
644  * @return converted bindto specification
645  */
646 static struct sockaddr *
647 tcp_address_to_sockaddr (const char *bindto,
648                          socklen_t *sock_len)
649 {
650   struct sockaddr *in;
651   size_t slen;
652
653   /* FIXME: parse, allocate, return! */
654   return NULL;
655 }
656
657
658 /**
659  * Setup @a cipher based on shared secret @a dh and decrypting
660  * peer @a pid.
661  *
662  * @param dh shared secret
663  * @param pid decrypting peer's identity
664  * @param cipher[out] cipher to initialize
665  * @param hmac_key[out] HMAC key to initialize
666  */
667 static void
668 setup_cipher (const struct GNUNET_HashCode *dh,
669               const struct GNUNET_PeerIdentity *pid,
670               gcry_cipher_hd_t *cipher,
671               struct GNUNET_HashCode *hmac_key)
672 {
673   char key[256/8];
674   char ctr[128/8];
675
676   gcry_cipher_open (cipher,
677                     GCRY_CIPHER_AES256 /* low level: go for speed */,
678                     GCRY_CIPHER_MODE_CTR,
679                     0 /* flags */);
680   GNUNET_assert (GNUNET_YES ==
681                  GNUNET_CRYPTO_kdf (key,
682                                     sizeof (key),
683                                     "TCP-key",
684                                     strlen ("TCP-key"),
685                                     dh,
686                                     sizeof (*dh),
687                                     pid,
688                                     sizeof (*pid),
689                                     NULL, 0));
690   gcry_cipher_setkey (*cipher,
691                       key,
692                       sizeof (key));
693   GNUNET_assert (GNUNET_YES ==
694                  GNUNET_CRYPTO_kdf (ctr,
695                                     sizeof (ctr),
696                                     "TCP-ctr",
697                                     strlen ("TCP-ctr"),
698                                     dh,
699                                     sizeof (*dh),
700                                     pid,
701                                     sizeof (*pid),
702                                     NULL, 0));
703   gcry_cipher_setctr (*cipher,
704                       ctr,
705                       sizeof (ctr));
706   GNUNET_assert (GNUNET_YES ==
707                  GNUNET_CRYPTO_kdf (hmac_key,
708                                     sizeof (struct GNUNET_HashCode),
709                                     "TCP-hmac",
710                                     strlen ("TCP-hmac"),
711                                     dh,
712                                     sizeof (*dh),
713                                     pid,
714                                     sizeof (*pid),
715                                     NULL, 0));
716 }
717
718
719 /**
720  * Setup cipher of @a queue for decryption.
721  *
722  * @param ephemeral ephemeral key we received from the other peer
723  * @param queue[in,out] queue to initialize decryption cipher for
724  */
725 static void
726 setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
727                  struct Queue *queue)
728 {
729   struct GNUNET_HashCode dh;
730   
731   GNUNET_CRYPTO_eddsa_ecdh (my_private_key,
732                             ephemeral,
733                             &dh);
734   setup_cipher (&dh,
735                 &my_identity,
736                 &queue->in_cipher,
737                 &queue->in_hmac);
738 }
739                 
740
741 /**
742  * Setup cipher for outgoing data stream based on target and
743  * our ephemeral private key.
744  *
745  * @param queue queue to setup outgoing (encryption) cipher for
746  */
747 static void
748 setup_out_cipher (struct Queue *queue)
749 {
750   struct GNUNET_HashCode dh;
751   
752   GNUNET_CRYPTO_ecdh_eddsa (&queue->ephemeral,
753                             &queue->target.public_key,
754                             &dh);
755   /* we don't need the private key anymore, drop it! */
756   memset (&queue->ephemeral,
757           0,
758           sizeof (queue->ephemeral));
759   setup_cipher (&dh,
760                 &queue->target,
761                 &queue->out_cipher,
762                 &queue->out_hmac);
763   
764   queue->rekey_time = GNUNET_TIME_relative_to_absolute (REKEY_TIME_INTERVAL);
765   queue->rekey_left_bytes = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
766                                                       REKEY_MAX_BYTES);
767 }
768
769
770 /**
771  * Inject a `struct TCPRekey` message into the queue's plaintext
772  * buffer.
773  *
774  * @param queue queue to perform rekeying on
775  */ 
776 static void
777 inject_rekey (struct Queue *queue)
778 {
779   struct TCPRekey rekey;
780   struct TcpHandshakeSignature thp;
781   
782   GNUNET_assert (0 == queue->pwrite_off);
783   memset (&rekey,
784           0,
785           sizeof (rekey));
786   GNUNET_assert (GNUNET_OK ==
787                  GNUNET_CRYPTO_ecdhe_key_create2 (&queue->ephemeral));
788   rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
789   rekey.header.size = ntohs (sizeof (rekey));
790   GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral,
791                                       &rekey.ephemeral);
792   rekey.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
793   thp.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY);
794   thp.purpose.size = htonl (sizeof (thp));
795   thp.sender = my_identity;
796   thp.receiver = queue->target;
797   thp.ephemeral = rekey.ephemeral;
798   thp.monotonic_time = rekey.monotonic_time;
799   GNUNET_assert (GNUNET_OK ==
800                  GNUNET_CRYPTO_eddsa_sign (my_private_key,
801                                            &thp.purpose,
802                                            &rekey.sender_sig));
803   hmac (&queue->out_hmac,
804         &rekey,
805         sizeof (rekey),
806         &rekey.hmac);
807   memcpy (queue->pwrite_buf,
808           &rekey,
809           sizeof (rekey));
810   queue->rekey_state = GNUNET_YES;
811 }
812
813
814 /**
815  * We encrypted the rekey message, now update actually swap the key
816  * material and update the key freshness parameters of @a queue.
817  */ 
818 static void
819 switch_key (struct Queue *queue)
820 {
821   queue->rekey_state = GNUNET_NO; 
822   gcry_cipher_close (queue->out_cipher);
823   setup_out_cipher (queue);
824 }
825
826
827 /**
828  * We have been notified that our socket is ready to write.
829  * Then reschedule this function to be called again once more is available.
830  *
831  * @param cls a `struct Queue`
832  */
833 static void
834 queue_write (void *cls)
835 {
836   struct Queue *queue = cls;
837   ssize_t sent;
838
839   queue->write_task = NULL;
840   sent = GNUNET_NETWORK_socket_send (queue->sock,
841                                      queue->cwrite_buf,
842                                      queue->cwrite_off);
843   if ( (-1 == sent) &&
844        (EAGAIN != errno) &&
845        (EINTR != errno) )
846   {
847     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
848                          "send");
849     queue_destroy (queue);
850     return;                      
851   }
852   if (sent > 0)
853   {
854     size_t usent = (size_t) sent;
855
856     memmove (queue->cwrite_buf,
857              &queue->cwrite_buf[sent],
858              queue->cwrite_off - sent);
859     /* FIXME: update queue timeout */ 
860  }
861   /* can we encrypt more? (always encrypt full messages, needed
862      such that #mq_cancel() can work!) */
863   if (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE)
864   {
865     GNUNET_assert (0 ==
866                    gcry_cipher_encrypt (queue->out_cipher,
867                                         &queue->cwrite_buf[queue->cwrite_off],
868                                         queue->pwrite_off,
869                                         queue->pwrite_buf,
870                                         queue->pwrite_off));
871     if (queue->rekey_left_bytes > queue->pwrite_off)
872       queue->rekey_left_bytes -= queue->pwrite_off;
873     else
874       queue->rekey_left_bytes = 0;
875     queue->cwrite_off += queue->pwrite_off;
876     queue->pwrite_off = 0;
877   }
878   if ( (GNUNET_YES == queue->rekey_state) &&
879        (0 == queue->pwrite_off) )
880     switch_key (queue);
881   if ( (0 == queue->pwrite_off) &&
882        ( (0 == queue->rekey_left_bytes) ||
883          (0 == GNUNET_TIME_absolute_get_remaining (queue->rekey_time).rel_value_us) ) )
884     inject_rekey (queue);
885   if ( (0 == queue->pwrite_off) &&
886        (! queue->finishing) &&
887        (queue->mq_awaits_continue) )
888   {
889     queue->mq_awaits_continue = GNUNET_NO;
890     GNUNET_MQ_impl_send_continue (queue->mq);
891   }
892   /* do we care to write more? */
893   if (0 < queue->cwrite_off)
894     queue->write_task 
895       = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
896                                         queue->sock,
897                                         &queue_write,
898                                         queue);
899 }
900
901
902 /**
903  * Signature of functions implementing the sending functionality of a
904  * message queue.
905  *
906  * @param mq the message queue
907  * @param msg the message to send
908  * @param impl_state our `struct Queue`
909  */
910 static void
911 mq_send (struct GNUNET_MQ_Handle *mq,
912          const struct GNUNET_MessageHeader *msg,
913          void *impl_state)
914 {
915   struct Queue *queue = impl_state;
916   uint16_t msize = ntohs (msg->size);
917   struct TCPBox box;
918
919   GNUNET_assert (mq == queue->mq);
920   GNUNET_assert (0 == queue->pread_off);
921   box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
922   box.header.size = htons (msize);
923   hmac (&queue->out_hmac,
924         msg,
925         msize,
926         &box.hmac);
927   memcpy (&queue->pread_buf[queue->pread_off],
928           &box,
929           sizeof (box));
930   queue->pread_off += sizeof (box);
931   memcpy (&queue->pread_buf[queue->pread_off],
932           msg,
933           msize);
934   queue->pread_off += msize;
935   GNUNET_assert (NULL != queue->sock);
936   if (NULL == queue->write_task)
937     queue->write_task =
938       GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
939                                       queue->sock,
940                                       &queue_write,
941                                       queue);
942 }
943
944
945 /**
946  * Signature of functions implementing the destruction of a message
947  * queue.  Implementations must not free @a mq, but should take care
948  * of @a impl_state.
949  *
950  * @param mq the message queue to destroy
951  * @param impl_state our `struct Queue`
952  */
953 static void
954 mq_destroy (struct GNUNET_MQ_Handle *mq,
955             void *impl_state)
956 {
957   struct Queue *queue = impl_state;
958
959   if (mq == queue->mq)
960   {
961     queue->mq = NULL;
962     queue_finish (queue);
963   }
964 }
965
966
967 /**
968  * Implementation function that cancels the currently sent message.
969  *
970  * @param mq message queue
971  * @param impl_state our `struct Queue`
972  */
973 static void
974 mq_cancel (struct GNUNET_MQ_Handle *mq,
975            void *impl_state)
976 {
977   struct Queue *queue = impl_state;
978
979   GNUNET_assert (0 != queue->pwrite_off);
980   queue->pwrite_off = 0;
981 }
982
983
984 /**
985  * Generic error handler, called with the appropriate
986  * error code and the same closure specified at the creation of
987  * the message queue.
988  * Not every message queue implementation supports an error handler.
989  *
990  * @param cls our `struct Queue`
991  * @param error error code
992  */
993 static void
994 mq_error (void *cls,
995           enum GNUNET_MQ_Error error)
996 {
997   struct Queue *queue = cls;
998
999   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1000               "MQ error in queue to %s: %d\n",
1001               GNUNET_i2s (&queue->target),
1002               (int) error);
1003   queue_finish (queue);
1004 }
1005
1006
1007 /**
1008  * Creates a new outbound queue the transport service will use to send
1009  * data to another peer.
1010  *
1011  * @param sock the queue's socket
1012  * @param target the target peer
1013  * @param cs inbound or outbound queue
1014  * @param in the address
1015  * @param in_len number of bytes in @a in
1016  * @return the queue or NULL of max connections exceeded
1017  */
1018 static struct Queue *
1019 setup_queue (struct GNUNET_NETWORK_Handle *sock,
1020              const struct GNUNET_PeerIdentity *target,
1021              enum GNUNET_TRANSPORT_ConnectionStatus cs,
1022              const struct sockaddr *in,
1023              socklen_t in_len)
1024 {
1025   struct Queue *queue;
1026
1027   queue = GNUNET_new (struct Queue);
1028   queue->target = *target; 
1029   queue->address = GNUNET_memdup (in,
1030                                   in_len);
1031   queue->address_len = in_len;
1032   queue->sock = sock; 
1033   queue->nt = 0; // FIXME: determine NT!
1034   (void) GNUNET_CONTAINER_multipeermap_put (queue_map,
1035                                             &queue->target,
1036                                             queue,
1037                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1038   GNUNET_STATISTICS_set (stats,
1039                          "# queues active",
1040                          GNUNET_CONTAINER_multipeermap_size (queue_map),
1041                          GNUNET_NO);
1042   queue->timeout
1043     = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1044   queue->read_task
1045     = GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1046                                      queue->sock,
1047                                      &queue_read,
1048                                      queue);
1049   queue->mq
1050     = GNUNET_MQ_queue_for_callbacks (&mq_send,
1051                                      &mq_destroy,
1052                                      &mq_cancel,
1053                                      queue,
1054                                      NULL,
1055                                      &mq_error,
1056                                      queue);
1057   {
1058     char *foreign_addr;
1059
1060     switch (queue->address->sa_family)
1061     {
1062     case AF_INET:
1063       GNUNET_asprintf (&foreign_addr,
1064                        "%s-%s:%d",
1065                        COMMUNICATOR_ADDRESS_PREFIX,
1066                        "inet-ntop-fixme",
1067                        4242);
1068       break;
1069     case AF_INET6:
1070       GNUNET_asprintf (&foreign_addr,
1071                        "%s-%s:%d",
1072                        COMMUNICATOR_ADDRESS_PREFIX,
1073                        "inet-ntop-fixme",
1074                        4242);
1075       break;
1076     default:
1077       GNUNET_assert (0);
1078     }
1079     queue->qh
1080       = GNUNET_TRANSPORT_communicator_mq_add (ch,
1081                                               &queue->target,
1082                                               foreign_addr,
1083                                               0 /* no MTU */,
1084                                               queue->nt,
1085                                               cs,
1086                                               queue->mq);
1087     GNUNET_free (foreign_addr);
1088   }
1089   return queue;
1090 }
1091
1092
1093 /**
1094  * We have been notified that our listen socket has something to
1095  * read. Do the read and reschedule this function to be called again
1096  * once more is available.
1097  *
1098  * @param cls NULL
1099  */
1100 static void
1101 listen_cb (void *cls);
1102
1103
1104 /**
1105  * We have been notified that our listen socket has something to
1106  * read. Do the read and reschedule this function to be called again
1107  * once more is available.
1108  *
1109  * @param cls NULL
1110  */
1111 static void
1112 listen_cb (void *cls)
1113 {
1114   struct Queue *queue;
1115   struct sockaddr_storage in;
1116   socklen_t addrlen;
1117   struct GNUNET_NETWORK_Handle *sock;
1118
1119   listen_task = NULL;
1120   GNUNET_assert (NULL != listen_sock);
1121   addrlen = sizeof (in);
1122   memset (&in,
1123           0,
1124           sizeof (in));
1125   sock = GNUNET_NETWORK_socket_accept (listen_sock,
1126                                        (struct sockaddr *) &in,
1127                                        &addrlen);
1128   if ( (NULL == sock) &&
1129        ( (EMFILE == errno) ||
1130          (ENFILE == errno) ) )
1131     return; /* system limit reached, wait until connection goes down */
1132   listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1133                                                listen_sock,
1134                                                &listen_cb,
1135                                                NULL);
1136   if ( (NULL == sock) &&
1137        ( (EAGAIN == errno) ||
1138          (ENOBUFS == errno) ) )
1139     return;
1140   if (NULL == sock)
1141   {
1142     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1143                          "accept");
1144     return;
1145   }
1146 #if 0
1147   // FIXME: setup proto-queue first here, until we have received the starting
1148   // messages!
1149   queue = setup_queue (sock,
1150                        GNUNET_TRANSPORT_CS_INBOUND,
1151                        (struct sockaddr *) &in,
1152                        addrlen);
1153   if (NULL == queue)
1154   {
1155     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1156                 _("Maximum number of TCP connections exceeded, dropping incoming connection\n"));
1157     return;
1158   }
1159 #endif
1160 }
1161
1162
1163 /**
1164  * Function called by the transport service to initialize a
1165  * message queue given address information about another peer.
1166  * If and when the communication channel is established, the
1167  * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
1168  * to notify the service that the channel is now up.  It is
1169  * the responsibility of the communicator to manage sane
1170  * retries and timeouts for any @a peer/@a address combination
1171  * provided by the transport service.  Timeouts and retries
1172  * do not need to be signalled to the transport service.
1173  *
1174  * @param cls closure
1175  * @param peer identity of the other peer
1176  * @param address where to send the message, human-readable
1177  *        communicator-specific format, 0-terminated, UTF-8
1178  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
1179  */
1180 static int
1181 mq_init (void *cls,
1182          const struct GNUNET_PeerIdentity *peer,
1183          const char *address)
1184 {
1185   struct Queue *queue;
1186   const char *path;
1187   struct sockaddr *in;
1188   socklen_t in_len;
1189   struct GNUNET_NETWORK_Handle *sock;
1190   struct GNUNET_CRYPTO_EcdhePublicKey epub;
1191   struct TcpHandshakeSignature ths;
1192   struct TCPConfirmation tc;
1193
1194   if (0 != strncmp (address,
1195                     COMMUNICATOR_ADDRESS_PREFIX "-",
1196                     strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
1197   {
1198     GNUNET_break_op (0);
1199     return GNUNET_SYSERR;
1200   }
1201   path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
1202   in = tcp_address_to_sockaddr (path,
1203                                 &in_len);
1204   
1205   sock = GNUNET_NETWORK_socket_create (in->sa_family,
1206                                        SOCK_STREAM,
1207                                        IPPROTO_TCP);
1208   if (NULL == sock)
1209   {
1210     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1211                 "socket(%d) failed: %s",
1212                 in->sa_family,
1213                 STRERROR (errno));
1214     GNUNET_free (in);
1215     return GNUNET_SYSERR;
1216   }
1217   if (GNUNET_OK !=
1218       GNUNET_NETWORK_socket_connect (sock,
1219                                      in,
1220                                      in_len))
1221   {
1222     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1223                 "connect to `%s' failed: %s",
1224                 address,
1225                 STRERROR (errno));
1226     GNUNET_NETWORK_socket_close (sock);
1227     GNUNET_free (in);
1228     return GNUNET_SYSERR;
1229   }
1230   queue = setup_queue (sock,
1231                        peer,
1232                        GNUNET_TRANSPORT_CS_OUTBOUND,
1233                        in,
1234                        in_len);
1235   GNUNET_free (in);
1236   if (NULL == queue)
1237   {
1238     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1239                 "Failed to setup queue to %s at `%s'\n",
1240                 GNUNET_i2s (peer),
1241                 path);
1242     GNUNET_NETWORK_socket_close (sock);
1243     return GNUNET_NO;
1244   }
1245   GNUNET_assert (GNUNET_OK ==
1246                  GNUNET_CRYPTO_ecdhe_key_create2 (&queue->ephemeral)); 
1247   GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral,
1248                                       &epub);
1249   setup_out_cipher (queue);
1250   memcpy (queue->cwrite_buf,
1251           &epub,
1252           sizeof (epub));
1253   queue->cwrite_off = sizeof (epub);
1254   /* compute 'tc' and append in encrypted format to cwrite_buf */
1255   tc.sender = my_identity;
1256   tc.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1257   ths.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE);
1258   ths.purpose.size = htonl (sizeof (ths));
1259   ths.sender = my_identity;
1260   ths.receiver = queue->target;
1261   ths.ephemeral = epub;
1262   ths.monotonic_time = tc.monotonic_time;
1263   GNUNET_assert (GNUNET_OK ==
1264                  GNUNET_CRYPTO_eddsa_sign (my_private_key,
1265                                            &ths.purpose,
1266                                            &tc.sender_sig));
1267   GNUNET_assert (0 ==
1268                  gcry_cipher_encrypt (queue->out_cipher,
1269                                       &queue->cwrite_buf[queue->cwrite_off],
1270                                       sizeof (tc),
1271                                       &tc,
1272                                       sizeof (tc)));
1273   queue->cwrite_off += sizeof (tc);
1274   
1275   return GNUNET_OK;
1276 }
1277
1278
1279 /**
1280  * Iterator over all message queues to clean up.
1281  *
1282  * @param cls NULL
1283  * @param target unused
1284  * @param value the queue to destroy
1285  * @return #GNUNET_OK to continue to iterate
1286  */
1287 static int
1288 get_queue_delete_it (void *cls,
1289                      const struct GNUNET_PeerIdentity *target,
1290                      void *value)
1291 {
1292   struct Queue *queue = value;
1293
1294   (void) cls;
1295   (void) target;
1296   queue_destroy (queue);
1297   return GNUNET_OK;
1298 }
1299
1300
1301 /**
1302  * Shutdown the UNIX communicator.
1303  *
1304  * @param cls NULL (always)
1305  */
1306 static void
1307 do_shutdown (void *cls)
1308 {
1309   if (NULL != listen_task)
1310   {
1311     GNUNET_SCHEDULER_cancel (listen_task);
1312     listen_task = NULL;
1313   }
1314   if (NULL != listen_sock)
1315   {
1316     GNUNET_break (GNUNET_OK ==
1317                   GNUNET_NETWORK_socket_close (listen_sock));
1318     listen_sock = NULL;
1319   }
1320   GNUNET_CONTAINER_multipeermap_iterate (queue_map,
1321                                          &get_queue_delete_it,
1322                                          NULL);
1323   GNUNET_CONTAINER_multipeermap_destroy (queue_map);
1324   if (NULL != ai)
1325   {
1326     GNUNET_TRANSPORT_communicator_address_remove (ai);
1327     ai = NULL;
1328   }
1329   if (NULL != ch)
1330   {
1331     GNUNET_TRANSPORT_communicator_disconnect (ch);
1332     ch = NULL;
1333   }
1334   if (NULL != stats)
1335   {
1336     GNUNET_STATISTICS_destroy (stats,
1337                                GNUNET_NO);
1338     stats = NULL;
1339   }
1340   if (NULL != my_private_key)
1341   {
1342     GNUNET_free (my_private_key);
1343     my_private_key = NULL;
1344   }
1345 }
1346
1347
1348 /**
1349  * Function called when the transport service has received an
1350  * acknowledgement for this communicator (!) via a different return
1351  * path.
1352  *
1353  * Not applicable for TCP.
1354  *
1355  * @param cls closure
1356  * @param sender which peer sent the notification
1357  * @param msg payload
1358  */
1359 static void
1360 enc_notify_cb (void *cls,
1361                const struct GNUNET_PeerIdentity *sender,
1362                const struct GNUNET_MessageHeader *msg)
1363 {
1364   (void) cls;
1365   (void) sender;
1366   (void) msg;
1367   GNUNET_break_op (0);
1368 }
1369
1370
1371 /**
1372  * Setup communicator and launch network interactions.
1373  *
1374  * @param cls NULL (always)
1375  * @param args remaining command-line arguments
1376  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1377  * @param c configuration
1378  */
1379 static void
1380 run (void *cls,
1381      char *const *args,
1382      const char *cfgfile,
1383      const struct GNUNET_CONFIGURATION_Handle *c)
1384 {
1385   char *bindto;
1386   struct sockaddr *in;
1387   socklen_t in_len;
1388   char *my_addr;
1389   (void) cls;
1390
1391   cfg = c;
1392   if (GNUNET_OK !=
1393       GNUNET_CONFIGURATION_get_value_filename (cfg,
1394                                                COMMUNICATOR_CONFIG_SECTION,
1395                                                "BINDTO",
1396                                                &bindto))
1397   {
1398     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1399                                COMMUNICATOR_CONFIG_SECTION,
1400                                "BINDTO");
1401     return;
1402   }
1403   if (GNUNET_OK !=
1404       GNUNET_CONFIGURATION_get_value_number (cfg,
1405                                              COMMUNICATOR_CONFIG_SECTION,
1406                                              "MAX_QUEUE_LENGTH",
1407                                              &max_queue_length))
1408     max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1409
1410   in = tcp_address_to_sockaddr (bindto,
1411                                 &in_len);
1412   if (NULL == in)
1413   {
1414     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1415                 "Failed to setup TCP socket address with path `%s'\n",
1416                 bindto);
1417     GNUNET_free (bindto);
1418     return;
1419   }
1420   listen_sock = GNUNET_NETWORK_socket_create (in->sa_family,
1421                                               SOCK_STREAM,
1422                                               IPPROTO_TCP);
1423   if (NULL == listen_sock)
1424   {
1425     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1426                          "socket");
1427     GNUNET_free (in);
1428     GNUNET_free (bindto);
1429     return;
1430   }
1431   if (GNUNET_OK !=
1432       GNUNET_NETWORK_socket_bind (listen_sock,
1433                                   in,
1434                                   in_len))
1435   {
1436     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1437                               "bind",
1438                               bindto);
1439     GNUNET_NETWORK_socket_close (listen_sock);
1440     listen_sock = NULL;
1441     GNUNET_free (in);
1442     GNUNET_free (bindto);
1443     return;
1444   }
1445   GNUNET_free (in);
1446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447               "Bound to `%s'\n",
1448               bindto);
1449   stats = GNUNET_STATISTICS_create ("C-TCP",
1450                                     cfg);
1451   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1452                                  NULL);
1453   my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1454   if (NULL == my_private_key)
1455   {
1456     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1457                 _("Transport service is lacking key configuration settings. Exiting.\n"));
1458     GNUNET_SCHEDULER_shutdown ();
1459     return;
1460   }
1461   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
1462                                       &my_identity.public_key);
1463
1464   listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1465                                                listen_sock,
1466                                                &listen_cb,
1467                                                NULL);
1468   queue_map = GNUNET_CONTAINER_multipeermap_create (10,
1469                                                       GNUNET_NO);
1470   ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1471                                               COMMUNICATOR_CONFIG_SECTION,
1472                                               COMMUNICATOR_ADDRESS_PREFIX,
1473                                               GNUNET_TRANSPORT_CC_RELIABLE,
1474                                               &mq_init,
1475                                               NULL,
1476                                               &enc_notify_cb,
1477                                               NULL);
1478   if (NULL == ch)
1479   {
1480     GNUNET_break (0);
1481     GNUNET_SCHEDULER_shutdown ();
1482     GNUNET_free (bindto);
1483     return;
1484   }
1485   // FIXME: bindto is wrong here, we MUST get our external
1486   // IP address and really look at 'in' here as we might
1487   // be bound to loopback or some other specific IP address!
1488   GNUNET_asprintf (&my_addr,
1489                    "%s-%s",
1490                    COMMUNICATOR_ADDRESS_PREFIX,
1491                    bindto);
1492   GNUNET_free (bindto);
1493   // FIXME: based on our bindto, we might not be able to tell the
1494   // network type yet! What to do here!?
1495   ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1496                                                   my_addr,
1497                                                   GNUNET_NT_LOOPBACK, // FIXME: wrong NT!
1498                                                   GNUNET_TIME_UNIT_FOREVER_REL);
1499   GNUNET_free (my_addr);
1500 }
1501
1502
1503 /**
1504  * The main function for the UNIX communicator.
1505  *
1506  * @param argc number of arguments from the command line
1507  * @param argv command line arguments
1508  * @return 0 ok, 1 on error
1509  */
1510 int
1511 main (int argc,
1512       char *const *argv)
1513 {
1514   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1515     GNUNET_GETOPT_OPTION_END
1516   };
1517   int ret;
1518
1519   if (GNUNET_OK !=
1520       GNUNET_STRINGS_get_utf8_args (argc, argv,
1521                                     &argc, &argv))
1522     return 2;
1523
1524   ret =
1525       (GNUNET_OK ==
1526        GNUNET_PROGRAM_run (argc, argv,
1527                            "gnunet-communicator-tcp",
1528                            _("GNUnet TCP communicator"),
1529                            options,
1530                            &run,
1531                            NULL)) ? 0 : 1;
1532   GNUNET_free ((void*) argv);
1533   return ret;
1534 }
1535
1536
1537 #if defined(LINUX) && defined(__GLIBC__)
1538 #include <malloc.h>
1539
1540 /**
1541  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1542  */
1543 void __attribute__ ((constructor))
1544 GNUNET_ARM_memory_init ()
1545 {
1546   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1547   mallopt (M_TOP_PAD, 1 * 1024);
1548   malloc_trim (0);
1549 }
1550 #endif
1551
1552 /* end of gnunet-communicator-tcp.c */