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