uncrustify as demanded.
[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      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21
22 /**
23  * @file testbed/gnunet-service-testbed_peers.c
24  * @brief implementation of TESTBED service that deals with peer management
25  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26  */
27
28 #include "gnunet-service-testbed.h"
29 #include "gnunet_arm_service.h"
30 #include <zlib.h>
31
32
33 /**
34  * A list of peers we know about
35  */
36 struct Peer **GST_peer_list;
37
38 /**
39  * The current number of peers running locally under this controller
40  */
41 unsigned int GST_num_local_peers;
42
43
44 /**
45  * Context information to manage peers' services
46  */
47 struct ManageServiceContext {
48   /**
49    * DLL next ptr
50    */
51   struct ManageServiceContext *next;
52
53   /**
54    * DLL prev ptr
55    */
56   struct ManageServiceContext *prev;
57
58   /**
59    * The ARM handle of the peer
60    */
61   struct GNUNET_ARM_Handle *ah;
62
63   /**
64    * peer whose service has to be managed
65    */
66   struct Peer *peer;
67
68   /**
69    * The client which requested to manage the peer's service
70    */
71   struct GNUNET_SERVICE_Client *client;
72
73   /**
74    * Name of the service.
75    */
76   char *service;
77
78   /**
79    * The operation id of the associated request
80    */
81   uint64_t op_id;
82
83   /**
84    * 1 if the service at the peer has to be started; 0 if it has to be stopped
85    */
86   uint8_t start;
87
88   /**
89    * Is this context expired?  Do not work on this context if it is set to
90    * GNUNET_YES
91    */
92   uint8_t expired;
93 };
94
95
96 /**
97  * Context information for peer re-configure operations
98  */
99 struct PeerReconfigureContext {
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
1139     case GNUNET_ARM_REQUEST_DISCONNECTED:
1140       return _("We disconnected from ARM before we could send a request");
1141     }
1142   return _("Unknown request status");
1143 }
1144
1145
1146 /**
1147  * Returns a string interpretation of the @a result.
1148  *
1149  * @param result the arm result
1150  * @return a string interpretation
1151  */
1152 static const char *
1153 arm_ret_string(enum GNUNET_ARM_Result result)
1154 {
1155   switch (result)
1156     {
1157     case GNUNET_ARM_RESULT_STOPPED:
1158       return _("%s is stopped");
1159
1160     case GNUNET_ARM_RESULT_STARTING:
1161       return _("%s is starting");
1162
1163     case GNUNET_ARM_RESULT_STOPPING:
1164       return _("%s is stopping");
1165
1166     case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1167       return _("%s is starting already");
1168
1169     case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1170       return _("%s is stopping already");
1171
1172     case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1173       return _("%s is started already");
1174
1175     case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1176       return _("%s is stopped already");
1177
1178     case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1179       return _("%s service is not known to ARM");
1180
1181     case GNUNET_ARM_RESULT_START_FAILED:
1182       return _("%s service failed to start");
1183
1184     case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1185       return _("%s service can't be started because ARM is shutting down");
1186     }
1187   return _("%.s Unknown result code.");
1188 }
1189
1190
1191 /**
1192  * Function called in response to a start/stop request.
1193  * Will be called when request was not sent successfully,
1194  * or when a reply comes. If the request was not sent successfully,
1195  * @a rs will indicate that, and @a result will be undefined.
1196  *
1197  * @param cls ManageServiceContext
1198  * @param rs status of the request
1199  * @param result result of the operation
1200  */
1201 static void
1202 service_manage_result_cb(void *cls,
1203                          enum GNUNET_ARM_RequestStatus rs,
1204                          enum GNUNET_ARM_Result result)
1205 {
1206   struct ManageServiceContext *mctx = cls;
1207   char *emsg;
1208
1209   emsg = NULL;
1210   if (GNUNET_YES == mctx->expired)
1211     return;
1212   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1213     {
1214       GNUNET_asprintf(&emsg,
1215                       "Error communicating with Peer %u's ARM: %s",
1216                       mctx->peer->id,
1217                       arm_req_string(rs));
1218       goto ret;
1219     }
1220   if (1 == mctx->start)
1221     goto service_start_check;
1222   if (!((GNUNET_ARM_RESULT_STOPPED == result)
1223         || (GNUNET_ARM_RESULT_STOPPING == result)
1224         || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1225         || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)))
1226     {
1227       /* stopping a service failed */
1228       GNUNET_asprintf(&emsg,
1229                       arm_ret_string(result),
1230                       mctx->service);
1231       goto ret;
1232     }
1233   /* service stopped successfully */
1234   goto ret;
1235
1236 service_start_check:
1237   if (!((GNUNET_ARM_RESULT_STARTING == result)
1238         || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1239         || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)))
1240     {
1241       /* starting a service failed */
1242       GNUNET_asprintf(&emsg,
1243                       arm_ret_string(result),
1244                       mctx->service);
1245       goto ret;
1246     }
1247   /* service started successfully */
1248
1249 ret:
1250   if (NULL != emsg)
1251     {
1252       LOG_DEBUG("%s\n", emsg);
1253       GST_send_operation_fail_msg(mctx->client,
1254                                   mctx->op_id,
1255                                   emsg);
1256     }
1257   else
1258     GST_send_operation_success_msg(mctx->client,
1259                                    mctx->op_id);
1260   GNUNET_free_non_null(emsg);
1261   cleanup_mctx(mctx);
1262 }
1263
1264
1265 /**
1266  * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1267  *
1268  * @param cls identification of client
1269  * @param msg the actual message
1270  * @return #GNUNET_OK if @a msg is well-formed
1271  */
1272 int
1273 check_manage_peer_service(void *cls,
1274                           const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1275 {
1276   uint16_t msize;
1277   const char* service;
1278
1279   msize = ntohs(msg->header.size);
1280   service = (const char *)&msg[1];
1281   if ('\0' != service[msize - sizeof
1282                       (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1283     {
1284       GNUNET_break_op(0);
1285       return GNUNET_SYSERR;
1286     }
1287   if (1 < msg->start)
1288     {
1289       GNUNET_break_op(0);
1290       return GNUNET_SYSERR;
1291     }
1292   return GNUNET_OK;
1293 }
1294
1295
1296 /**
1297  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1298  *
1299  * @param cls identification of client
1300  * @param msg the actual message
1301  */
1302 void
1303 handle_manage_peer_service(void *cls,
1304                            const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1305 {
1306   struct GNUNET_SERVICE_Client *client = cls;
1307   const char* service;
1308   struct Peer *peer;
1309   char *emsg;
1310   struct GNUNET_ARM_Handle *ah;
1311   struct ManageServiceContext *mctx;
1312   struct ForwardedOperationContext *fopc;
1313   uint64_t op_id;
1314   uint32_t peer_id;
1315
1316   service = (const char *)&msg[1];
1317   peer_id = ntohl(msg->peer_id);
1318   op_id = GNUNET_ntohll(msg->operation_id);
1319   LOG_DEBUG("Received request to manage service %s on peer %u\n",
1320             service, (unsigned int)peer_id);
1321   if ((GST_peer_list_size <= peer_id)
1322       || (NULL == (peer = GST_peer_list[peer_id])))
1323     {
1324       GNUNET_asprintf(&emsg, "Asked to manage service of a non existent peer "
1325                       "with id: %u", peer_id);
1326       goto err_ret;
1327     }
1328   if (0 == strcasecmp("arm", service))
1329     {
1330       emsg = GNUNET_strdup("Cannot start/stop peer's ARM service.  "
1331                            "Use peer start/stop for that");
1332       goto err_ret;
1333     }
1334   if (GNUNET_YES == peer->is_remote)
1335     {
1336       /* Forward the destory message to sub controller */
1337       fopc = GNUNET_new(struct ForwardedOperationContext);
1338       fopc->client = client;
1339       fopc->cls = peer;
1340       fopc->type = OP_MANAGE_SERVICE;
1341       fopc->operation_id = op_id;
1342       fopc->opc =
1343         GNUNET_TESTBED_forward_operation_msg_(peer->details.remote.
1344                                               slave->controller,
1345                                               fopc->operation_id,
1346                                               &msg->header,
1347                                               &GST_forwarded_operation_reply_relay,
1348                                               fopc);
1349       fopc->timeout_task =
1350         GNUNET_SCHEDULER_add_delayed(GST_timeout,
1351                                      &GST_forwarded_operation_timeout,
1352                                      fopc);
1353       GNUNET_CONTAINER_DLL_insert_tail(fopcq_head,
1354                                        fopcq_tail,
1355                                        fopc);
1356       GNUNET_SERVICE_client_continue(client);
1357       return;
1358     }
1359   if (GNUNET_NO == peer->details.local.is_running)
1360     {
1361       emsg = GNUNET_strdup("Peer not running\n");
1362       goto err_ret;
1363     }
1364   if ((0 != peer->reference_cnt)
1365       && ((0 == strcasecmp("core", service))
1366           || (0 == strcasecmp("transport", service))))
1367     {
1368       GNUNET_asprintf(&emsg, "Cannot stop %s service of peer with id: %u "
1369                       "since it is required by existing operations",
1370                       service, peer_id);
1371       goto err_ret;
1372     }
1373   ah = GNUNET_ARM_connect(peer->details.local.cfg, NULL, NULL);
1374   if (NULL == ah)
1375     {
1376       GNUNET_asprintf(&emsg,
1377                       "Cannot connect to ARM service of peer with id: %u",
1378                       peer_id);
1379       goto err_ret;
1380     }
1381   mctx = GNUNET_new(struct ManageServiceContext);
1382   mctx->peer = peer;
1383   peer->reference_cnt++;
1384   mctx->op_id = op_id;
1385   mctx->ah = ah;
1386   mctx->client = client;
1387   mctx->start = msg->start;
1388   mctx->service = GNUNET_strdup(service);
1389   GNUNET_CONTAINER_DLL_insert_tail(mctx_head,
1390                                    mctx_tail,
1391                                    mctx);
1392   if (1 == mctx->start)
1393     GNUNET_ARM_request_service_start(mctx->ah,
1394                                      service,
1395                                      GNUNET_OS_INHERIT_STD_ERR,
1396                                      &service_manage_result_cb,
1397                                      mctx);
1398   else
1399     GNUNET_ARM_request_service_stop(mctx->ah, service,
1400                                     &service_manage_result_cb,
1401                                     mctx);
1402   GNUNET_SERVICE_client_continue(client);
1403   return;
1404
1405 err_ret:
1406   LOG(GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1407   GST_send_operation_fail_msg(client, op_id, emsg);
1408   GNUNET_free(emsg);
1409   GNUNET_SERVICE_client_continue(client);
1410 }
1411
1412
1413 /**
1414  * Stops and destroys all peers
1415  */
1416 void
1417 GST_destroy_peers()
1418 {
1419   struct Peer *peer;
1420   unsigned int id;
1421
1422   if (NULL == GST_peer_list)
1423     return;
1424   for (id = 0; id < GST_peer_list_size; id++)
1425     {
1426       peer = GST_peer_list[id];
1427       if (NULL == peer)
1428         continue;
1429       /* If destroy flag is set it means that this peer should have been
1430        * destroyed by a context which we destroy before */
1431       GNUNET_break(GNUNET_NO == peer->destroy_flag);
1432       /* counter should be zero as we free all contexts before */
1433       GNUNET_break(0 == peer->reference_cnt);
1434       if ((GNUNET_NO == peer->is_remote) &&
1435           (GNUNET_YES == peer->details.local.is_running))
1436         GNUNET_TESTING_peer_kill(peer->details.local.peer);
1437     }
1438   for (id = 0; id < GST_peer_list_size; id++)
1439     {
1440       peer = GST_peer_list[id];
1441       if (NULL == peer)
1442         continue;
1443       if (GNUNET_NO == peer->is_remote)
1444         {
1445           if (GNUNET_YES == peer->details.local.is_running)
1446             GNUNET_TESTING_peer_wait(peer->details.local.peer);
1447           GNUNET_TESTING_peer_destroy(peer->details.local.peer);
1448           GNUNET_CONFIGURATION_destroy(peer->details.local.cfg);
1449         }
1450       GNUNET_free(peer);
1451     }
1452   GNUNET_free_non_null(GST_peer_list);
1453   GST_peer_list = NULL;
1454   GST_peer_list_size = 0;
1455 }
1456
1457
1458 /**
1459  * The reply msg handler forwarded SHUTDOWN_PEERS operation.  Checks if a
1460  * success reply is received from all clients and then sends the success message
1461  * to the client
1462  *
1463  * @param cls ForwardedOperationContext
1464  * @param msg the message to relay
1465  */
1466 static void
1467 shutdown_peers_reply_cb(void *cls,
1468                         const struct GNUNET_MessageHeader *msg)
1469 {
1470   struct ForwardedOperationContext *fo_ctxt = cls;
1471   struct HandlerContext_ShutdownPeers *hc;
1472
1473   hc = fo_ctxt->cls;
1474   GNUNET_assert(0 < hc->nslaves);
1475   hc->nslaves--;
1476   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1477       ntohs(msg->type))
1478     hc->timeout = GNUNET_YES;
1479   if (0 == hc->nslaves)
1480     {
1481       if (GNUNET_YES == hc->timeout)
1482         GST_send_operation_fail_msg(fo_ctxt->client,
1483                                     fo_ctxt->operation_id,
1484                                     "Timeout at a slave controller");
1485       else
1486         GST_send_operation_success_msg(fo_ctxt->client,
1487                                        fo_ctxt->operation_id);
1488       GNUNET_free(hc);
1489       hc = NULL;
1490     }
1491   GNUNET_CONTAINER_DLL_remove(fopcq_head,
1492                               fopcq_tail,
1493                               fo_ctxt);
1494   GNUNET_free(fo_ctxt);
1495 }
1496
1497
1498 /**
1499  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1500  *
1501  * @param cls identification of the client
1502  * @param msg the actual message
1503  */
1504 void
1505 handle_shutdown_peers(void *cls,
1506                       const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1507 {
1508   struct GNUNET_SERVICE_Client *client = cls;
1509   struct HandlerContext_ShutdownPeers *hc;
1510   struct Slave *slave;
1511   struct ForwardedOperationContext *fo_ctxt;
1512   uint64_t op_id;
1513   unsigned int cnt;
1514
1515   LOG_DEBUG("Received SHUTDOWN_PEERS\n");
1516   /* Stop and destroy all peers */
1517   GST_free_mctxq();
1518   GST_free_occq();
1519   GST_free_roccq();
1520   GST_clear_fopcq();
1521   /* Forward to all slaves which we have started */
1522   op_id = GNUNET_ntohll(msg->operation_id);
1523   hc = GNUNET_new(struct HandlerContext_ShutdownPeers);
1524   /* FIXME: have a better implementation where we track which slaves are
1525      started by this controller */
1526   for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1527     {
1528       slave = GST_slave_list[cnt];
1529       if (NULL == slave)
1530         continue;
1531       if (NULL == slave->controller_proc) /* We didn't start the slave */
1532         continue;
1533       LOG_DEBUG("Forwarding SHUTDOWN_PEERS\n");
1534       hc->nslaves++;
1535       fo_ctxt = GNUNET_new(struct ForwardedOperationContext);
1536       fo_ctxt->client = client;
1537       fo_ctxt->operation_id = op_id;
1538       fo_ctxt->cls = hc;
1539       fo_ctxt->type = OP_SHUTDOWN_PEERS;
1540       fo_ctxt->opc =
1541         GNUNET_TESTBED_forward_operation_msg_(slave->controller,
1542                                               fo_ctxt->operation_id,
1543                                               &msg->header,
1544                                               shutdown_peers_reply_cb,
1545                                               fo_ctxt);
1546       GNUNET_CONTAINER_DLL_insert_tail(fopcq_head,
1547                                        fopcq_tail,
1548                                        fo_ctxt);
1549     }
1550   LOG_DEBUG("Shutting down peers\n");
1551   GST_destroy_peers();
1552   if (0 == hc->nslaves)
1553     {
1554       GST_send_operation_success_msg(client,
1555                                      op_id);
1556       GNUNET_free(hc);
1557     }
1558   GNUNET_SERVICE_client_continue(client);
1559 }