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