fix
[oweals/gnunet.git] / src / testbed / testbed_api_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 it
6       under the terms of the GNU Affero General Public License as published
7       by the Free Software Foundation, either version 3 of the License,
8       or (at your option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       Affero General Public License for more details.
14      
15       You should have received a copy of the GNU Affero General Public License
16       along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /**
20  * @file testbed/testbed_api_peers.c
21  * @brief management of the knowledge about peers in this library
22  *        (we know the peer ID, its host, pending operations, etc.)
23  * @author Christian Grothoff
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "testbed_api_peers.h"
29 #include "testbed_api.h"
30 #include "testbed.h"
31 #include "testbed_api_hosts.h"
32 #include "testbed_api_operations.h"
33
34
35 /**
36  * Peer list DLL head
37  */
38 static struct GNUNET_TESTBED_Peer *peer_list_head;
39
40 /**
41  * Peer list DLL tail
42  */
43 static struct GNUNET_TESTBED_Peer *peer_list_tail;
44
45
46 /**
47  * Adds a peer to the peer list
48  *
49  * @param peer the peer to add to the peer list
50  */
51 void
52 GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer)
53 {
54   GNUNET_CONTAINER_DLL_insert_tail (peer_list_head, peer_list_tail, peer);
55 }
56
57
58 /**
59  * Removes a peer from the peer list
60  *
61  * @param peer the peer to remove
62  */
63 void
64 GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer)
65 {
66   GNUNET_CONTAINER_DLL_remove (peer_list_head, peer_list_tail, peer);
67 }
68
69
70 /**
71  * Frees all peers
72  */
73 void
74 GNUNET_TESTBED_cleanup_peers_ (void)
75 {
76   struct GNUNET_TESTBED_Peer *peer;
77
78   while (NULL != (peer = peer_list_head))
79   {
80     GNUNET_TESTBED_peer_deregister_ (peer);
81     GNUNET_free (peer);
82   }
83 }
84
85
86
87 /**
88  * Function to call to start a peer_create type operation once all
89  * queues the operation is part of declare that the
90  * operation can be activated.
91  *
92  * @param cls the closure from GNUNET_TESTBED_operation_create_()
93  */
94 static void
95 opstart_peer_create (void *cls)
96 {
97   struct OperationContext *opc = cls;
98   struct PeerCreateData *data = opc->data;
99   struct GNUNET_TESTBED_PeerCreateMessage *msg;
100   struct GNUNET_MQ_Envelope *env;
101   char *config;
102   char *xconfig;
103   size_t c_size;
104   size_t xc_size;
105
106   GNUNET_assert (OP_PEER_CREATE == opc->type);
107   GNUNET_assert (NULL != data);
108   GNUNET_assert (NULL != data->peer);
109   opc->state = OPC_STATE_STARTED;
110   config = GNUNET_CONFIGURATION_serialize (data->cfg,
111                                            &c_size);
112   xc_size = GNUNET_TESTBED_compress_config_ (config,
113                                              c_size,
114                                              &xconfig);
115   GNUNET_free (config);
116   env = GNUNET_MQ_msg_extra (msg,
117                              xc_size,
118                              GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
119   msg->operation_id = GNUNET_htonll (opc->id);
120   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
121   msg->peer_id = htonl (data->peer->unique_id);
122   msg->config_size = htons ((uint16_t) c_size);
123   GNUNET_memcpy (&msg[1],
124           xconfig,
125           xc_size);
126   GNUNET_MQ_send (opc->c->mq,
127                   env);
128   GNUNET_free (xconfig);
129   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
130 }
131
132
133 /**
134  * Callback which will be called when peer_create type operation is released
135  *
136  * @param cls the closure from GNUNET_TESTBED_operation_create_()
137  */
138 static void
139 oprelease_peer_create (void *cls)
140 {
141   struct OperationContext *opc = cls;
142
143   switch (opc->state)
144   {
145   case OPC_STATE_STARTED:
146     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
147     /* No break we continue flow */
148   case OPC_STATE_INIT:
149     GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
150     GNUNET_free (opc->data);
151     break;
152   case OPC_STATE_FINISHED:
153     break;
154   }
155   GNUNET_free (opc);
156 }
157
158
159 /**
160  * Function called when a peer destroy operation is ready
161  *
162  * @param cls the closure from GNUNET_TESTBED_operation_create_()
163  */
164 static void
165 opstart_peer_destroy (void *cls)
166 {
167   struct OperationContext *opc = cls;
168   struct GNUNET_TESTBED_Peer *peer = opc->data;
169   struct GNUNET_TESTBED_PeerDestroyMessage *msg;
170   struct GNUNET_MQ_Envelope *env;
171
172   GNUNET_assert (OP_PEER_DESTROY == opc->type);
173   GNUNET_assert (NULL != peer);
174   opc->state = OPC_STATE_STARTED;
175   env = GNUNET_MQ_msg (msg,
176                        GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
177   msg->peer_id = htonl (peer->unique_id);
178   msg->operation_id = GNUNET_htonll (opc->id);
179   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
180   GNUNET_MQ_send (peer->controller->mq,
181                   env);
182 }
183
184
185 /**
186  * Callback which will be called when peer_create type operation is released
187  *
188  * @param cls the closure from GNUNET_TESTBED_operation_create_()
189  */
190 static void
191 oprelease_peer_destroy (void *cls)
192 {
193   struct OperationContext *opc = cls;
194
195   switch (opc->state)
196   {
197   case OPC_STATE_STARTED:
198     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
199     /* no break; continue */
200   case OPC_STATE_INIT:
201     break;
202   case OPC_STATE_FINISHED:
203     break;
204   }
205   GNUNET_free (opc);
206 }
207
208
209 /**
210  * Function called when a peer start operation is ready
211  *
212  * @param cls the closure from GNUNET_TESTBED_operation_create_()
213  */
214 static void
215 opstart_peer_start (void *cls)
216 {
217   struct OperationContext *opc = cls;
218   struct GNUNET_TESTBED_PeerStartMessage *msg;
219   struct GNUNET_MQ_Envelope *env;
220   struct PeerEventData *data;
221   struct GNUNET_TESTBED_Peer *peer;
222
223   GNUNET_assert (OP_PEER_START == opc->type);
224   GNUNET_assert (NULL != (data = opc->data));
225   GNUNET_assert (NULL != (peer = data->peer));
226   GNUNET_assert ((TESTBED_PS_CREATED == peer->state) || (TESTBED_PS_STOPPED == peer->state));
227   opc->state = OPC_STATE_STARTED;
228   env = GNUNET_MQ_msg (msg,
229                        GNUNET_MESSAGE_TYPE_TESTBED_START_PEER);
230   msg->peer_id = htonl (peer->unique_id);
231   msg->operation_id = GNUNET_htonll (opc->id);
232   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
233   GNUNET_MQ_send (peer->controller->mq,
234                   env);
235 }
236
237
238 /**
239  * Callback which will be called when peer start type operation is released
240  *
241  * @param cls the closure from GNUNET_TESTBED_operation_create_()
242  */
243 static void
244 oprelease_peer_start (void *cls)
245 {
246   struct OperationContext *opc = cls;
247
248   switch (opc->state)
249   {
250   case OPC_STATE_STARTED:
251     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
252     /* no break; continue */
253   case OPC_STATE_INIT:
254     GNUNET_free (opc->data);
255     break;
256   case OPC_STATE_FINISHED:
257     break;
258   }
259   GNUNET_free (opc);
260 }
261
262
263 /**
264  * Function called when a peer stop operation is ready
265  *
266  * @param cls the closure from GNUNET_TESTBED_operation_create_()
267  */
268 static void
269 opstart_peer_stop (void *cls)
270 {
271   struct OperationContext *opc = cls;
272   struct GNUNET_TESTBED_PeerStopMessage *msg;
273   struct PeerEventData *data;
274   struct GNUNET_TESTBED_Peer *peer;
275   struct GNUNET_MQ_Envelope *env;
276
277   GNUNET_assert (NULL != (data = opc->data));
278   GNUNET_assert (NULL != (peer = data->peer));
279   GNUNET_assert (TESTBED_PS_STARTED == peer->state);
280   opc->state = OPC_STATE_STARTED;
281   env = GNUNET_MQ_msg (msg,
282                        GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER);
283   msg->peer_id = htonl (peer->unique_id);
284   msg->operation_id = GNUNET_htonll (opc->id);
285   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
286   GNUNET_MQ_send (peer->controller->mq,
287                   env);
288 }
289
290
291 /**
292  * Callback which will be called when peer stop type operation is released
293  *
294  * @param cls the closure from GNUNET_TESTBED_operation_create_()
295  */
296 static void
297 oprelease_peer_stop (void *cls)
298 {
299   struct OperationContext *opc = cls;
300
301   switch (opc->state)
302   {
303   case OPC_STATE_STARTED:
304     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
305     /* no break; continue */
306   case OPC_STATE_INIT:
307     GNUNET_free (opc->data);
308     break;
309   case OPC_STATE_FINISHED:
310     break;
311   }
312   GNUNET_free (opc);
313 }
314
315
316 /**
317  * Generate PeerGetConfigurationMessage
318  *
319  * @param peer_id the id of the peer whose information we have to get
320  * @param operation_id the ip of the operation that should be represented in the
321  *          message
322  * @return the PeerGetConfigurationMessage
323  */
324 struct GNUNET_TESTBED_PeerGetConfigurationMessage *
325 GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
326                                             uint64_t operation_id)
327 {
328   struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
329
330   msg =
331       GNUNET_malloc (sizeof
332                      (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
333   msg->header.size =
334       htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
335   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION);
336   msg->peer_id = htonl (peer_id);
337   msg->operation_id = GNUNET_htonll (operation_id);
338   return msg;
339 }
340
341
342 /**
343  * Function called when a peer get information operation is ready
344  *
345  * @param cls the closure from GNUNET_TESTBED_operation_create_()
346  */
347 static void
348 opstart_peer_getinfo (void *cls)
349 {
350   struct OperationContext *opc = cls;
351   struct PeerInfoData *data = opc->data;
352   struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
353
354   GNUNET_assert (NULL != data);
355   opc->state = OPC_STATE_STARTED;
356   msg =
357       GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id,
358                                                   opc->id);
359   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
360   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
361 }
362
363
364 /**
365  * Callback which will be called when peer stop type operation is released
366  *
367  * @param cls the closure from GNUNET_TESTBED_operation_create_()
368  */
369 static void
370 oprelease_peer_getinfo (void *cls)
371 {
372   struct OperationContext *opc = cls;
373   struct GNUNET_TESTBED_PeerInformation *data;
374
375   switch (opc->state)
376   {
377   case OPC_STATE_STARTED:
378     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
379     /* no break; continue */
380   case OPC_STATE_INIT:
381     GNUNET_free (opc->data);
382     break;
383   case OPC_STATE_FINISHED:
384     data = opc->data;
385     GNUNET_assert (NULL != data);
386     switch (data->pit)
387     {
388     case GNUNET_TESTBED_PIT_CONFIGURATION:
389       if (NULL != data->result.cfg)
390         GNUNET_CONFIGURATION_destroy (data->result.cfg);
391       break;
392     case GNUNET_TESTBED_PIT_IDENTITY:
393       GNUNET_free (data->result.id);
394       break;
395     default:
396       GNUNET_assert (0);        /* We should never reach here */
397     }
398     GNUNET_free (data);
399     break;
400   }
401   GNUNET_free (opc);
402 }
403
404
405 /**
406  * Function called when a overlay connect operation is ready
407  *
408  * @param cls the closure from GNUNET_TESTBED_operation_create_()
409  */
410 static void
411 opstart_overlay_connect (void *cls)
412 {
413   struct OperationContext *opc = cls;
414   struct GNUNET_MQ_Envelope *env;
415   struct GNUNET_TESTBED_OverlayConnectMessage *msg;
416   struct OverlayConnectData *data;
417
418   opc->state = OPC_STATE_STARTED;
419   data = opc->data;
420   GNUNET_assert (NULL != data);
421   env = GNUNET_MQ_msg (msg,
422                        GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT);
423   msg->peer1 = htonl (data->p1->unique_id);
424   msg->peer2 = htonl (data->p2->unique_id);
425   msg->operation_id = GNUNET_htonll (opc->id);
426   msg->peer2_host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->p2->host));
427   GNUNET_TESTBED_insert_opc_ (opc->c,
428                               opc);
429   GNUNET_MQ_send (opc->c->mq,
430                   env);
431 }
432
433
434 /**
435  * Callback which will be called when overlay connect operation is released
436  *
437  * @param cls the closure from GNUNET_TESTBED_operation_create_()
438  */
439 static void
440 oprelease_overlay_connect (void *cls)
441 {
442   struct OperationContext *opc = cls;
443   struct OverlayConnectData *data;
444
445   data = opc->data;
446   switch (opc->state)
447   {
448   case OPC_STATE_INIT:
449     break;
450   case OPC_STATE_STARTED:
451     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
452     break;
453   case OPC_STATE_FINISHED:
454     break;
455   }
456   GNUNET_free (data);
457   GNUNET_free (opc);
458 }
459
460
461 /**
462  * Function called when a peer reconfigure operation is ready
463  *
464  * @param cls the closure from GNUNET_TESTBED_operation_create_()
465  */
466 static void
467 opstart_peer_reconfigure (void *cls)
468 {
469   struct OperationContext *opc = cls;
470   struct PeerReconfigureData *data = opc->data;
471   struct GNUNET_MQ_Envelope *env;
472   struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
473   char *xconfig;
474   size_t xc_size;
475
476   opc->state = OPC_STATE_STARTED;
477   GNUNET_assert (NULL != data);
478   xc_size = GNUNET_TESTBED_compress_config_ (data->config,
479                                              data->cfg_size,
480                                              &xconfig);
481   GNUNET_free (data->config);
482   data->config = NULL;
483   GNUNET_assert (xc_size < UINT16_MAX - sizeof (*msg));
484   env = GNUNET_MQ_msg_extra (msg,
485                              xc_size,
486                              GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER);
487   msg->peer_id = htonl (data->peer->unique_id);
488   msg->operation_id = GNUNET_htonll (opc->id);
489   msg->config_size = htons (data->cfg_size);
490   GNUNET_memcpy (&msg[1],
491           xconfig,
492           xc_size);
493   GNUNET_free (xconfig);
494   GNUNET_free (data);
495   opc->data = NULL;
496   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
497   GNUNET_MQ_send (opc->c->mq,
498                   env);
499 }
500
501
502 /**
503  * Callback which will be called when a peer reconfigure operation is released
504  *
505  * @param cls the closure from GNUNET_TESTBED_operation_create_()
506  */
507 static void
508 oprelease_peer_reconfigure (void *cls)
509 {
510   struct OperationContext *opc = cls;
511   struct PeerReconfigureData *data = opc->data;
512
513   switch (opc->state)
514   {
515   case OPC_STATE_INIT:
516     GNUNET_free (data->config);
517     GNUNET_free (data);
518     break;
519   case OPC_STATE_STARTED:
520     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
521     break;
522   case OPC_STATE_FINISHED:
523     break;
524   }
525   GNUNET_free (opc);
526 }
527
528
529 /**
530  * Lookup a peer by ID.
531  *
532  * @param id global peer ID assigned to the peer
533  * @return handle to the host, NULL on error
534  */
535 struct GNUNET_TESTBED_Peer *
536 GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
537 {
538   GNUNET_break (0);
539   return NULL;
540 }
541
542
543 /**
544  * Create the given peer at the specified host using the given
545  * controller.  If the given controller is not running on the target
546  * host, it should find or create a controller at the target host and
547  * delegate creating the peer.  Explicit delegation paths can be setup
548  * using 'GNUNET_TESTBED_controller_link'.  If no explicit delegation
549  * path exists, a direct link with a subordinate controller is setup
550  * for the first delegated peer to a particular host; the subordinate
551  * controller is then destroyed once the last peer that was delegated
552  * to the remote host is stopped.
553  *
554  * Creating the peer only creates the handle to manipulate and further
555  * configure the peer; use "GNUNET_TESTBED_peer_start" and
556  * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
557  * processes.
558  *
559  * Note that the given configuration will be adjusted by the
560  * controller to avoid port/path conflicts with other peers.
561  * The "final" configuration can be obtained using
562  * 'GNUNET_TESTBED_peer_get_information'.
563  *
564  * @param controller controller process to use
565  * @param host host to run the peer on; cannot be NULL
566  * @param cfg Template configuration to use for the peer. Should exist until
567  *          operation is cancelled or GNUNET_TESTBED_operation_done() is called
568  * @param cb the callback to call when the peer has been created
569  * @param cls the closure to the above callback
570  * @return the operation handle
571  */
572 struct GNUNET_TESTBED_Operation *
573 GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller,
574                             struct GNUNET_TESTBED_Host *host,
575                             const struct GNUNET_CONFIGURATION_Handle *cfg,
576                             GNUNET_TESTBED_PeerCreateCallback cb, void *cls)
577 {
578
579   struct GNUNET_TESTBED_Peer *peer;
580   struct PeerCreateData *data;
581   struct OperationContext *opc;
582   static uint32_t id_gen;
583
584   peer = GNUNET_new (struct GNUNET_TESTBED_Peer);
585   peer->controller = controller;
586   peer->host = host;
587   peer->unique_id = id_gen++;
588   peer->state = TESTBED_PS_INVALID;
589   data = GNUNET_new (struct PeerCreateData);
590   data->host = host;
591   data->cfg = cfg;
592   data->cb = cb;
593   data->cls = cls;
594   data->peer = peer;
595   opc = GNUNET_new (struct OperationContext);
596   opc->c = controller;
597   opc->data = data;
598   opc->id = GNUNET_TESTBED_get_next_op_id (controller);
599   opc->type = OP_PEER_CREATE;
600   opc->op =
601       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create,
602                                         &oprelease_peer_create);
603   GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations,
604                                           opc->op);
605   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
606   return opc->op;
607 }
608
609
610 /**
611  * Start the given peer.
612  *
613  * @param op_cls the closure for this operation; will be set in
614  *          event->details.operation_finished.op_cls when this operation fails.
615  * @param peer peer to start
616  * @param pcc function to call upon completion
617  * @param pcc_cls closure for 'pcc'
618  * @return handle to the operation
619  */
620 struct GNUNET_TESTBED_Operation *
621 GNUNET_TESTBED_peer_start (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
622                            GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
623 {
624   struct OperationContext *opc;
625   struct PeerEventData *data;
626
627   data = GNUNET_new (struct PeerEventData);
628   data->peer = peer;
629   data->pcc = pcc;
630   data->pcc_cls = pcc_cls;
631   opc = GNUNET_new (struct OperationContext);
632   opc->c = peer->controller;
633   opc->data = data;
634   opc->op_cls = op_cls;
635   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
636   opc->type = OP_PEER_START;
637   opc->op =
638       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_start,
639                                         &oprelease_peer_start);
640   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
641                                           opc->op);
642   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
643   return opc->op;
644 }
645
646
647 /**
648  * Stop the given peer.  The handle remains valid (use
649  * "GNUNET_TESTBED_peer_destroy" to fully clean up the
650  * state of the peer).
651  *
652  * @param op_cls the closure for this operation; will be set in the event
653  *          information
654  * @param peer peer to stop
655  * @param pcc function to call upon completion
656  * @param pcc_cls closure for 'pcc'
657  * @return handle to the operation
658  */
659 struct GNUNET_TESTBED_Operation *
660 GNUNET_TESTBED_peer_stop (void *op_cls,
661                           struct GNUNET_TESTBED_Peer *peer,
662                           GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
663 {
664   struct OperationContext *opc;
665   struct PeerEventData *data;
666
667   data = GNUNET_new (struct PeerEventData);
668   data->peer = peer;
669   data->pcc = pcc;
670   data->pcc_cls = pcc_cls;
671   opc = GNUNET_new (struct OperationContext);
672   opc->c = peer->controller;
673   opc->data = data;
674   opc->op_cls = op_cls;
675   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
676   opc->type = OP_PEER_STOP;
677   opc->op =
678       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop,
679                                         &oprelease_peer_stop);
680   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
681                                           opc->op);
682   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
683   return opc->op;
684 }
685
686
687 /**
688  * Request information about a peer. The controller callback will not be called
689  * with event type GNUNET_TESTBED_ET_OPERATION_FINISHED when result for this
690  * operation is available. Instead, the GNUNET_TESTBED_PeerInfoCallback() will
691  * be called.
692  * The peer information in the callback is valid until the operation is canceled.
693  *
694  * @param peer peer to request information about
695  * @param pit desired information
696  * @param cb the convenience callback to be called when results for this
697  *          operation are available
698  * @param cb_cls the closure for the above callback
699  * @return handle to the operation
700  */
701 struct GNUNET_TESTBED_Operation *
702 GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
703                                      enum GNUNET_TESTBED_PeerInformationType
704                                      pit, GNUNET_TESTBED_PeerInfoCallback cb,
705                                      void *cb_cls)
706 {
707   struct OperationContext *opc;
708   struct PeerInfoData *data;
709
710   GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit);
711   GNUNET_assert (NULL != cb);
712   data = GNUNET_new (struct PeerInfoData);
713   data->peer = peer;
714   data->pit = pit;
715   data->cb = cb;
716   data->cb_cls = cb_cls;
717   opc = GNUNET_new (struct OperationContext);
718   opc->c = peer->controller;
719   opc->data = data;
720   opc->type = OP_PEER_INFO;
721   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
722   opc->op =
723       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo,
724                                         &oprelease_peer_getinfo);
725   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
726                                           opc->op);
727   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
728   return opc->op;
729 }
730
731
732 /**
733  * Change peer configuration.  Must only be called while the
734  * peer is stopped.  Ports and paths cannot be changed this
735  * way.
736  *
737  * @param peer peer to change configuration for
738  * @param cfg new configuration (differences to existing
739  *            configuration only)
740  * @return handle to the operation
741  */
742 struct GNUNET_TESTBED_Operation *
743 GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
744                                           const struct
745                                           GNUNET_CONFIGURATION_Handle *cfg)
746 {
747   struct OperationContext *opc;
748   struct PeerReconfigureData *data;
749   size_t csize;
750
751   data = GNUNET_new (struct PeerReconfigureData);
752   data->peer = peer;
753   data->config = GNUNET_CONFIGURATION_serialize (cfg, &csize);
754   if (NULL == data->config)
755   {
756     GNUNET_free (data);
757     return NULL;
758   }
759   if (csize > UINT16_MAX)
760   {
761     GNUNET_break (0);
762     GNUNET_free (data->config);
763     GNUNET_free (data);
764     return NULL;
765   }
766   data->cfg_size = (uint16_t) csize;
767   opc = GNUNET_new (struct OperationContext);
768   opc->c = peer->controller;
769   opc->data = data;
770   opc->type = OP_PEER_RECONFIGURE;
771   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
772   opc->op =
773       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_reconfigure,
774                                         &oprelease_peer_reconfigure);
775   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
776                                           opc->op);
777   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
778   return opc->op;
779 }
780
781
782 /**
783  * Destroy the given peer; the peer should have been
784  * stopped first (if it was started).
785  *
786  * @param peer peer to stop
787  * @return handle to the operation
788  */
789 struct GNUNET_TESTBED_Operation *
790 GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer)
791 {
792   struct OperationContext *opc;
793
794   opc = GNUNET_new (struct OperationContext);
795   opc->data = peer;
796   opc->c = peer->controller;
797   opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller);
798   opc->type = OP_PEER_DESTROY;
799   opc->op =
800       GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy,
801                                         &oprelease_peer_destroy);
802   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
803                                           opc->op);
804   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
805   return opc->op;
806 }
807
808
809 /**
810  * Manipulate the P2P underlay topology by configuring a link
811  * between two peers.
812  *
813  * @param op_cls closure argument to give with the operation event
814  * @param p1 first peer
815  * @param p2 second peer
816  * @param co option to change
817  * @param ... option-specific values
818  * @return handle to the operation, NULL if configuring the link at this
819  *         time is not allowed
820  */
821 struct GNUNET_TESTBED_Operation *
822 GNUNET_TESTBED_underlay_configure_link (void *op_cls,
823                                         struct GNUNET_TESTBED_Peer *p1,
824                                         struct GNUNET_TESTBED_Peer *p2,
825                                         enum GNUNET_TESTBED_ConnectOption co,
826                                         ...)
827 {
828   GNUNET_break (0);
829   return NULL;
830 }
831
832
833 /**
834  * Both peers must have been started before calling this function.
835  * This function then obtains a HELLO from 'p1', gives it to 'p2'
836  * and asks 'p2' to connect to 'p1'.
837  *
838  * @param op_cls closure argument to give with the operation event
839  * @param cb the callback to call when this operation has finished
840  * @param cb_cls the closure for the above callback
841  * @param p1 first peer
842  * @param p2 second peer
843  * @return handle to the operation, NULL if connecting these two
844  *         peers is fundamentally not possible at this time (peers
845  *         not running or underlay disallows)
846  */
847 struct GNUNET_TESTBED_Operation *
848 GNUNET_TESTBED_overlay_connect (void *op_cls,
849                                 GNUNET_TESTBED_OperationCompletionCallback cb,
850                                 void *cb_cls, struct GNUNET_TESTBED_Peer *p1,
851                                 struct GNUNET_TESTBED_Peer *p2)
852 {
853   struct OperationContext *opc;
854   struct OverlayConnectData *data;
855
856   GNUNET_assert ((TESTBED_PS_STARTED == p1->state) && (TESTBED_PS_STARTED == p2->state));
857   data = GNUNET_new (struct OverlayConnectData);
858   data->p1 = p1;
859   data->p2 = p2;
860   data->cb = cb;
861   data->cb_cls = cb_cls;
862   opc = GNUNET_new (struct OperationContext);
863   opc->data = data;
864   opc->c = p1->controller;
865   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
866   opc->type = OP_OVERLAY_CONNECT;
867   opc->op_cls = op_cls;
868   opc->op =
869       GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
870                                         &oprelease_overlay_connect);
871   GNUNET_TESTBED_host_queue_oc_ (p1->host, opc->op);
872   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
873   return opc->op;
874 }
875
876
877 /**
878  * Function called when a peer manage service operation is ready
879  *
880  * @param cls the closure from GNUNET_TESTBED_operation_create_()
881  */
882 static void
883 opstart_manage_service (void *cls)
884 {
885   struct OperationContext *opc = cls;
886   struct ManageServiceData *data = opc->data;
887   struct GNUNET_MQ_Envelope *env;
888   struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
889   size_t xlen;
890
891   GNUNET_assert (NULL != data);
892   xlen = data->msize - sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage);
893   env = GNUNET_MQ_msg_extra (msg,
894                              xlen,
895                              GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE);
896   msg->peer_id = htonl (data->peer->unique_id);
897   msg->operation_id = GNUNET_htonll (opc->id);
898   msg->start = (uint8_t) data->start;
899   GNUNET_memcpy (&msg[1],
900           data->service_name,
901           xlen);
902   GNUNET_free (data->service_name);
903   data->service_name = NULL;
904   opc->state = OPC_STATE_STARTED;
905   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
906   GNUNET_MQ_send (opc->c->mq,
907                   env);
908 }
909
910
911 /**
912  * Callback which will be called when peer manage server operation is released
913  *
914  * @param cls the closure from GNUNET_TESTBED_operation_create_()
915  */
916 static void
917 oprelease_manage_service (void *cls)
918 {
919   struct OperationContext *opc = cls;
920   struct ManageServiceData *data;
921
922   data = opc->data;
923   switch (opc->state)
924   {
925   case OPC_STATE_STARTED:
926     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
927     break;
928   case OPC_STATE_INIT:
929     GNUNET_assert (NULL != data);
930     GNUNET_free (data->service_name);
931     break;
932   case OPC_STATE_FINISHED:
933     break;
934   }
935   GNUNET_free_non_null (data);
936   GNUNET_free (opc);
937 }
938
939
940 /**
941  * Start or stop given service at a peer.  This should not be called to
942  * start/stop the peer's ARM service.  Use GNUNET_TESTBED_peer_start(),
943  * GNUNET_TESTBED_peer_stop() for starting/stopping peer's ARM service.  Success
944  * or failure of the generated operation is signalled through the controller
945  * event callback and/or operation completion callback.
946  *
947  * @param op_cls the closure for the operation
948  * @param peer the peer whose service is to be started/stopped
949  * @param service_name the name of the service
950  * @param cb the operation completion callback
951  * @param cb_cls the closure for the operation completion callback
952  * @param start 1 to start the service; 0 to stop the service
953  * @return an operation handle; NULL upon error (peer not running)
954  */
955 struct GNUNET_TESTBED_Operation *
956 GNUNET_TESTBED_peer_manage_service (void *op_cls,
957                                     struct GNUNET_TESTBED_Peer *peer,
958                                     const char *service_name,
959                                     GNUNET_TESTBED_OperationCompletionCallback cb,
960                                     void *cb_cls,
961                                     unsigned int start)
962 {
963   struct ManageServiceData *data;
964   struct OperationContext *opc;
965   size_t msize;
966
967   GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */
968   msize = strlen (service_name) + 1;
969   msize += sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage);
970   if (GNUNET_MAX_MESSAGE_SIZE < msize)
971     return NULL;
972   data = GNUNET_new (struct ManageServiceData);
973   data->cb = cb;
974   data->cb_cls = cb_cls;
975   data->peer = peer;
976   data->service_name = GNUNET_strdup (service_name);
977   data->start = start;
978   data->msize = (uint16_t) msize;
979   opc = GNUNET_new (struct OperationContext);
980   opc->data = data;
981   opc->c = peer->controller;
982   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
983   opc->type = OP_MANAGE_SERVICE;
984   opc->op_cls = op_cls;
985   opc->op =
986       GNUNET_TESTBED_operation_create_ (opc, &opstart_manage_service,
987                                         &oprelease_manage_service);
988   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
989                                           opc->op);
990   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
991   return opc->op;
992 }
993
994
995
996 /* end of testbed_api_peers.c */