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