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