Merge branch 'master' of git+ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / transport / transport-testing2.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 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/transport-testing2.c
23  * @brief functions related to testing-tng
24  * @author Christian Grothoff
25  * @author Julius Bünger
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_constants.h"
31 #include "transport-testing2.h"
32 #include "gnunet_ats_transport_service.h"
33 #include "gnunet_hello_lib.h"
34 #include "gnunet_signatures.h"
35 #include "transport.h"
36
37
38 #define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__)
39
40
41 /**
42  * @brief Handle to a transport communicator
43  */
44 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
45 {
46   /**
47    * @brief Handle to the configuration
48    */
49   struct GNUNET_CONFIGURATION_Handle *cfg;
50
51   /**
52    * @brief File name of configuration file
53    */
54   char *cfg_filename;
55
56   /**
57    * @brief Handle to the transport service
58    */
59   struct GNUNET_SERVICE_Handle *tsh;
60
61   /**
62    * @brief Task that will be run on shutdown to stop and clean transport
63    * service
64    */
65   struct GNUNET_SCHEDULER_Task *ts_shutdown_task;
66
67   /**
68    * @brief Handle to the client
69    */
70   struct GNUNET_SERVICE_Client *client;
71
72   /**
73    * @brief Handle to the client
74    */
75   struct GNUNET_MQ_Handle *c_mq;
76
77   /**
78    * @brief Process of the communicator
79    */
80   struct GNUNET_OS_Process *c_proc;
81
82   /**
83    * NAT process
84    */
85   struct GNUNET_OS_Process *nat_proc;
86
87   /**
88    * @brief Task that will be run on shutdown to stop and clean communicator
89    */
90   struct GNUNET_SCHEDULER_Task *c_shutdown_task;
91
92   /**
93    * @brief Characteristics of the communicator
94    */
95   enum GNUNET_TRANSPORT_CommunicatorCharacteristics c_characteristics;
96
97   /**
98    * @brief Specifies supported addresses
99    */
100   char *c_addr_prefix;
101
102   /**
103    * @brief Specifies supported addresses
104    */
105   char *c_address;
106
107   /**
108    * @brief Head of the DLL of queues associated with this communicator
109    */
110   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_head;
111
112   /**
113    * @brief Tail of the DLL of queues associated with this communicator
114    */
115   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_tail;
116
117   /* Callbacks + Closures */
118   /**
119    * @brief Callback called when a new communicator connects
120    */
121   GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
122     communicator_available_cb;
123
124   /**
125    * @brief Callback called when a new communicator connects
126    */
127   GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb;
128
129   /**
130    * @brief Callback called when a new communicator connects
131    */
132   GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb;
133
134   /**
135    * @brief Callback called when a new communicator connects
136    */
137   GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb;
138
139   /**
140    * @brief Callback called when a new communicator connects
141    */
142   GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_msg_cb;
143
144   /**
145    * Our service handle
146    */
147   struct GNUNET_SERVICE_Handle *sh;
148
149   /**
150    * @brief Closure to the callback
151    */
152   void *cb_cls;
153 };
154
155
156 /**
157  * @brief Queue of a communicator and some context
158  */
159 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
160 {
161   /**
162    * @brief Handle to the TransportCommunicator
163    */
164   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
165
166   /**
167    * @brief Envelope to a message that requests the opening of the queue.
168    *
169    * If the client already requests queue(s), but the communicator is not yet
170    * connected, we cannot send the request to open the queue. Save it until the
171    * communicator becomes available and send it then.
172    */
173   struct GNUNET_MQ_Envelope *open_queue_env;
174
175   /**
176    * @brief Peer ID of the peer on the other side of the queue
177    */
178   struct GNUNET_PeerIdentity peer_id;
179
180   /**
181    * @brief Queue ID
182    */
183   uint32_t qid;
184
185   /**
186    * @brief Current message id
187    */
188   uint64_t mid;
189
190   /**
191    * An `enum GNUNET_NetworkType` in NBO.
192    */
193   uint32_t nt;
194
195   /**
196    * Maximum transmission unit, in NBO.  UINT32_MAX for unlimited.
197    */
198   uint32_t mtu;
199
200   /**
201    * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
202    */
203   uint32_t cs;
204
205   /**
206    * @brief Next element inside a DLL
207    */
208   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next;
209
210   /**
211    * @brief Previous element inside a DLL
212    */
213   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev;
214 };
215
216
217 /**
218  * @brief Handle/Context to a single transmission
219  */
220 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission
221 {
222 };
223
224
225 /**
226  * @brief Check whether incoming msg indicating available communicator is
227  * correct
228  *
229  * @param cls Closure
230  * @param msg Message struct
231  *
232  * @return GNUNET_YES in case message is correct
233  */
234 static int
235 check_communicator_available (
236   void *cls,
237   const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
238 {
239   uint16_t size;
240
241   size = ntohs (msg->header.size) - sizeof(*msg);
242   if (0 == size)
243     return GNUNET_OK; /* receive-only communicator */
244   GNUNET_MQ_check_zero_termination (msg);
245   return GNUNET_OK;
246 }
247
248
249 /**
250  * @brief Handle new communicator
251  *
252  * Store characteristics of communicator, call respective client callback.
253  *
254  * @param cls Closure - communicator handle
255  * @param msg Message struct
256  */
257 static void
258 handle_communicator_available (
259   void *cls,
260   const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
261 {
262   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
263   uint16_t size;
264
265   size = ntohs (msg->header.size) - sizeof(*msg);
266   if (0 == size)
267     return; /* receive-only communicator */
268   tc_h->c_characteristics = ntohl (msg->cc);
269   tc_h->c_addr_prefix = GNUNET_strdup ((const char *) &msg[1]);
270   if (NULL != tc_h->communicator_available_cb)
271   {
272     LOG (GNUNET_ERROR_TYPE_DEBUG, "calling communicator_available_cb()\n");
273     tc_h->communicator_available_cb (tc_h->cb_cls,
274                                      tc_h,
275                                      tc_h->c_characteristics,
276                                      tc_h->c_addr_prefix);
277   }
278   GNUNET_SERVICE_client_continue (tc_h->client);
279 }
280
281
282 /**
283  * Address of our peer added.  Test message is well-formed.
284  *
285  * @param cls the client
286  * @param aam the send message that was sent
287  * @return #GNUNET_OK if message is well-formed
288  */
289 static int
290 check_add_address (void *cls,
291                    const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
292 {
293   // if (CT_COMMUNICATOR != tc->type)
294   // {
295   //  GNUNET_break (0);
296   //  return GNUNET_SYSERR;
297   // }
298   GNUNET_MQ_check_zero_termination (msg);
299   return GNUNET_OK;
300 }
301
302
303 /**
304  * @brief The communicator informs about an address.
305  *
306  * Store address and call client callback.
307  *
308  * @param cls Closure - communicator handle
309  * @param msg Message
310  */
311 static void
312 handle_add_address (void *cls,
313                     const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
314 {
315   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
316   uint16_t size;
317   size = ntohs (msg->header.size) - sizeof(*msg);
318   if (0 == size)
319     return; /* receive-only communicator */
320   LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size);
321   tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]);
322   if (NULL != tc_h->add_address_cb)
323   {
324     LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n");
325     tc_h->add_address_cb (tc_h->cb_cls,
326                           tc_h,
327                           tc_h->c_address,
328                           GNUNET_TIME_relative_ntoh (msg->expiration),
329                           msg->aid,
330                           ntohl (msg->nt));
331   }
332   GNUNET_SERVICE_client_continue (tc_h->client);
333 }
334
335
336 /**
337  * Incoming message.  Test message is well-formed.
338  *
339  * @param cls the client
340  * @param msg the send message that was sent
341  * @return #GNUNET_OK if message is well-formed
342  */
343 static int
344 check_incoming_msg (void *cls,
345                     const struct GNUNET_TRANSPORT_IncomingMessage *msg)
346 {
347   // struct TransportClient *tc = cls;
348
349   // if (CT_COMMUNICATOR != tc->type)
350   // {
351   //  GNUNET_break (0);
352   //  return GNUNET_SYSERR;
353   // }
354   GNUNET_MQ_check_boxed_message (msg);
355   return GNUNET_OK;
356 }
357
358
359 /**
360  * @brief Receive an incoming message.
361  *
362  * Pass the message to the client.
363  *
364  * @param cls Closure - communicator handle
365  * @param msg Message
366  */
367 static void
368 handle_incoming_msg (void *cls,
369                      const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg)
370 {
371   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
372   struct GNUNET_MessageHeader *msg;
373   msg = (struct GNUNET_MessageHeader *) &inc_msg[1];
374   size_t payload_len = ntohs (msg->size) - sizeof (struct
375                                                    GNUNET_MessageHeader);
376
377   if (NULL != tc_h->incoming_msg_cb)
378   {
379     tc_h->incoming_msg_cb (tc_h->cb_cls,
380                            tc_h,
381                            (char*) &msg[1],
382                            payload_len);
383   }
384   else
385   {
386     LOG (GNUNET_ERROR_TYPE_WARNING,
387          "Incoming message from communicator but no handler!\n");
388   }
389   if (0 != ntohl (inc_msg->fc_on))
390   {
391     /* send ACK when done to communicator for flow control! */
392     struct GNUNET_MQ_Envelope *env;
393     struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
394
395     env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
396     ack->reserved = htonl (0);
397     ack->fc_id = inc_msg->fc_id;
398     ack->sender = inc_msg->sender;
399     GNUNET_MQ_send (tc_h->c_mq, env);
400   }
401
402   GNUNET_SERVICE_client_continue (tc_h->client);
403 }
404
405
406 /**
407  * @brief Communicator informs that it tries to establish requested queue
408  *
409  * @param cls Closure - communicator handle
410  * @param msg Message
411  */
412 static void
413 handle_queue_create_ok (void *cls,
414                         const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
415 {
416   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
417
418   if (NULL != tc_h->queue_create_reply_cb)
419   {
420     tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES);
421   }
422   GNUNET_SERVICE_client_continue (tc_h->client);
423 }
424
425
426 /**
427  * @brief Communicator informs that it wont try establishing requested queue.
428  *
429  * It will not do so probably because the address is bougus (see comment to
430  * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL)
431  *
432  * @param cls Closure - communicator handle
433  * @param msg Message
434  */
435 static void
436 handle_queue_create_fail (
437   void *cls,
438   const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
439 {
440   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
441
442   if (NULL != tc_h->queue_create_reply_cb)
443   {
444     tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO);
445   }
446   GNUNET_SERVICE_client_continue (tc_h->client);
447 }
448
449
450 /**
451  * New queue became available.  Check message.
452  *
453  * @param cls the client
454  * @param aqm the send message that was sent
455  */
456 static int
457 check_add_queue_message (void *cls,
458                          const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
459 {
460   GNUNET_MQ_check_zero_termination (aqm);
461   return GNUNET_OK;
462 }
463
464
465 /**
466  * @brief Handle new queue
467  *
468  * Store context and call client callback.
469  *
470  * @param cls Closure - communicator handle
471  * @param msg Message struct
472  */
473 static void
474 handle_add_queue_message (void *cls,
475                           const struct GNUNET_TRANSPORT_AddQueueMessage *msg)
476 {
477   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
478   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
479
480   tc_queue = tc_h->queue_head;
481   if (NULL != tc_queue)
482   {
483     while (tc_queue->qid != msg->qid)
484     {
485       tc_queue = tc_queue->next;
486     }
487   }
488   else
489   {
490     tc_queue =
491       GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
492     tc_queue->tc_h = tc_h;
493     tc_queue->qid = msg->qid;
494     tc_queue->peer_id = msg->receiver;
495     GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
496   }
497   GNUNET_assert (tc_queue->qid == msg->qid);
498   GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
499   tc_queue->nt = msg->nt;
500   tc_queue->mtu = msg->mtu;
501   tc_queue->cs = msg->cs;
502   if (NULL != tc_h->add_queue_cb)
503   {
504     tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue);
505   }
506   GNUNET_SERVICE_client_continue (tc_h->client);
507 }
508
509
510 /**
511  * @brief Shut down the service
512  *
513  * @param cls Closure - Handle to the service
514  */
515 static void
516 shutdown_service (void *cls)
517 {
518   struct GNUNET_SERVICE_Handle *h = cls;
519
520   GNUNET_SERVICE_stop (h);
521 }
522
523
524 /**
525  * @brief Callback called when new Client (Communicator) connects
526  *
527  * @param cls Closure - TransporCommmunicator Handle
528  * @param client Client
529  * @param mq Messagequeue
530  *
531  * @return TransportCommunicator Handle
532  */
533 static void *
534 connect_cb (void *cls,
535             struct GNUNET_SERVICE_Client *client,
536             struct GNUNET_MQ_Handle *mq)
537 {
538   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
539
540   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected.\n");
541   tc_h->client = client;
542   tc_h->c_mq = mq;
543
544   if (NULL == tc_h->queue_head)
545     return tc_h;
546   /* Iterate over queues. They are yet to be opened. Request opening. */
547   for (struct
548        GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter =
549          tc_h->queue_head;
550        NULL != tc_queue_iter;
551        tc_queue_iter = tc_queue_iter->next)
552   {
553     if (NULL == tc_queue_iter->open_queue_env)
554       continue;
555     /* Send the previously created mq envelope to request the creation of the
556      * queue. */
557     GNUNET_MQ_send (tc_h->c_mq,
558                     tc_queue_iter->open_queue_env);
559     tc_queue_iter->open_queue_env = NULL;
560   }
561   return tc_h;
562 }
563
564
565 /**
566  * @brief Callback called when Client disconnects
567  *
568  * @param cls Closure - TransportCommunicator Handle
569  * @param client Client
570  * @param internal_cls TransporCommmunicator Handle
571  */
572 static void
573 disconnect_cb (void *cls,
574                struct GNUNET_SERVICE_Client *client,
575                void *internal_cls)
576 {
577   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
578
579   LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n");
580   tc_h->client = NULL;
581 }
582
583
584 /**
585  * Message was transmitted.  Process the request.
586  *
587  * @param cls the client
588  * @param sma the send message that was sent
589  */
590 static void
591 handle_send_message_ack (void *cls,
592                          const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
593 {
594   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
595   GNUNET_SERVICE_client_continue (tc_h->client);
596   // NOP
597 }
598
599
600 /**
601  * @brief Start the communicator part of the transport service
602  *
603  * @param communicator_available Callback to be called when a new communicator
604  * becomes available
605  * @param cfg Configuration
606  */
607 static void
608 transport_communicator_start (
609   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
610 {
611   struct GNUNET_MQ_MessageHandler mh[] = {
612     GNUNET_MQ_hd_var_size (communicator_available,
613                            GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
614                            struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
615                            tc_h),
616     // GNUNET_MQ_hd_var_size (communicator_backchannel,
617     //    GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
618     //    struct GNUNET_TRANSPORT_CommunicatorBackchannel,
619     //    NULL),
620     GNUNET_MQ_hd_var_size (add_address,
621                            GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
622                            struct GNUNET_TRANSPORT_AddAddressMessage,
623                            tc_h),
624     // GNUNET_MQ_hd_fixed_size (del_address,
625     //                         GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
626     //                         struct GNUNET_TRANSPORT_DelAddressMessage,
627     //                         NULL),
628     GNUNET_MQ_hd_var_size (incoming_msg,
629                            GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
630                            struct GNUNET_TRANSPORT_IncomingMessage,
631                            tc_h),
632     GNUNET_MQ_hd_fixed_size (queue_create_ok,
633                              GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
634                              struct GNUNET_TRANSPORT_CreateQueueResponse,
635                              tc_h),
636     GNUNET_MQ_hd_fixed_size (queue_create_fail,
637                              GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
638                              struct GNUNET_TRANSPORT_CreateQueueResponse,
639                              tc_h),
640     GNUNET_MQ_hd_var_size (add_queue_message,
641                            GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
642                            struct GNUNET_TRANSPORT_AddQueueMessage,
643                            tc_h),
644     // GNUNET_MQ_hd_fixed_size (del_queue_message,
645     //                         GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
646     //                         struct GNUNET_TRANSPORT_DelQueueMessage,
647     //                         NULL),
648     GNUNET_MQ_hd_fixed_size (send_message_ack,
649                              GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
650                              struct GNUNET_TRANSPORT_SendMessageToAck,
651                              tc_h),
652     GNUNET_MQ_handler_end ()
653   };
654
655
656   tc_h->sh = GNUNET_SERVICE_start ("transport",
657                                    tc_h->cfg,
658                                    &connect_cb,
659                                    &disconnect_cb,
660                                    tc_h,
661                                    mh);
662   GNUNET_assert (NULL != tc_h->sh);
663 }
664
665
666 /**
667  * @brief Task run at shutdown to kill communicator and clean up
668  *
669  * @param cls Closure - Process of communicator
670  */
671 static void
672 shutdown_process (struct GNUNET_OS_Process *proc)
673 {
674   if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
675   {
676     LOG (GNUNET_ERROR_TYPE_WARNING,
677          "Error shutting down communicator with SIGERM, trying SIGKILL\n");
678     if (0 != GNUNET_OS_process_kill (proc, SIGKILL))
679     {
680       LOG (GNUNET_ERROR_TYPE_ERROR,
681            "Error shutting down communicator with SIGERM and SIGKILL\n");
682     }
683   }
684   GNUNET_OS_process_destroy (proc);
685 }
686
687
688 static void
689 shutdown_communicator (void *cls)
690 {
691   struct GNUNET_OS_Process *proc = cls;
692   shutdown_process (proc);
693 }
694
695
696 /**
697  * @brief Start the communicator
698  *
699  * @param cfgname Name of the communicator
700  */
701 static void
702 communicator_start (
703   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
704   const char *binary_name)
705 {
706   char *binary;
707
708   LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n");
709   binary = GNUNET_OS_get_libexec_binary_path (binary_name);
710   tc_h->c_proc = GNUNET_OS_start_process (GNUNET_YES,
711                                           GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
712                                           NULL,
713                                           NULL,
714                                           NULL,
715                                           binary,
716                                           binary_name,
717                                           "-c",
718                                           tc_h->cfg_filename,
719                                           NULL);
720   if (NULL == tc_h->c_proc)
721   {
722     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!");
723     return;
724   }
725   LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n");
726   GNUNET_free (binary);
727 }
728
729
730 /**
731  * @brief Task run at shutdown to kill communicator and clean up
732  *
733  * @param cls Closure - Process of communicator
734  */
735 static void
736 shutdown_nat (void *cls)
737 {
738   struct GNUNET_OS_Process *proc = cls;
739   shutdown_process (proc);
740 }
741
742
743 /**
744  * @brief Start NAT
745  *
746  */
747 static void
748 nat_start (
749   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
750 {
751   char *binary;
752
753   LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n");
754   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat");
755   tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_YES,
756                                             GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
757                                             NULL,
758                                             NULL,
759                                             NULL,
760                                             binary,
761                                             "gnunet-service-nat",
762                                             "-c",
763                                             tc_h->cfg_filename,
764                                             NULL);
765   if (NULL == tc_h->nat_proc)
766   {
767     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!");
768     return;
769   }
770   LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n");
771   GNUNET_free (binary);
772 }
773
774
775 static void
776 do_shutdown (void *cls)
777 {
778   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
779   shutdown_communicator (tc_h->c_proc);
780   shutdown_service (tc_h->sh);
781   shutdown_nat (tc_h->nat_proc);
782 }
783
784
785 /**
786  * @brief Start communicator part of transport service and communicator
787  *
788  * @param service_name Name of the service
789  * @param cfg Configuration handle
790  * @param communicator_available_cb Callback that is called when a new
791  * @param add_address_cb Callback that is called when a new
792  * communicator becomes available
793  * @param cb_cls Closure to @a communicator_available_cb and @a
794  *
795  * @return Handle to the communicator duo
796  */
797 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
798 GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
799   const char *service_name,
800   const char *binary_name,
801   const char *cfg_filename,
802   GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
803   communicator_available_cb,
804   GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
805   GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
806   GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
807   GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
808   void *cb_cls)
809 {
810   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
811
812   tc_h =
813     GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle);
814   tc_h->cfg_filename = GNUNET_strdup (cfg_filename);
815   tc_h->cfg = GNUNET_CONFIGURATION_create ();
816   if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename)))
817   {
818     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
819                 _ ("Malformed configuration file `%s', exit ...\n"),
820                 cfg_filename);
821     GNUNET_free (tc_h->cfg_filename);
822     GNUNET_CONFIGURATION_destroy (tc_h->cfg);
823     GNUNET_free (tc_h);
824     return NULL;
825   }
826   tc_h->communicator_available_cb = communicator_available_cb;
827   tc_h->add_address_cb = add_address_cb;
828   tc_h->queue_create_reply_cb = queue_create_reply_cb;
829   tc_h->add_queue_cb = add_queue_cb;
830   tc_h->incoming_msg_cb = incoming_message_cb;
831   tc_h->cb_cls = cb_cls;
832
833   /* Start communicator part of service */
834   transport_communicator_start (tc_h);
835   /* Start NAT */
836   nat_start (tc_h);
837   /* Schedule start communicator */
838   communicator_start (tc_h,
839                       binary_name);
840   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, tc_h);
841   return tc_h;
842 }
843
844
845 /**
846  * @brief Instruct communicator to open a queue
847  *
848  * @param tc_h Handle to communicator which shall open queue
849  * @param peer_id Towards which peer
850  * @param address For which address
851  */
852 void
853 GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (
854   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
855   const struct GNUNET_PeerIdentity *peer_id,
856   const char *address)
857 {
858   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
859   static uint32_t idgen;
860   char *prefix;
861   struct GNUNET_TRANSPORT_CreateQueue *msg;
862   struct GNUNET_MQ_Envelope *env;
863   size_t alen;
864
865   tc_queue =
866     GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
867   tc_queue->tc_h = tc_h;
868   prefix = GNUNET_HELLO_address_to_prefix (address);
869   if (NULL == prefix)
870   {
871     GNUNET_break (0);  /* We got an invalid address!? */
872     GNUNET_free (tc_queue);
873     return;
874   }
875   GNUNET_free (prefix);
876   alen = strlen (address) + 1;
877   env =
878     GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
879   msg->request_id = htonl (idgen++);
880   tc_queue->qid = msg->request_id;
881   msg->receiver = *peer_id;
882   tc_queue->peer_id = *peer_id;
883   memcpy (&msg[1], address, alen);
884   if (NULL != tc_h->c_mq)
885   {
886     GNUNET_MQ_send (tc_h->c_mq, env);
887   }
888   else
889   {
890     tc_queue->open_queue_env = env;
891   }
892   GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
893 }
894
895
896 /**
897  * @brief Instruct communicator to send data
898  *
899  * @param tc_queue The queue to use for sending
900  * @param payload Data to send
901  * @param payload_size Size of the payload
902  *
903  * @return Handle to the transmission
904  */
905 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission *
906 GNUNET_TRANSPORT_TESTING_transport_communicator_send
907   (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue,
908   const void *payload,
909   size_t payload_size)
910 {
911   struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission *tc_t;
912   struct GNUNET_MessageHeader *mh;
913   struct GNUNET_TRANSPORT_SendMessageTo *msg;
914   struct GNUNET_MQ_Envelope *env;
915   size_t inbox_size;
916
917   inbox_size = sizeof(struct GNUNET_MessageHeader) + payload_size;
918   mh = GNUNET_malloc (inbox_size);
919   mh->size = htons (inbox_size);
920   mh->type = GNUNET_MESSAGE_TYPE_DUMMY;
921   memcpy (&mh[1],
922           payload,
923           payload_size);
924   env = GNUNET_MQ_msg_extra (msg,
925                              inbox_size,
926                              GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
927   msg->qid = htonl (tc_queue->qid);
928   msg->mid = tc_queue->mid++;
929   msg->receiver = tc_queue->peer_id;
930   memcpy (&msg[1], mh, inbox_size);
931   GNUNET_free (mh);
932   GNUNET_MQ_send (tc_queue->tc_h->c_mq, env);
933   // GNUNET_assert (0); // FIXME: not iplemented!
934   return tc_t;
935 }