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