- exit when an operation fails
[oweals/gnunet.git] / src / testbed / testbed_api_peers.c
1 /*
2       This file is part of GNUnet
3       (C) 2008--2012 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  * @file testbed/testbed_api_peers.c
23  * @brief management of the knowledge about peers in this library
24  *        (we know the peer ID, its host, pending operations, etc.)
25  * @author Christian Grothoff
26  * @author Sree Harsha Totakura
27  */
28
29 #include "platform.h"
30 #include "testbed_api_peers.h"
31 #include "testbed_api.h"
32 #include "testbed.h"
33 #include "testbed_api_hosts.h"
34 #include "testbed_api_operations.h"
35
36
37 /**
38  * Peer list DLL head
39  */
40 static struct GNUNET_TESTBED_Peer *peer_list_head;
41
42 /**
43  * Peer list DLL tail
44  */
45 static struct GNUNET_TESTBED_Peer *peer_list_tail;
46
47
48 /**
49  * Adds a peer to the peer list
50  *
51  * @param peer the peer to add to the peer list
52  */
53 void
54 GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer)
55 {
56   GNUNET_CONTAINER_DLL_insert_tail (peer_list_head, peer_list_tail, peer);
57 }
58
59
60 /**
61  * Removes a peer from the peer list
62  *
63  * @param peer the peer to remove
64  */
65 void
66 GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer)
67 {
68   GNUNET_CONTAINER_DLL_remove (peer_list_head, peer_list_tail, peer);
69 }
70
71
72 /**
73  * Frees all peers
74  */
75 void
76 GNUNET_TESTBED_cleanup_peers_ (void)
77 {
78   struct GNUNET_TESTBED_Peer *peer;
79
80   while (NULL != (peer = peer_list_head))
81   {
82     GNUNET_TESTBED_peer_deregister_ (peer);
83     GNUNET_free (peer);
84   }
85 }
86
87
88
89 /**
90  * Function to call to start a peer_create type operation once all
91  * queues the operation is part of declare that the
92  * operation can be activated.
93  *
94  * @param cls the closure from GNUNET_TESTBED_operation_create_()
95  */
96 static void
97 opstart_peer_create (void *cls)
98 {
99   struct OperationContext *opc = cls;
100   struct PeerCreateData *data;
101   struct GNUNET_TESTBED_PeerCreateMessage *msg;
102   char *config;
103   char *xconfig;
104   size_t c_size;
105   size_t xc_size;
106   uint16_t msize;
107
108   GNUNET_assert (OP_PEER_CREATE == opc->type);
109   data = opc->data;
110   GNUNET_assert (NULL != data);
111   GNUNET_assert (NULL != data->peer);
112   opc->state = OPC_STATE_STARTED;
113   config = GNUNET_CONFIGURATION_serialize (data->cfg, &c_size);
114   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
115   GNUNET_free (config);
116   msize = xc_size + sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
117   msg = GNUNET_realloc (xconfig, msize);
118   memmove (&msg[1], msg, xc_size);
119   msg->header.size = htons (msize);
120   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
121   msg->operation_id = GNUNET_htonll (opc->id);
122   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
123   msg->peer_id = htonl (data->peer->unique_id);
124   msg->config_size = htonl (c_size);
125   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
126   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
127 }
128
129
130 /**
131  * Callback which will be called when peer_create type operation is released
132  *
133  * @param cls the closure from GNUNET_TESTBED_operation_create_()
134  */
135 static void
136 oprelease_peer_create (void *cls)
137 {
138   struct OperationContext *opc = cls;
139
140   switch (opc->state)
141   {
142   case OPC_STATE_STARTED:
143     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
144     /* No break we continue flow */
145   case OPC_STATE_INIT:
146     GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
147     GNUNET_free (opc->data);
148     break;
149   case OPC_STATE_FINISHED:
150     break;
151   }
152   GNUNET_free (opc);
153 }
154
155
156 /**
157  * Function called when a peer destroy operation is ready
158  *
159  * @param cls the closure from GNUNET_TESTBED_operation_create_()
160  */
161 static void
162 opstart_peer_destroy (void *cls)
163 {
164   struct OperationContext *opc = cls;
165   struct GNUNET_TESTBED_Peer *peer;
166   struct GNUNET_TESTBED_PeerDestroyMessage *msg;
167
168   GNUNET_assert (OP_PEER_DESTROY == opc->type);
169   peer = opc->data;
170   GNUNET_assert (NULL != peer);
171   opc->state = OPC_STATE_STARTED;
172   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
173   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
174   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
175   msg->peer_id = htonl (peer->unique_id);
176   msg->operation_id = GNUNET_htonll (opc->id);
177   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
178   GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
179 }
180
181
182 /**
183  * Callback which will be called when peer_create type operation is released
184  *
185  * @param cls the closure from GNUNET_TESTBED_operation_create_()
186  */
187 static void
188 oprelease_peer_destroy (void *cls)
189 {
190   struct OperationContext *opc = cls;
191
192   if (OPC_STATE_FINISHED != opc->state)
193     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
194   GNUNET_free (opc);
195 }
196
197
198 /**
199  * Function called when a peer start operation is ready
200  *
201  * @param cls the closure from GNUNET_TESTBED_operation_create_()
202  */
203 static void
204 opstart_peer_start (void *cls)
205 {
206   struct OperationContext *opc = cls;
207   struct GNUNET_TESTBED_PeerStartMessage *msg;
208   struct PeerEventData *data;
209   struct GNUNET_TESTBED_Peer *peer;
210
211   GNUNET_assert (OP_PEER_START == opc->type);
212   GNUNET_assert (NULL != opc->data);
213   data = opc->data;
214   GNUNET_assert (NULL != data->peer);
215   peer = data->peer;
216   GNUNET_assert ((PS_CREATED == peer->state) || (PS_STOPPED == peer->state));
217   opc->state = OPC_STATE_STARTED;
218   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
219   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
220   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_START_PEER);
221   msg->peer_id = htonl (peer->unique_id);
222   msg->operation_id = GNUNET_htonll (opc->id);
223   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
224   GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
225 }
226
227
228 /**
229  * Callback which will be called when peer start type operation is released
230  *
231  * @param cls the closure from GNUNET_TESTBED_operation_create_()
232  */
233 static void
234 oprelease_peer_start (void *cls)
235 {
236   struct OperationContext *opc = cls;
237
238   if (OPC_STATE_FINISHED != opc->state)
239   {
240     GNUNET_free (opc->data);
241     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
242   }
243   GNUNET_free (opc);
244 }
245
246
247 /**
248  * Function called when a peer stop operation is ready
249  *
250  * @param cls the closure from GNUNET_TESTBED_operation_create_()
251  */
252 static void
253 opstart_peer_stop (void *cls)
254 {
255   struct OperationContext *opc = cls;
256   struct GNUNET_TESTBED_PeerStopMessage *msg;
257   struct PeerEventData *data;
258   struct GNUNET_TESTBED_Peer *peer;
259
260   GNUNET_assert (NULL != opc->data);
261   data = opc->data;
262   GNUNET_assert (NULL != data->peer);
263   peer = data->peer;
264   GNUNET_assert (PS_STARTED == peer->state);
265   opc->state = OPC_STATE_STARTED;
266   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
267   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER);
268   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
269   msg->peer_id = htonl (peer->unique_id);
270   msg->operation_id = GNUNET_htonll (opc->id);
271   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
272   GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
273 }
274
275
276 /**
277  * Callback which will be called when peer stop type operation is released
278  *
279  * @param cls the closure from GNUNET_TESTBED_operation_create_()
280  */
281 static void
282 oprelease_peer_stop (void *cls)
283 {
284   struct OperationContext *opc = cls;
285
286   if (OPC_STATE_FINISHED != opc->state)
287   {
288     GNUNET_free (opc->data);
289     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
290   }
291   GNUNET_free (opc);
292 }
293
294
295 /**
296  * Generate PeerGetConfigurationMessage
297  *
298  * @param peer_id the id of the peer whose information we have to get
299  * @param operation_id the ip of the operation that should be represented in the
300  *          message
301  * @return the PeerGetConfigurationMessage
302  */
303 struct GNUNET_TESTBED_PeerGetConfigurationMessage *
304 GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
305                                             uint64_t operation_id)
306 {
307   struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
308
309   msg =
310       GNUNET_malloc (sizeof
311                      (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
312   msg->header.size =
313       htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
314   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
315   msg->peer_id = htonl (peer_id);
316   msg->operation_id = GNUNET_htonll (operation_id);
317   return msg;
318 }
319
320
321 /**
322  * Function called when a peer get information operation is ready
323  *
324  * @param cls the closure from GNUNET_TESTBED_operation_create_()
325  */
326 static void
327 opstart_peer_getinfo (void *cls)
328 {
329   struct OperationContext *opc = cls;
330   struct PeerInfoData *data;
331   struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
332
333   data = opc->data;
334   GNUNET_assert (NULL != data);
335   opc->state = OPC_STATE_STARTED;
336   msg =
337       GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id,
338                                                   opc->id);
339   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
340   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
341 }
342
343
344 /**
345  * Callback which will be called when peer stop type operation is released
346  *
347  * @param cls the closure from GNUNET_TESTBED_operation_create_()
348  */
349 static void
350 oprelease_peer_getinfo (void *cls)
351 {
352   struct OperationContext *opc = cls;
353   struct GNUNET_TESTBED_PeerInformation *data;
354
355   if (OPC_STATE_FINISHED != opc->state)
356   {
357     GNUNET_free_non_null (opc->data);
358     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
359   }
360   else
361   {
362     data = opc->data;
363     GNUNET_assert (NULL != data);
364     switch (data->pit)
365     {
366     case GNUNET_TESTBED_PIT_CONFIGURATION:
367       GNUNET_CONFIGURATION_destroy (data->result.cfg);
368       break;
369     case GNUNET_TESTBED_PIT_IDENTITY:
370       GNUNET_free (data->result.id);
371       break;
372     default:
373       GNUNET_assert (0);        /* We should never reach here */
374     }
375     GNUNET_free (data);
376   }
377   GNUNET_free (opc);
378 }
379
380
381 /**
382  * Function called when a overlay connect operation is ready
383  *
384  * @param cls the closure from GNUNET_TESTBED_operation_create_()
385  */
386 static void
387 opstart_overlay_connect (void *cls)
388 {
389   struct OperationContext *opc = cls;
390   struct GNUNET_TESTBED_OverlayConnectMessage *msg;
391   struct OverlayConnectData *data;
392
393   opc->state = OPC_STATE_STARTED;
394   data = opc->data;
395   GNUNET_assert (NULL != data);
396   data->tslot_index = GNUNET_TESTBED_get_tslot_ (data->p1->host, data);
397   data->tstart = GNUNET_TIME_absolute_get ();
398   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
399   msg->header.size =
400       htons (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
401   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT);
402   msg->peer1 = htonl (data->p1->unique_id);
403   msg->peer2 = htonl (data->p2->unique_id);
404   msg->operation_id = GNUNET_htonll (opc->id);
405   msg->peer2_host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->p2->host));
406   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
407   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
408 }
409
410
411 /**
412  * Callback which will be called when overlay connect operation is released
413  *
414  * @param cls the closure from GNUNET_TESTBED_operation_create_()
415  */
416 static void
417 oprelease_overlay_connect (void *cls)
418 {
419   struct OperationContext *opc = cls;
420   struct GNUNET_TIME_Relative duration;
421   struct OverlayConnectData *data;
422
423   data = opc->data;
424   switch (opc->state)
425   {
426   case OPC_STATE_INIT:
427     break;
428   case OPC_STATE_STARTED:
429     (void) GNUNET_TESTBED_release_time_slot_ (data->p1->host, data->tslot_index,
430                                               data);
431     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
432     break;
433   case OPC_STATE_FINISHED:
434     duration = GNUNET_TIME_absolute_get_duration (data->tstart);
435     GNUNET_TESTBED_update_time_slot_ (data->p1->host, data->tslot_index, data,
436                                       duration, data->failed);
437   }
438   GNUNET_free (data);
439   GNUNET_free (opc);
440 }
441
442
443 /**
444  * Lookup a peer by ID.
445  *
446  * @param id global peer ID assigned to the peer
447  * @return handle to the host, NULL on error
448  */
449 struct GNUNET_TESTBED_Peer *
450 GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
451 {
452   GNUNET_break (0);
453   return NULL;
454 }
455
456
457 /**
458  * Create the given peer at the specified host using the given
459  * controller.  If the given controller is not running on the target
460  * host, it should find or create a controller at the target host and
461  * delegate creating the peer.  Explicit delegation paths can be setup
462  * using 'GNUNET_TESTBED_controller_link'.  If no explicit delegation
463  * path exists, a direct link with a subordinate controller is setup
464  * for the first delegated peer to a particular host; the subordinate
465  * controller is then destroyed once the last peer that was delegated
466  * to the remote host is stopped.
467  *
468  * Creating the peer only creates the handle to manipulate and further
469  * configure the peer; use "GNUNET_TESTBED_peer_start" and
470  * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
471  * processes.
472  *
473  * Note that the given configuration will be adjusted by the
474  * controller to avoid port/path conflicts with other peers.
475  * The "final" configuration can be obtained using
476  * 'GNUNET_TESTBED_peer_get_information'.
477  *
478  * @param controller controller process to use
479  * @param host host to run the peer on; cannot be NULL
480  * @param cfg Template configuration to use for the peer. Should exist until
481  *          operation is cancelled or GNUNET_TESTBED_operation_done() is called
482  * @param cb the callback to call when the peer has been created
483  * @param cls the closure to the above callback
484  * @return the operation handle
485  */
486 struct GNUNET_TESTBED_Operation *
487 GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller,
488                             struct GNUNET_TESTBED_Host *host,
489                             const struct GNUNET_CONFIGURATION_Handle *cfg,
490                             GNUNET_TESTBED_PeerCreateCallback cb, void *cls)
491 {
492
493   struct GNUNET_TESTBED_Peer *peer;
494   struct PeerCreateData *data;
495   struct OperationContext *opc;
496   static uint32_t id_gen;
497
498   peer = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer));
499   peer->controller = controller;
500   peer->host = host;
501   peer->unique_id = id_gen++;
502   peer->state = PS_INVALID;
503   data = GNUNET_malloc (sizeof (struct PeerCreateData));
504   data->host = host;
505   data->cfg = cfg;
506   data->cb = cb;
507   data->cls = cls;
508   data->peer = peer;
509   opc = GNUNET_malloc (sizeof (struct OperationContext));
510   opc->c = controller;
511   opc->data = data;
512   opc->id = GNUNET_TESTBED_get_next_op_id (controller);
513   opc->type = OP_PEER_CREATE;
514   opc->op =
515       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create,
516                                         &oprelease_peer_create);
517   GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations,
518                                           opc->op);
519   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
520   return opc->op;
521 }
522
523
524 /**
525  * Start the given peer.
526  *
527  * @param op_cls the closure for this operation; will be set in
528  *          event->details.operation_finished.op_cls when this operation fails.
529  * @param peer peer to start
530  * @param pcc function to call upon completion
531  * @param pcc_cls closure for 'pcc'
532  * @return handle to the operation
533  */
534 struct GNUNET_TESTBED_Operation *
535 GNUNET_TESTBED_peer_start (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
536                            GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
537 {
538   struct OperationContext *opc;
539   struct PeerEventData *data;
540
541   data = GNUNET_malloc (sizeof (struct PeerEventData));
542   data->peer = peer;
543   data->pcc = pcc;
544   data->pcc_cls = pcc_cls;
545   opc = GNUNET_malloc (sizeof (struct OperationContext));
546   opc->c = peer->controller;
547   opc->data = data;
548   opc->op_cls = op_cls;
549   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
550   opc->type = OP_PEER_START;
551   opc->op =
552       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_start,
553                                         &oprelease_peer_start);
554   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
555                                           opc->op);
556   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
557   return opc->op;
558 }
559
560
561 /**
562  * Stop the given peer.  The handle remains valid (use
563  * "GNUNET_TESTBED_peer_destroy" to fully clean up the
564  * state of the peer).
565  *
566  * @param op_cls the closure for this operation; will be set in the event
567  *          information
568  * @param peer peer to stop
569  * @param pcc function to call upon completion
570  * @param pcc_cls closure for 'pcc'
571  * @return handle to the operation
572  */
573 struct GNUNET_TESTBED_Operation *
574 GNUNET_TESTBED_peer_stop (void *op_cls,
575                           struct GNUNET_TESTBED_Peer *peer,
576                           GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
577 {
578   struct OperationContext *opc;
579   struct PeerEventData *data;
580
581   data = GNUNET_malloc (sizeof (struct PeerEventData));
582   data->peer = peer;
583   data->pcc = pcc;
584   data->pcc_cls = pcc_cls;
585   opc = GNUNET_malloc (sizeof (struct OperationContext));
586   opc->c = peer->controller;
587   opc->data = data;
588   opc->op_cls = op_cls;
589   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
590   opc->type = OP_PEER_STOP;
591   opc->op =
592       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop,
593                                         &oprelease_peer_stop);
594   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
595                                           opc->op);
596   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
597   return opc->op;
598 }
599
600
601 /**
602  * Request information about a peer. The controller callback will not be called
603  * with event type GNUNET_TESTBED_ET_OPERATION_FINISHED when result for this
604  * operation is available. Instead, the GNUNET_TESTBED_PeerInfoCallback() will
605  * be called.
606  *
607  * @param peer peer to request information about
608  * @param pit desired information
609  * @param cb the convenience callback to be called when results for this
610  *          operation are available
611  * @param cb_cls the closure for the above callback
612  * @return handle to the operation
613  */
614 struct GNUNET_TESTBED_Operation *
615 GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
616                                      enum GNUNET_TESTBED_PeerInformationType
617                                      pit, GNUNET_TESTBED_PeerInfoCallback cb,
618                                      void *cb_cls)
619 {
620   struct OperationContext *opc;
621   struct PeerInfoData *data;
622
623   GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit);
624   GNUNET_assert (NULL != cb);
625   data = GNUNET_malloc (sizeof (struct PeerInfoData));
626   data->peer = peer;
627   data->pit = pit;
628   data->cb = cb;
629   data->cb_cls = cb_cls;
630   opc = GNUNET_malloc (sizeof (struct OperationContext));
631   opc->c = peer->controller;
632   opc->data = data;
633   opc->type = OP_PEER_INFO;
634   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
635   opc->op =
636       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo,
637                                         &oprelease_peer_getinfo);
638   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
639                                           opc->op);
640   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
641   return opc->op;
642 }
643
644
645 /**
646  * Change peer configuration.  Must only be called while the
647  * peer is stopped.  Ports and paths cannot be changed this
648  * way.
649  *
650  * @param peer peer to change configuration for
651  * @param cfg new configuration (differences to existing
652  *            configuration only)
653  * @return handle to the operation
654  */
655 struct GNUNET_TESTBED_Operation *
656 GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
657                                           const struct
658                                           GNUNET_CONFIGURATION_Handle *cfg)
659 {
660   // FIXME: handle locally or delegate...
661   GNUNET_break (0);
662   return NULL;
663 }
664
665
666 /**
667  * Destroy the given peer; the peer should have been
668  * stopped first (if it was started).
669  *
670  * @param peer peer to stop
671  * @return handle to the operation
672  */
673 struct GNUNET_TESTBED_Operation *
674 GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer)
675 {
676   struct OperationContext *opc;
677
678   opc = GNUNET_malloc (sizeof (struct OperationContext));
679   opc->data = peer;
680   opc->c = peer->controller;
681   opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller);
682   opc->type = OP_PEER_DESTROY;
683   opc->op =
684       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy,
685                                         &oprelease_peer_destroy);
686   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
687                                           opc->op);
688   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
689   return opc->op;
690 }
691
692
693 /**
694  * Manipulate the P2P underlay topology by configuring a link
695  * between two peers.
696  *
697  * @param op_cls closure argument to give with the operation event
698  * @param p1 first peer
699  * @param p2 second peer
700  * @param co option to change
701  * @param ... option-specific values
702  * @return handle to the operation, NULL if configuring the link at this
703  *         time is not allowed
704  */
705 struct GNUNET_TESTBED_Operation *
706 GNUNET_TESTBED_underlay_configure_link (void *op_cls,
707                                         struct GNUNET_TESTBED_Peer *p1,
708                                         struct GNUNET_TESTBED_Peer *p2,
709                                         enum GNUNET_TESTBED_ConnectOption co,
710                                         ...)
711 {
712   GNUNET_break (0);
713   return NULL;
714 }
715
716
717 /**
718  * Both peers must have been started before calling this function.
719  * This function then obtains a HELLO from 'p1', gives it to 'p2'
720  * and asks 'p2' to connect to 'p1'.
721  *
722  * @param op_cls closure argument to give with the operation event
723  * @param cb the callback to call when this operation has finished
724  * @param cb_cls the closure for the above callback
725  * @param p1 first peer
726  * @param p2 second peer
727  * @return handle to the operation, NULL if connecting these two
728  *         peers is fundamentally not possible at this time (peers
729  *         not running or underlay disallows)
730  */
731 struct GNUNET_TESTBED_Operation *
732 GNUNET_TESTBED_overlay_connect (void *op_cls,
733                                 GNUNET_TESTBED_OperationCompletionCallback cb,
734                                 void *cb_cls, struct GNUNET_TESTBED_Peer *p1,
735                                 struct GNUNET_TESTBED_Peer *p2)
736 {
737   struct OperationContext *opc;
738   struct OverlayConnectData *data;
739
740   GNUNET_assert ((PS_STARTED == p1->state) && (PS_STARTED == p2->state));
741   data = GNUNET_malloc (sizeof (struct OverlayConnectData));
742   data->p1 = p1;
743   data->p2 = p2;
744   data->cb = cb;
745   data->cb_cls = cb_cls;
746   opc = GNUNET_malloc (sizeof (struct OperationContext));
747   opc->data = data;
748   opc->c = p1->controller;
749   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
750   opc->type = OP_OVERLAY_CONNECT;
751   opc->op_cls = op_cls;
752   opc->op =
753       GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
754                                         &oprelease_overlay_connect);
755   GNUNET_TESTBED_host_queue_oc_ (p1->host, opc->op);
756   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
757   return opc->op;
758 }
759
760
761
762 /* end of testbed_api_peers.c */