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