first batch of license fixes (boring)
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_peers.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU 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
16
17 /**
18  * @file testbed/gnunet-service-testbed_peers.c
19  * @brief implementation of TESTBED service that deals with peer management
20  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
21  */
22
23 #include "gnunet-service-testbed.h"
24 #include "gnunet_arm_service.h"
25 #include <zlib.h>
26
27
28 /**
29  * A list of peers we know about
30  */
31 struct Peer **GST_peer_list;
32
33 /**
34  * The current number of peers running locally under this controller
35  */
36 unsigned int GST_num_local_peers;
37
38
39 /**
40  * Context information to manage peers' services
41  */
42 struct ManageServiceContext
43 {
44   /**
45    * DLL next ptr
46    */
47   struct ManageServiceContext *next;
48
49   /**
50    * DLL prev ptr
51    */
52   struct ManageServiceContext *prev;
53
54   /**
55    * The ARM handle of the peer
56    */
57   struct GNUNET_ARM_Handle *ah;
58
59   /**
60    * peer whose service has to be managed
61    */
62   struct Peer *peer;
63
64   /**
65    * The client which requested to manage the peer's service
66    */
67   struct GNUNET_SERVICE_Client *client;
68
69   /**
70    * Name of the service.
71    */
72   char *service;
73
74   /**
75    * The operation id of the associated request
76    */
77   uint64_t op_id;
78
79   /**
80    * 1 if the service at the peer has to be started; 0 if it has to be stopped
81    */
82   uint8_t start;
83
84   /**
85    * Is this context expired?  Do not work on this context if it is set to
86    * GNUNET_YES
87    */
88   uint8_t expired;
89 };
90
91
92 /**
93  * Context information for peer re-configure operations
94  */
95 struct PeerReconfigureContext
96 {
97   /**
98    * DLL next for inclusoin in peer reconfigure operations list
99    */
100   struct PeerReconfigureContext *next;
101
102   /**
103    * DLL prev
104    */
105   struct PeerReconfigureContext *prev;
106
107   /**
108    * The client which gave this operation to us
109    */
110   struct GNUNET_SERVICE_Client *client;
111
112   /**
113    * The configuration handle to use as the new template
114    */
115   struct GNUNET_CONFIGURATION_Handle *cfg;
116
117   /**
118    * The id of the operation
119    */
120   uint64_t op_id;
121
122   /**
123    * The id of the peer which has to be reconfigured
124    */
125   uint32_t peer_id;
126
127   /**
128    * The the peer stopped?  Used while cleaning up this context to decide
129    * whether the asynchronous stop request through Testing/ARM API has to be
130    * cancelled
131    */
132   uint8_t stopped;
133 };
134
135 /**
136  * The DLL head for the peer reconfigure list
137  */
138 static struct PeerReconfigureContext *prc_head;
139
140 /**
141  * The DLL tail for the peer reconfigure list
142  */
143 static struct PeerReconfigureContext *prc_tail;
144
145
146
147 /**
148  * DLL head for queue of manage service requests
149  */
150 static struct ManageServiceContext *mctx_head;
151
152 /**
153  * DLL tail for queue of manage service requests
154  */
155 static struct ManageServiceContext *mctx_tail;
156
157
158 /**
159  * Adds a peer to the peer array
160  *
161  * @param peer the peer to add
162  */
163 static void
164 peer_list_add (struct Peer *peer)
165 {
166   if (peer->id >= GST_peer_list_size)
167     GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
168   GNUNET_assert (NULL == GST_peer_list[peer->id]);
169   GST_peer_list[peer->id] = peer;
170   if (GNUNET_NO == peer->is_remote)
171     GST_num_local_peers++;
172 }
173
174
175 /**
176  * Removes a the give peer from the peer array
177  *
178  * @param peer the peer to be removed
179  */
180 static void
181 peer_list_remove (struct Peer *peer)
182 {
183   unsigned int orig_size;
184   uint32_t id;
185
186   if (GNUNET_NO == peer->is_remote)
187     GST_num_local_peers--;
188   GST_peer_list[peer->id] = NULL;
189   orig_size = GST_peer_list_size;
190   while (GST_peer_list_size >= LIST_GROW_STEP)
191   {
192     for (id = GST_peer_list_size - 1;
193          (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
194          id--)
195       if (NULL != GST_peer_list[id])
196         break;
197     if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
198       break;
199     GST_peer_list_size -= LIST_GROW_STEP;
200   }
201   if (orig_size == GST_peer_list_size)
202     return;
203   GST_peer_list =
204       GNUNET_realloc (GST_peer_list,
205                       sizeof (struct Peer *) * GST_peer_list_size);
206 }
207
208
209 /**
210  * The task to be executed if the forwarded peer create operation has been
211  * timed out
212  *
213  * @param cls the FowardedOperationContext
214  */
215 static void
216 peer_create_forward_timeout (void *cls)
217 {
218   struct ForwardedOperationContext *fopc = cls;
219
220   GNUNET_free (fopc->cls);
221   GST_forwarded_operation_timeout (fopc);
222 }
223
224
225 /**
226  * Callback to be called when forwarded peer create operation is successfull. We
227  * have to relay the reply msg back to the client
228  *
229  * @param cls ForwardedOperationContext
230  * @param msg the peer create success message
231  */
232 static void
233 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
234 {
235   struct ForwardedOperationContext *fopc = cls;
236   struct Peer *remote_peer;
237
238   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
239   {
240     GNUNET_assert (NULL != fopc->cls);
241     remote_peer = fopc->cls;
242     peer_list_add (remote_peer);
243   }
244   GST_forwarded_operation_reply_relay (fopc,
245                                        msg);
246 }
247
248
249 /**
250  * Function to destroy a peer
251  *
252  * @param peer the peer structure to destroy
253  */
254 void
255 GST_destroy_peer (struct Peer *peer)
256 {
257   GNUNET_break (0 == peer->reference_cnt);
258   if (GNUNET_YES == peer->is_remote)
259   {
260     peer_list_remove (peer);
261     GNUNET_free (peer);
262     return;
263   }
264   if (GNUNET_YES == peer->details.local.is_running)
265   {
266     GNUNET_TESTING_peer_stop (peer->details.local.peer);
267     peer->details.local.is_running = GNUNET_NO;
268   }
269   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
270   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
271   peer_list_remove (peer);
272   GNUNET_free (peer);
273 }
274
275
276 /**
277  * Cleanup the context information created for managing a peer's service
278  *
279  * @param mctx the ManageServiceContext
280  */
281 static void
282 cleanup_mctx (struct ManageServiceContext *mctx)
283 {
284   mctx->expired = GNUNET_YES;
285   GNUNET_CONTAINER_DLL_remove (mctx_head,
286                                mctx_tail,
287                                mctx);
288   GNUNET_ARM_disconnect (mctx->ah);
289   GNUNET_assert (0 < mctx->peer->reference_cnt);
290   mctx->peer->reference_cnt--;
291   if ( (GNUNET_YES == mctx->peer->destroy_flag) &&
292        (0 == mctx->peer->reference_cnt) )
293     GST_destroy_peer (mctx->peer);
294   GNUNET_free (mctx->service);
295   GNUNET_free (mctx);
296 }
297
298
299 /**
300  * Stops a peer
301  *
302  * @param peer the peer to stop
303  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
304  */
305 static int
306 stop_peer (struct Peer *peer)
307 {
308   GNUNET_assert (GNUNET_NO == peer->is_remote);
309   if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
310     return GNUNET_SYSERR;
311   peer->details.local.is_running = GNUNET_NO;
312   return GNUNET_OK;
313 }
314
315
316 /**
317  * Cleans up the given PeerReconfigureContext
318  *
319  * @param prc the PeerReconfigureContext
320  */
321 static void
322 cleanup_prc (struct PeerReconfigureContext *prc)
323 {
324   struct Peer *peer;
325
326   if (VALID_PEER_ID (prc->peer_id))
327   {
328     peer = GST_peer_list [prc->peer_id];
329     if (1 != prc->stopped)
330     {
331       GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
332       stop_peer (peer);         /* Stop the peer synchronously */
333     }
334   }
335   if (NULL != prc->cfg)
336     GNUNET_CONFIGURATION_destroy (prc->cfg);
337   GNUNET_CONTAINER_DLL_remove (prc_head,
338                                prc_tail,
339                                prc);
340   GNUNET_free (prc);
341 }
342
343
344 /**
345  * Notify peers subsystem that @a client disconnected.
346  *
347  * @param client the client that disconnected
348  */
349 void
350 GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
351 {
352   struct ForwardedOperationContext *fopc;
353   struct ForwardedOperationContext *fopcn;
354   struct ManageServiceContext *mctx;
355   struct ManageServiceContext *mctxn;
356   struct PeerReconfigureContext *prc;
357   struct PeerReconfigureContext *prcn;
358
359   for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
360   {
361     fopcn = fopc->next;
362     if (client == fopc->client)
363     {
364       if (OP_PEER_CREATE == fopc->type)
365         GNUNET_free (fopc->cls);
366       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
367       GST_forwarded_operation_timeout (fopc);
368     }
369   }
370   for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
371   {
372     mctxn = mctx->next;
373     if (client == mctx->client)
374       cleanup_mctx (mctx);
375   }
376   for (prc = prc_head; NULL != prc; prc = prcn)
377   {
378     prcn = prc->next;
379     if (client == prc->client)
380       cleanup_prc (prc);
381   }
382 }
383
384
385 /**
386  * Callback to be called when forwarded peer destroy operation is successfull. We
387  * have to relay the reply msg back to the client
388  *
389  * @param cls ForwardedOperationContext
390  * @param msg the peer create success message
391  */
392 static void
393 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
394 {
395   struct ForwardedOperationContext *fopc = cls;
396   struct Peer *remote_peer;
397
398   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
399       ntohs (msg->type))
400   {
401     remote_peer = fopc->cls;
402     GNUNET_assert (NULL != remote_peer);
403     remote_peer->destroy_flag = GNUNET_YES;
404     if (0 == remote_peer->reference_cnt)
405       GST_destroy_peer (remote_peer);
406   }
407   GST_forwarded_operation_reply_relay (fopc,
408                                        msg);
409 }
410
411
412 /**
413  * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
414  *
415  * @param cls identification of the client
416  * @param msg the actual message
417  * @return #GNUNET_OK if @a msg is well-formed
418  */
419 int
420 check_peer_create (void *cls,
421                    const struct GNUNET_TESTBED_PeerCreateMessage *msg)
422 {
423   return GNUNET_OK; /* checked later */
424 }
425
426
427 /**
428  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
429  *
430  * @param cls identification of the client
431  * @param msg the actual message
432  */
433 void
434 handle_peer_create (void *cls,
435                     const struct GNUNET_TESTBED_PeerCreateMessage *msg)
436 {
437   struct GNUNET_SERVICE_Client *client = cls;
438   struct GNUNET_MQ_Envelope *env;
439   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
440   struct GNUNET_CONFIGURATION_Handle *cfg;
441   struct ForwardedOperationContext *fo_ctxt;
442   struct Route *route;
443   struct Peer *peer;
444   char *emsg;
445   uint32_t host_id;
446   uint32_t peer_id;
447
448   host_id = ntohl (msg->host_id);
449   peer_id = ntohl (msg->peer_id);
450   if (VALID_PEER_ID (peer_id))
451   {
452     (void) GNUNET_asprintf (&emsg,
453                             "Peer with ID %u already exists",
454                             peer_id);
455     GST_send_operation_fail_msg (client,
456                                  GNUNET_ntohll (msg->operation_id),
457                                  emsg);
458     GNUNET_free (emsg);
459     GNUNET_SERVICE_client_continue (client);
460     return;
461   }
462   if (UINT32_MAX == peer_id)
463   {
464     GST_send_operation_fail_msg (client,
465                                  GNUNET_ntohll (msg->operation_id),
466                                  "Cannot create peer with given ID");
467     GNUNET_SERVICE_client_continue (client);
468     return;
469   }
470   if (host_id == GST_context->host_id)
471   {
472     /* We are responsible for this peer */
473     cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
474     if (NULL == cfg)
475     {
476       GNUNET_break (0);
477       GNUNET_SERVICE_client_drop (client);
478       return;
479     }
480     GNUNET_CONFIGURATION_set_value_number (cfg,
481                                            "TESTBED",
482                                            "PEERID",
483                                            (unsigned long long) peer_id);
484
485     GNUNET_CONFIGURATION_set_value_number (cfg,
486                                            "PATHS",
487                                            "PEERID",
488                                            (unsigned long long) peer_id);
489     peer = GNUNET_new (struct Peer);
490     peer->is_remote = GNUNET_NO;
491     peer->details.local.cfg = cfg;
492     peer->id = peer_id;
493     LOG_DEBUG ("Creating peer with id: %u\n",
494                (unsigned int) peer->id);
495     peer->details.local.peer =
496         GNUNET_TESTING_peer_configure (GST_context->system,
497                                        peer->details.local.cfg, peer->id,
498                                        NULL /* Peer id */ ,
499                                        &emsg);
500     if (NULL == peer->details.local.peer)
501     {
502       LOG (GNUNET_ERROR_TYPE_WARNING,
503            "Configuring peer failed: %s\n",
504            emsg);
505       GNUNET_free (emsg);
506       GNUNET_free (peer);
507       GNUNET_break (0);
508       GNUNET_SERVICE_client_drop (client);
509       return;
510     }
511     peer->details.local.is_running = GNUNET_NO;
512     peer_list_add (peer);
513     env = GNUNET_MQ_msg (reply,
514                          GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
515     reply->peer_id = msg->peer_id;
516     reply->operation_id = msg->operation_id;
517     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
518                     env);
519     GNUNET_SERVICE_client_continue (client);
520     return;
521   }
522
523   /* Forward peer create request */
524   route = GST_find_dest_route (host_id);
525   if (NULL == route)
526   {
527     GNUNET_break (0);
528     GNUNET_SERVICE_client_continue (client); // ?
529     return;
530   }
531   peer = GNUNET_new (struct Peer);
532   peer->is_remote = GNUNET_YES;
533   peer->id = peer_id;
534   peer->details.remote.slave = GST_slave_list[route->dest];
535   peer->details.remote.remote_host_id = host_id;
536   fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
537   fo_ctxt->client = client;
538   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
539   fo_ctxt->cls = peer;
540   fo_ctxt->type = OP_PEER_CREATE;
541   fo_ctxt->opc =
542       GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
543                                              [route->dest]->controller,
544                                              fo_ctxt->operation_id,
545                                              &msg->header,
546                                              &peer_create_success_cb,
547                                              fo_ctxt);
548   fo_ctxt->timeout_task =
549       GNUNET_SCHEDULER_add_delayed (GST_timeout,
550                                     &peer_create_forward_timeout,
551                                     fo_ctxt);
552   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
553                                     fopcq_tail,
554                                     fo_ctxt);
555   GNUNET_SERVICE_client_continue (client);
556 }
557
558
559 /**
560  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
561  *
562  * @param cls identification of the client
563  * @param msg the actual message
564  */
565 void
566 handle_peer_destroy (void *cls,
567                      const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
568 {
569   struct GNUNET_SERVICE_Client *client = cls;
570   struct ForwardedOperationContext *fopc;
571   struct Peer *peer;
572   uint32_t peer_id;
573
574   peer_id = ntohl (msg->peer_id);
575   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %llu\n",
576              (unsigned int) peer_id,
577              (unsigned long long) GNUNET_ntohll (msg->operation_id));
578   if (!VALID_PEER_ID (peer_id))
579   {
580     LOG (GNUNET_ERROR_TYPE_ERROR,
581          "Asked to destroy a non existent peer with id: %u\n", peer_id);
582     GST_send_operation_fail_msg (client,
583                                  GNUNET_ntohll (msg->operation_id),
584                                  "Peer doesn't exist");
585     GNUNET_SERVICE_client_continue (client);
586     return;
587   }
588   peer = GST_peer_list[peer_id];
589   if (GNUNET_YES == peer->is_remote)
590   {
591     /* Forward the destory message to sub controller */
592     fopc = GNUNET_new (struct ForwardedOperationContext);
593     fopc->client = client;
594     fopc->cls = peer;
595     fopc->type = OP_PEER_DESTROY;
596     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
597     fopc->opc =
598         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
599                                                slave->controller,
600                                                fopc->operation_id,
601                                                &msg->header,
602                                                &peer_destroy_success_cb,
603                                                fopc);
604     fopc->timeout_task =
605         GNUNET_SCHEDULER_add_delayed (GST_timeout,
606                                       &GST_forwarded_operation_timeout,
607                                       fopc);
608     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
609                                       fopcq_tail,
610                                       fopc);
611     GNUNET_SERVICE_client_continue (client);
612     return;
613   }
614   peer->destroy_flag = GNUNET_YES;
615   if (0 == peer->reference_cnt)
616     GST_destroy_peer (peer);
617   else
618     LOG (GNUNET_ERROR_TYPE_DEBUG,
619          "Delaying peer destroy as peer is currently in use\n");
620   GST_send_operation_success_msg (client,
621                                   GNUNET_ntohll (msg->operation_id));
622   GNUNET_SERVICE_client_continue (client);
623 }
624
625
626 /**
627  * Stats a peer
628  *
629  * @param peer the peer to start
630  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
631  */
632 static int
633 start_peer (struct Peer *peer)
634 {
635   GNUNET_assert (GNUNET_NO == peer->is_remote);
636   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
637     return GNUNET_SYSERR;
638   peer->details.local.is_running = GNUNET_YES;
639   return GNUNET_OK;
640 }
641
642
643 /**
644  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
645  *
646  * @param cls identification of the client
647  * @param msg the actual message
648  */
649 void
650 handle_peer_start (void *cls,
651                    const struct GNUNET_TESTBED_PeerStartMessage *msg)
652 {
653   struct GNUNET_SERVICE_Client *client = cls;
654   struct GNUNET_MQ_Envelope *env;
655   struct GNUNET_TESTBED_PeerEventMessage *reply;
656   struct ForwardedOperationContext *fopc;
657   struct Peer *peer;
658   uint32_t peer_id;
659
660   peer_id = ntohl (msg->peer_id);
661   if (! VALID_PEER_ID (peer_id))
662   {
663     GNUNET_break (0);
664     LOG (GNUNET_ERROR_TYPE_ERROR,
665          "Asked to start a non existent peer with id: %u\n",
666          peer_id);
667     GNUNET_SERVICE_client_continue (client);
668     return;
669   }
670   peer = GST_peer_list[peer_id];
671   if (GNUNET_YES == peer->is_remote)
672   {
673     fopc = GNUNET_new (struct ForwardedOperationContext);
674     fopc->client = client;
675     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
676     fopc->type = OP_PEER_START;
677     fopc->opc =
678         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
679                                                slave->controller,
680                                                fopc->operation_id, &msg->header,
681                                                &GST_forwarded_operation_reply_relay,
682                                                fopc);
683     fopc->timeout_task =
684         GNUNET_SCHEDULER_add_delayed (GST_timeout,
685                                       &GST_forwarded_operation_timeout,
686                                       fopc);
687     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
688                                       fopcq_tail,
689                                       fopc);
690     GNUNET_SERVICE_client_continue (client);
691     return;
692   }
693   if (GNUNET_OK != start_peer (peer))
694   {
695     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
696                                  "Failed to start");
697     GNUNET_SERVICE_client_continue (client);
698     return;
699   }
700   env = GNUNET_MQ_msg (reply,
701                        GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
702   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
703   reply->host_id = htonl (GST_context->host_id);
704   reply->peer_id = msg->peer_id;
705   reply->operation_id = msg->operation_id;
706   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
707                   env);
708   GNUNET_SERVICE_client_continue (client);
709 }
710
711
712 /**
713  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
714  *
715  * @param cls identification of the client
716  * @param msg the actual message
717  */
718 void
719 handle_peer_stop (void *cls,
720                   const struct GNUNET_TESTBED_PeerStopMessage *msg)
721 {
722   struct GNUNET_SERVICE_Client *client = cls;
723   struct GNUNET_MQ_Envelope *env;
724   struct GNUNET_TESTBED_PeerEventMessage *reply;
725   struct ForwardedOperationContext *fopc;
726   struct Peer *peer;
727   uint32_t peer_id;
728
729   peer_id = ntohl (msg->peer_id);
730   LOG (GNUNET_ERROR_TYPE_DEBUG,
731        "Received PEER_STOP for peer %u\n",
732        (unsigned int) peer_id);
733   if (! VALID_PEER_ID (peer_id))
734   {
735     GST_send_operation_fail_msg (client,
736                                  GNUNET_ntohll (msg->operation_id),
737                                  "Peer not found");
738     GNUNET_SERVICE_client_continue (client);
739     return;
740   }
741   peer = GST_peer_list[peer_id];
742   if (GNUNET_YES == peer->is_remote)
743   {
744     LOG (GNUNET_ERROR_TYPE_DEBUG,
745          "Forwarding PEER_STOP for peer %u\n",
746          (unsigned int) peer_id);
747     fopc = GNUNET_new (struct ForwardedOperationContext);
748     fopc->client = client;
749     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
750     fopc->type = OP_PEER_STOP;
751     fopc->opc =
752         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
753                                                slave->controller,
754                                                fopc->operation_id,
755                                                &msg->header,
756                                                &GST_forwarded_operation_reply_relay,
757                                                fopc);
758     fopc->timeout_task =
759         GNUNET_SCHEDULER_add_delayed (GST_timeout,
760                                       &GST_forwarded_operation_timeout,
761                                       fopc);
762     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
763                                       fopcq_tail,
764                                       fopc);
765     GNUNET_SERVICE_client_continue (client);
766     return;
767   }
768   if (GNUNET_OK != stop_peer (peer))
769   {
770     LOG (GNUNET_ERROR_TYPE_WARNING,
771          "Stopping peer %u failed\n",
772          (unsigned int) peer_id);
773     GST_send_operation_fail_msg (client,
774                                  GNUNET_ntohll (msg->operation_id),
775                                  "Peer not running");
776     GNUNET_SERVICE_client_continue (client);
777     return;
778   }
779   LOG (GNUNET_ERROR_TYPE_DEBUG,
780        "Peer %u successfully stopped\n",
781        (unsigned int) peer_id);
782   env = GNUNET_MQ_msg (reply,
783                        GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
784   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
785   reply->host_id = htonl (GST_context->host_id);
786   reply->peer_id = msg->peer_id;
787   reply->operation_id = msg->operation_id;
788   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
789                   env);
790   GNUNET_SERVICE_client_continue (client);
791   GNUNET_TESTING_peer_wait (peer->details.local.peer);
792 }
793
794
795 /**
796  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
797  *
798  * @param cls identification of the client
799  * @param msg the actual message
800  */
801 void
802 handle_peer_get_config (void *cls,
803                         const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
804 {
805   struct GNUNET_SERVICE_Client *client = cls;
806   struct GNUNET_MQ_Envelope *env;
807   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
808   struct ForwardedOperationContext *fopc;
809   struct Peer *peer;
810   char *config;
811   char *xconfig;
812   size_t c_size;
813   size_t xc_size;
814   uint32_t peer_id;
815
816   peer_id = ntohl (msg->peer_id);
817   LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
818              (unsigned int) peer_id);
819   if (!VALID_PEER_ID (peer_id))
820   {
821     GST_send_operation_fail_msg (client,
822                                  GNUNET_ntohll (msg->operation_id),
823                                  "Peer not found");
824     GNUNET_SERVICE_client_continue (client);
825     return;
826   }
827   peer = GST_peer_list[peer_id];
828   if (GNUNET_YES == peer->is_remote)
829   {
830     LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
831                (unsigned int) peer_id);
832     fopc = GNUNET_new (struct ForwardedOperationContext);
833     fopc->client = client;
834     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
835     fopc->type = OP_PEER_INFO;
836     fopc->opc =
837         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
838                                                slave->controller,
839                                                fopc->operation_id,
840                                                &msg->header,
841                                                &GST_forwarded_operation_reply_relay,
842                                                fopc);
843     fopc->timeout_task =
844         GNUNET_SCHEDULER_add_delayed (GST_timeout,
845                                       &GST_forwarded_operation_timeout,
846                                       fopc);
847     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
848                                       fopcq_tail,
849                                       fopc);
850     GNUNET_SERVICE_client_continue (client);
851     return;
852   }
853   LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
854              peer_id);
855   config =
856       GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
857                                       &c_size);
858   xc_size = GNUNET_TESTBED_compress_config_ (config,
859                                              c_size,
860                                              &xconfig);
861   GNUNET_free (config);
862   env = GNUNET_MQ_msg_extra (reply,
863                              xc_size,
864                              GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
865   reply->peer_id = msg->peer_id;
866   reply->operation_id = msg->operation_id;
867   GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
868                                     &reply->peer_identity);
869   reply->config_size = htons ((uint16_t) c_size);
870   GNUNET_memcpy (&reply[1],
871                  xconfig,
872                  xc_size);
873   GNUNET_free (xconfig);
874   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
875                   env);
876   GNUNET_SERVICE_client_continue (client);
877 }
878
879
880 /**
881  * Cleans up the Peer reconfigure context list
882  */
883 void
884 GST_free_prcq ()
885 {
886   while (NULL != prc_head)
887     cleanup_prc (prc_head);
888 }
889
890
891 /**
892  * Update peer configuration
893  *
894  * @param peer the peer to update
895  * @param cfg the new configuration
896  * @return error message (freshly allocated); NULL upon success
897  */
898 static char *
899 update_peer_config (struct Peer *peer,
900                     struct GNUNET_CONFIGURATION_Handle *cfg)
901 {
902   char *emsg;
903
904   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
905   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
906   peer->details.local.cfg = cfg;
907   emsg = NULL;
908   peer->details.local.peer
909       = GNUNET_TESTING_peer_configure (GST_context->system,
910                                        peer->details.local.cfg,
911                                        peer->id,
912                                        NULL /* Peer id */ ,
913                                        &emsg);
914   return emsg;
915 }
916
917
918 /**
919  * Callback to inform whether the peer is running or stopped.
920  *
921  * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
922  * @param p the respective peer whose status is being reported
923  * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
924  *          error
925  */
926 static void
927 prc_stop_cb (void *cls,
928              struct GNUNET_TESTING_Peer *p,
929              int success)
930 {
931   struct PeerReconfigureContext *prc = cls;
932   struct Peer *peer;
933   char *emsg;
934
935   GNUNET_assert (VALID_PEER_ID (prc->peer_id));
936   peer = GST_peer_list [prc->peer_id];
937   GNUNET_assert (GNUNET_NO == peer->is_remote);
938   emsg = update_peer_config (peer, prc->cfg);
939   prc->cfg = NULL;
940   prc->stopped = 1;
941   if (NULL != emsg)
942   {
943     GST_send_operation_fail_msg (prc->client,
944                                  prc->op_id,
945                                  emsg);
946     goto cleanup;
947   }
948   if (GNUNET_OK != start_peer (peer))
949   {
950     GST_send_operation_fail_msg (prc->client,
951                                  prc->op_id,
952                                  "Failed to start reconfigured peer");
953     goto cleanup;
954   }
955   GST_send_operation_success_msg (prc->client,
956                                   prc->op_id);
957
958  cleanup:
959   cleanup_prc (prc);
960   return;
961 }
962
963
964 /**
965  * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
966  *
967  * @param cls identification of the client
968  * @param msg the actual message
969  * @return #GNUNET_OK if @a msg is well-formed
970  */
971 int
972 check_peer_reconfigure (void *cls,
973                         const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
974 {
975   return GNUNET_OK; /* checked later */
976 }
977
978
979 /**
980  * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
981  * Should stop the peer asyncronously, destroy it and create it again with the
982  * new configuration.
983  *
984  * @param cls identification of the client
985  * @param msg the actual message
986  */
987 void
988 handle_peer_reconfigure (void *cls,
989                          const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
990 {
991   struct GNUNET_SERVICE_Client *client = cls;
992   struct Peer *peer;
993   struct GNUNET_CONFIGURATION_Handle *cfg;
994   struct ForwardedOperationContext *fopc;
995   struct PeerReconfigureContext *prc;
996   char *emsg;
997   uint64_t op_id;
998   uint32_t peer_id;
999
1000   peer_id = ntohl (msg->peer_id);
1001   op_id = GNUNET_ntohll (msg->operation_id);
1002   if (! VALID_PEER_ID (peer_id))
1003   {
1004     GNUNET_break (0);
1005     GST_send_operation_fail_msg (client,
1006                                  op_id,
1007                                  "Peer not found");
1008     GNUNET_SERVICE_client_continue (client);
1009     return;
1010   }
1011   peer = GST_peer_list[peer_id];
1012   if (GNUNET_YES == peer->is_remote)
1013   {
1014     LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1015     fopc = GNUNET_new (struct ForwardedOperationContext);
1016     fopc->client = client;
1017     fopc->operation_id = op_id;
1018     fopc->type = OP_PEER_RECONFIGURE;
1019     fopc->opc =
1020         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1021                                                slave->controller,
1022                                                fopc->operation_id,
1023                                                &msg->header,
1024                                                &GST_forwarded_operation_reply_relay,
1025                                                fopc);
1026     fopc->timeout_task =
1027         GNUNET_SCHEDULER_add_delayed (GST_timeout,
1028                                       &GST_forwarded_operation_timeout,
1029                                       fopc);
1030     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1031                                       fopcq_tail,
1032                                       fopc);
1033     GNUNET_SERVICE_client_continue (client);
1034     return;
1035   }
1036   LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1037              (unsigned int) peer_id);
1038   if (0 < peer->reference_cnt)
1039   {
1040     GNUNET_break (0);
1041     GST_send_operation_fail_msg (client,
1042                                  op_id,
1043                                  "Peer in use");
1044     GNUNET_SERVICE_client_continue (client);
1045     return;
1046   }
1047   if (GNUNET_YES == peer->destroy_flag)
1048   {
1049     GNUNET_break (0);
1050     GST_send_operation_fail_msg (client,
1051                                  op_id,
1052                                  "Peer is being destroyed");
1053     GNUNET_SERVICE_client_continue (client);
1054     return;
1055   }
1056   cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1057   if (NULL == cfg)
1058   {
1059     GNUNET_break (0);
1060     GST_send_operation_fail_msg (client,
1061                                  op_id,
1062                                  "Compression error");
1063     GNUNET_SERVICE_client_continue (client);
1064     return;
1065   }
1066   if (GNUNET_NO == peer->details.local.is_running)
1067   {
1068     emsg = update_peer_config (peer,
1069                                cfg);
1070     if (NULL != emsg)
1071       GST_send_operation_fail_msg (client,
1072                                    op_id,
1073                                    emsg);
1074     GST_send_operation_success_msg (client,
1075                                     op_id);
1076     GNUNET_SERVICE_client_continue (client);
1077     GNUNET_free_non_null (emsg);
1078     return;
1079   }
1080   prc = GNUNET_new (struct PeerReconfigureContext);
1081   if (GNUNET_OK !=
1082       GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1083                                       &prc_stop_cb,
1084                                       prc))
1085   {
1086     GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1087                                         "Error trying to stop peer %u asynchronously\n",
1088                                         peer_id));
1089     LOG (GNUNET_ERROR_TYPE_ERROR,
1090          "%s\n",
1091          emsg);
1092     GST_send_operation_fail_msg (client,
1093                                  op_id,
1094                                  emsg);
1095     GNUNET_SERVICE_client_continue (client);
1096     GNUNET_free (prc);
1097     GNUNET_free (emsg);
1098     return;
1099   }
1100   prc->cfg = cfg;
1101   prc->peer_id = peer_id;
1102   prc->op_id = op_id;
1103   prc->client = client;
1104   GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1105                                     prc_tail,
1106                                     prc);
1107   GNUNET_SERVICE_client_continue (client);
1108 }
1109
1110
1111 /**
1112  * Frees the ManageServiceContext queue
1113  */
1114 void
1115 GST_free_mctxq ()
1116 {
1117   while (NULL != mctx_head)
1118     cleanup_mctx (mctx_head);
1119 }
1120
1121
1122 /**
1123  * Returns a string interpretation of @a rs.
1124  *
1125  * @param rs the request status from ARM
1126  * @return a string interpretation of the request status
1127  */
1128 static const char *
1129 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1130 {
1131   switch (rs)
1132   {
1133   case GNUNET_ARM_REQUEST_SENT_OK:
1134     return _("Message was sent successfully");
1135   case GNUNET_ARM_REQUEST_DISCONNECTED:
1136     return _("We disconnected from ARM before we could send a request");
1137   }
1138   return _("Unknown request status");
1139 }
1140
1141
1142 /**
1143  * Returns a string interpretation of the @a result.
1144  *
1145  * @param result the arm result
1146  * @return a string interpretation
1147  */
1148 static const char *
1149 arm_ret_string (enum GNUNET_ARM_Result result)
1150 {
1151   switch (result)
1152   {
1153   case GNUNET_ARM_RESULT_STOPPED:
1154     return _("%s is stopped");
1155   case GNUNET_ARM_RESULT_STARTING:
1156     return _("%s is starting");
1157   case GNUNET_ARM_RESULT_STOPPING:
1158     return _("%s is stopping");
1159   case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1160     return _("%s is starting already");
1161   case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1162     return _("%s is stopping already");
1163   case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1164     return _("%s is started already");
1165   case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1166     return _("%s is stopped already");
1167   case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1168     return _("%s service is not known to ARM");
1169   case GNUNET_ARM_RESULT_START_FAILED:
1170     return _("%s service failed to start");
1171   case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1172     return _("%s service can't be started because ARM is shutting down");
1173   }
1174   return _("%.s Unknown result code.");
1175 }
1176
1177
1178 /**
1179  * Function called in response to a start/stop request.
1180  * Will be called when request was not sent successfully,
1181  * or when a reply comes. If the request was not sent successfully,
1182  * @a rs will indicate that, and @a result will be undefined.
1183  *
1184  * @param cls ManageServiceContext
1185  * @param rs status of the request
1186  * @param result result of the operation
1187  */
1188 static void
1189 service_manage_result_cb (void *cls,
1190                           enum GNUNET_ARM_RequestStatus rs,
1191                           enum GNUNET_ARM_Result result)
1192 {
1193   struct ManageServiceContext *mctx = cls;
1194   char *emsg;
1195
1196   emsg = NULL;
1197   if (GNUNET_YES == mctx->expired)
1198     return;
1199   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1200   {
1201     GNUNET_asprintf (&emsg,
1202                      "Error communicating with Peer %u's ARM: %s",
1203                      mctx->peer->id,
1204                      arm_req_string (rs));
1205     goto ret;
1206   }
1207   if (1 == mctx->start)
1208     goto service_start_check;
1209   if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1210             || (GNUNET_ARM_RESULT_STOPPING == result)
1211             || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1212             || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1213   {
1214     /* stopping a service failed */
1215     GNUNET_asprintf (&emsg,
1216                      arm_ret_string (result),
1217                      mctx->service);
1218     goto ret;
1219   }
1220   /* service stopped successfully */
1221   goto ret;
1222
1223  service_start_check:
1224   if (! ((GNUNET_ARM_RESULT_STARTING == result)
1225             || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1226             || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1227   {
1228     /* starting a service failed */
1229     GNUNET_asprintf (&emsg,
1230                      arm_ret_string (result),
1231                      mctx->service);
1232     goto ret;
1233   }
1234   /* service started successfully */
1235
1236  ret:
1237   if (NULL != emsg)
1238   {
1239     LOG_DEBUG ("%s\n", emsg);
1240     GST_send_operation_fail_msg (mctx->client,
1241                                  mctx->op_id,
1242                                  emsg);
1243   }
1244   else
1245     GST_send_operation_success_msg (mctx->client,
1246                                     mctx->op_id);
1247   GNUNET_free_non_null (emsg);
1248   cleanup_mctx (mctx);
1249 }
1250
1251
1252 /**
1253  * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1254  *
1255  * @param cls identification of client
1256  * @param msg the actual message
1257  * @return #GNUNET_OK if @a msg is well-formed
1258  */
1259 int
1260 check_manage_peer_service (void *cls,
1261                            const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1262 {
1263   uint16_t msize;
1264   const char* service;
1265
1266   msize = ntohs (msg->header.size);
1267   service = (const char *) &msg[1];
1268   if ('\0' != service[msize - sizeof
1269                       (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1270   {
1271     GNUNET_break_op (0);
1272     return GNUNET_SYSERR;
1273   }
1274   if (1 < msg->start)
1275   {
1276     GNUNET_break_op (0);
1277     return GNUNET_SYSERR;
1278   }
1279   return GNUNET_OK;
1280 }
1281
1282
1283 /**
1284  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1285  *
1286  * @param cls identification of client
1287  * @param msg the actual message
1288  */
1289 void
1290 handle_manage_peer_service (void *cls,
1291                             const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1292 {
1293   struct GNUNET_SERVICE_Client *client = cls;
1294   const char* service;
1295   struct Peer *peer;
1296   char *emsg;
1297   struct GNUNET_ARM_Handle *ah;
1298   struct ManageServiceContext *mctx;
1299   struct ForwardedOperationContext *fopc;
1300   uint64_t op_id;
1301   uint32_t peer_id;
1302
1303   service = (const char *) &msg[1];
1304   peer_id = ntohl (msg->peer_id);
1305   op_id = GNUNET_ntohll (msg->operation_id);
1306   LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1307              service, (unsigned int) peer_id);
1308   if ((GST_peer_list_size <= peer_id)
1309       || (NULL == (peer = GST_peer_list[peer_id])))
1310   {
1311     GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1312                      "with id: %u", peer_id);
1313     goto err_ret;
1314   }
1315   if (0 == strcasecmp ("arm", service))
1316   {
1317     emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service.  "
1318                           "Use peer start/stop for that");
1319     goto err_ret;
1320   }
1321   if (GNUNET_YES == peer->is_remote)
1322   {
1323     /* Forward the destory message to sub controller */
1324     fopc = GNUNET_new (struct ForwardedOperationContext);
1325     fopc->client = client;
1326     fopc->cls = peer;
1327     fopc->type = OP_MANAGE_SERVICE;
1328     fopc->operation_id = op_id;
1329     fopc->opc =
1330         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1331                                                slave->controller,
1332                                                fopc->operation_id,
1333                                                &msg->header,
1334                                                &GST_forwarded_operation_reply_relay,
1335                                                fopc);
1336     fopc->timeout_task =
1337         GNUNET_SCHEDULER_add_delayed (GST_timeout,
1338                                       &GST_forwarded_operation_timeout,
1339                                       fopc);
1340     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1341                                       fopcq_tail,
1342                                       fopc);
1343     GNUNET_SERVICE_client_continue (client);
1344     return;
1345   }
1346   if (GNUNET_NO == peer->details.local.is_running)
1347   {
1348     emsg = GNUNET_strdup ("Peer not running\n");
1349     goto err_ret;
1350   }
1351   if ((0 != peer->reference_cnt)
1352       && ( (0 == strcasecmp ("core", service))
1353            || (0 == strcasecmp ("transport", service)) )  )
1354   {
1355     GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1356                      "since it is required by existing operations",
1357                      service, peer_id);
1358     goto err_ret;
1359   }
1360   ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1361   if (NULL == ah)
1362   {
1363     GNUNET_asprintf (&emsg,
1364                      "Cannot connect to ARM service of peer with id: %u",
1365                      peer_id);
1366     goto err_ret;
1367   }
1368   mctx = GNUNET_new (struct ManageServiceContext);
1369   mctx->peer = peer;
1370   peer->reference_cnt++;
1371   mctx->op_id = op_id;
1372   mctx->ah = ah;
1373   mctx->client = client;
1374   mctx->start = msg->start;
1375   mctx->service = GNUNET_strdup (service);
1376   GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1377                                     mctx_tail,
1378                                     mctx);
1379   if (1 == mctx->start)
1380     GNUNET_ARM_request_service_start (mctx->ah,
1381                                       service,
1382                                       GNUNET_OS_INHERIT_STD_ERR,
1383                                       &service_manage_result_cb,
1384                                       mctx);
1385   else
1386     GNUNET_ARM_request_service_stop (mctx->ah, service,
1387                                      &service_manage_result_cb,
1388                                      mctx);
1389   GNUNET_SERVICE_client_continue (client);
1390   return;
1391
1392  err_ret:
1393   LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1394   GST_send_operation_fail_msg (client, op_id, emsg);
1395   GNUNET_free (emsg);
1396   GNUNET_SERVICE_client_continue (client);
1397 }
1398
1399
1400 /**
1401  * Stops and destroys all peers
1402  */
1403 void
1404 GST_destroy_peers ()
1405 {
1406   struct Peer *peer;
1407   unsigned int id;
1408
1409   if (NULL == GST_peer_list)
1410     return;
1411   for (id = 0; id < GST_peer_list_size; id++)
1412   {
1413     peer = GST_peer_list[id];
1414     if (NULL == peer)
1415       continue;
1416     /* If destroy flag is set it means that this peer should have been
1417      * destroyed by a context which we destroy before */
1418     GNUNET_break (GNUNET_NO == peer->destroy_flag);
1419     /* counter should be zero as we free all contexts before */
1420     GNUNET_break (0 == peer->reference_cnt);
1421     if ((GNUNET_NO == peer->is_remote) &&
1422         (GNUNET_YES == peer->details.local.is_running))
1423       GNUNET_TESTING_peer_kill (peer->details.local.peer);
1424   }
1425   for (id = 0; id < GST_peer_list_size; id++)
1426   {
1427     peer = GST_peer_list[id];
1428     if (NULL == peer)
1429       continue;
1430     if (GNUNET_NO == peer->is_remote)
1431     {
1432       if (GNUNET_YES == peer->details.local.is_running)
1433         GNUNET_TESTING_peer_wait (peer->details.local.peer);
1434       GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1435       GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1436     }
1437     GNUNET_free (peer);
1438   }
1439   GNUNET_free_non_null (GST_peer_list);
1440   GST_peer_list = NULL;
1441   GST_peer_list_size = 0;
1442 }
1443
1444
1445 /**
1446  * The reply msg handler forwarded SHUTDOWN_PEERS operation.  Checks if a
1447  * success reply is received from all clients and then sends the success message
1448  * to the client
1449  *
1450  * @param cls ForwardedOperationContext
1451  * @param msg the message to relay
1452  */
1453 static void
1454 shutdown_peers_reply_cb (void *cls,
1455                          const struct GNUNET_MessageHeader *msg)
1456 {
1457   struct ForwardedOperationContext *fo_ctxt = cls;
1458   struct HandlerContext_ShutdownPeers *hc;
1459
1460   hc = fo_ctxt->cls;
1461   GNUNET_assert (0 < hc->nslaves);
1462   hc->nslaves--;
1463   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1464       ntohs (msg->type))
1465     hc->timeout = GNUNET_YES;
1466   if (0 == hc->nslaves)
1467   {
1468     if (GNUNET_YES == hc->timeout)
1469       GST_send_operation_fail_msg (fo_ctxt->client,
1470                                    fo_ctxt->operation_id,
1471                                    "Timeout at a slave controller");
1472     else
1473       GST_send_operation_success_msg (fo_ctxt->client,
1474                                       fo_ctxt->operation_id);
1475     GNUNET_free (hc);
1476     hc = NULL;
1477   }
1478   GNUNET_CONTAINER_DLL_remove (fopcq_head,
1479                                fopcq_tail,
1480                                fo_ctxt);
1481   GNUNET_free (fo_ctxt);
1482 }
1483
1484
1485 /**
1486  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1487  *
1488  * @param cls identification of the client
1489  * @param msg the actual message
1490  */
1491 void
1492 handle_shutdown_peers (void *cls,
1493                        const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1494 {
1495   struct GNUNET_SERVICE_Client *client = cls;
1496   struct HandlerContext_ShutdownPeers *hc;
1497   struct Slave *slave;
1498   struct ForwardedOperationContext *fo_ctxt;
1499   uint64_t op_id;
1500   unsigned int cnt;
1501
1502   LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1503     /* Stop and destroy all peers */
1504   GST_free_mctxq ();
1505   GST_free_occq ();
1506   GST_free_roccq ();
1507   GST_clear_fopcq ();
1508   /* Forward to all slaves which we have started */
1509   op_id = GNUNET_ntohll (msg->operation_id);
1510   hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1511   /* FIXME: have a better implementation where we track which slaves are
1512      started by this controller */
1513   for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1514   {
1515     slave = GST_slave_list[cnt];
1516     if (NULL == slave)
1517       continue;
1518     if (NULL == slave->controller_proc) /* We didn't start the slave */
1519       continue;
1520     LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1521     hc->nslaves++;
1522     fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1523     fo_ctxt->client = client;
1524     fo_ctxt->operation_id = op_id;
1525     fo_ctxt->cls = hc;
1526     fo_ctxt->type = OP_SHUTDOWN_PEERS;
1527     fo_ctxt->opc =
1528         GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1529                                                fo_ctxt->operation_id,
1530                                                &msg->header,
1531                                                shutdown_peers_reply_cb,
1532                                                fo_ctxt);
1533     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1534                                       fopcq_tail,
1535                                       fo_ctxt);
1536   }
1537   LOG_DEBUG ("Shutting down peers\n");
1538   GST_destroy_peers ();
1539   if (0 == hc->nslaves)
1540   {
1541     GST_send_operation_success_msg (client,
1542                                     op_id);
1543     GNUNET_free (hc);
1544   }
1545   GNUNET_SERVICE_client_continue (client);
1546 }