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