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