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