2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file testbed/testbed_api.c
23 * @brief API for accessing the GNUnet testing service.
24 * This library is supposed to make it easier to write
25 * testcases and script large-scale benchmarks.
26 * @author Christian Grothoff
27 * @author Sree Harsha Totakura
30 #include "gnunet_testbed_service.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_hello_lib.h"
38 #include "testbed_api.h"
39 #include "testbed_api_hosts.h"
40 #include "testbed_api_peers.h"
41 #include "testbed_api_operations.h"
42 #include "testbed_api_sd.h"
45 * Generic logging shorthand
47 #define LOG(kind, ...) GNUNET_log_from (kind, "testbed-api", __VA_ARGS__)
52 #define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
55 * Relative time seconds shorthand
57 #define TIME_REL_SECS(sec) \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
62 * Default server message sending retry timeout
64 #define TIMEOUT_REL TIME_REL_SECS (1)
68 * Context data for forwarded Operation
70 struct ForwardedOperationData
73 * The callback to call when reply is available
75 GNUNET_MQ_MessageCallback cc;
78 * The closure for the above callback
85 * Context data for get slave config operations
87 struct GetSlaveConfigData
90 * The id of the slave controller
97 * Context data for controller link operations
99 struct ControllerLinkData
102 * The controller link message
104 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
107 * The id of the host which is hosting the controller to be linked
114 * Date context for OP_SHUTDOWN_PEERS operations
116 struct ShutdownPeersData
119 * The operation completion callback to call
121 GNUNET_TESTBED_OperationCompletionCallback cb;
124 * The closure for the above callback
131 * An entry in the stack for keeping operations which are about to expire
133 struct ExpireOperationEntry
136 * DLL head; new entries are to be inserted here
138 struct ExpireOperationEntry *next;
141 * DLL tail; entries are deleted from here
143 struct ExpireOperationEntry *prev;
146 * The operation. This will be a dangling pointer when the operation is freed
148 const struct GNUNET_TESTBED_Operation *op;
153 * DLL head for list of operations marked for expiry
155 static struct ExpireOperationEntry *exop_head;
158 * DLL tail for list of operation marked for expiry
160 static struct ExpireOperationEntry *exop_tail;
164 * Inserts an operation into the list of operations marked for expiry
166 * @param op the operation to insert
169 exop_insert (struct GNUNET_TESTBED_Operation *op)
171 struct ExpireOperationEntry *entry;
173 entry = GNUNET_new (struct ExpireOperationEntry);
175 GNUNET_CONTAINER_DLL_insert_tail (exop_head, exop_tail, entry);
180 * Checks if an operation is present in the list of operations marked for
181 * expiry. If the operation is found, it and the tail of operations after it
182 * are removed from the list.
184 * @param op the operation to check
185 * @return GNUNET_NO if the operation is not present in the list; GNUNET_YES if
186 * the operation is found in the list (the operation is then removed
187 * from the list -- calling this function again with the same
188 * paramenter will return GNUNET_NO)
191 exop_check (const struct GNUNET_TESTBED_Operation *const op)
193 struct ExpireOperationEntry *entry;
194 struct ExpireOperationEntry *entry2;
199 while (NULL != entry)
208 if (GNUNET_NO == found)
210 /* Truncate the tail */
211 while (NULL != entry)
213 entry2 = entry->next;
214 GNUNET_CONTAINER_DLL_remove (exop_head, exop_tail, entry);
223 * Context information to be used while searching for operation contexts
228 * The result of the search
230 struct OperationContext *opc;
233 * The id of the operation context we are searching for
240 * Search iterator for searching an operation context
242 * @param cls the serach context
243 * @param key current key code
244 * @param value value in the hash map
245 * @return #GNUNET_YES if we should continue to iterate,
249 opc_search_iterator (void *cls, uint32_t key, void *value)
251 struct SearchContext *sc = cls;
252 struct OperationContext *opc = value;
254 GNUNET_assert (NULL != opc);
255 GNUNET_assert (NULL == sc->opc);
256 if (opc->id != sc->id)
264 * Returns the operation context with the given id if found in the Operation
265 * context queues of the controller
267 * @param c the controller whose operation context map is searched
268 * @param id the id which has to be checked
269 * @return the matching operation context; NULL if no match found
271 static struct OperationContext *
272 find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
274 struct SearchContext sc;
278 GNUNET_assert (NULL != c->opc_map);
280 GNUNET_CONTAINER_multihashmap32_get_multiple (c->opc_map,
282 &opc_search_iterator,
290 * Inserts the given operation context into the operation context map of the
291 * given controller. Creates the operation context map if one does not exist
294 * @param c the controller
295 * @param opc the operation context to be inserted
298 GNUNET_TESTBED_insert_opc_ (struct GNUNET_TESTBED_Controller *c,
299 struct OperationContext *opc)
301 if (NULL == c->opc_map)
302 c->opc_map = GNUNET_CONTAINER_multihashmap32_create (256);
303 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap32_put (
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
312 * Removes the given operation context from the operation context map of the
315 * @param c the controller
316 * @param opc the operation context to remove
319 GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
320 struct OperationContext *opc)
322 GNUNET_assert (NULL != c->opc_map);
323 GNUNET_assert (GNUNET_YES ==
324 GNUNET_CONTAINER_multihashmap32_remove (c->opc_map,
327 if ((0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map)) &&
328 (NULL != c->opcq_empty_cb))
329 c->opcq_empty_cb (c->opcq_empty_cls);
334 * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message is well-formed.
336 * @param cls the controller handler
337 * @param msg message received
338 * @return #GNUNET_OK if message is well-formed
341 check_add_host_confirm (void *cls,
342 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
347 msg_size = ntohs (msg->header.size) - sizeof(*msg);
350 /* We have an error message */
351 emsg = (const char *) &msg[1];
352 if ('\0' != emsg[msg_size - 1])
355 return GNUNET_SYSERR;
362 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
363 * controller (testbed service)
365 * @param cls the controller handler
366 * @param msg message received
369 handle_add_host_confirm (void *cls,
370 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
372 struct GNUNET_TESTBED_Controller *c = cls;
373 struct GNUNET_TESTBED_HostRegistrationHandle *rh = c->rh;
379 if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
381 LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
382 GNUNET_TESTBED_host_get_id_ (rh->host),
383 ntohl (msg->host_id));
387 msg_size = ntohs (msg->header.size) - sizeof(*msg);
390 LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
391 GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
392 rh->cc (rh->cc_cls, NULL);
396 /* We have an error message */
397 emsg = (const char *) &msg[1];
398 LOG (GNUNET_ERROR_TYPE_ERROR,
399 _ ("Adding host %u failed with error: %s\n"),
400 ntohl (msg->host_id),
402 rh->cc (rh->cc_cls, emsg);
408 * Handler for forwarded operations
410 * @param c the controller handle
411 * @param opc the opearation context
412 * @param msg the message
415 handle_forwarded_operation_msg (void *cls,
416 struct OperationContext *opc,
417 const struct GNUNET_MessageHeader *msg)
419 struct GNUNET_TESTBED_Controller *c = cls;
420 struct ForwardedOperationData *fo_data;
423 if (NULL != fo_data->cc)
424 fo_data->cc (fo_data->cc_cls, msg);
425 GNUNET_TESTBED_remove_opc_ (c, opc);
426 GNUNET_free (fo_data);
432 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS message from
433 * controller (testbed service)
435 * @param c the controller handler
436 * @param msg message received
441 const struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
443 struct GNUNET_TESTBED_Controller *c = cls;
444 struct OperationContext *opc;
445 GNUNET_TESTBED_OperationCompletionCallback op_comp_cb;
446 void *op_comp_cb_cls;
447 struct GNUNET_TESTBED_EventInformation event;
450 op_id = GNUNET_ntohll (msg->operation_id);
451 LOG_DEBUG ("Operation %lu successful\n", op_id);
452 if (NULL == (opc = find_opc (c, op_id)))
454 LOG_DEBUG ("Operation not found\n");
457 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
459 event.op_cls = opc->op_cls;
460 event.details.operation_finished.emsg = NULL;
461 event.details.operation_finished.generic = NULL;
463 op_comp_cb_cls = NULL;
467 handle_forwarded_operation_msg (c,
470 GNUNET_MessageHeader *) msg);
475 case OP_PEER_DESTROY: {
476 struct GNUNET_TESTBED_Peer *peer;
479 GNUNET_TESTBED_peer_deregister_ (peer);
486 case OP_SHUTDOWN_PEERS: {
487 struct ShutdownPeersData *data;
490 op_comp_cb = data->cb;
491 op_comp_cb_cls = data->cb_cls;
494 GNUNET_TESTBED_cleanup_peers_ ();
498 case OP_MANAGE_SERVICE: {
499 struct ManageServiceData *data;
501 GNUNET_assert (NULL != (data = opc->data));
502 op_comp_cb = data->cb;
503 op_comp_cb_cls = data->cb_cls;
509 case OP_PEER_RECONFIGURE:
515 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
516 opc->state = OPC_STATE_FINISHED;
517 exop_insert (event.op);
518 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
521 c->cc (c->cc_cls, &event);
522 if (GNUNET_NO == exop_check (event.op))
526 LOG_DEBUG ("Not calling callback\n");
527 if (NULL != op_comp_cb)
528 op_comp_cb (op_comp_cb_cls, event.op, NULL);
529 /* You could have marked the operation as done by now */
530 GNUNET_break (GNUNET_NO == exop_check (event.op));
535 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS message from
536 * controller (testbed service)
538 * @param c the controller handle
539 * @param msg message received
542 handle_peer_create_success (
544 const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
546 struct GNUNET_TESTBED_Controller *c = cls;
547 struct OperationContext *opc;
548 struct PeerCreateData *data;
549 struct GNUNET_TESTBED_Peer *peer;
550 struct GNUNET_TESTBED_Operation *op;
551 GNUNET_TESTBED_PeerCreateCallback cb;
555 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
556 ntohs (msg->header.size));
557 op_id = GNUNET_ntohll (msg->operation_id);
558 if (NULL == (opc = find_opc (c, op_id)))
560 LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
563 if (OP_FORWARDED == opc->type)
565 handle_forwarded_operation_msg (c,
567 (const struct GNUNET_MessageHeader *) msg);
570 GNUNET_assert (OP_PEER_CREATE == opc->type);
571 GNUNET_assert (NULL != opc->data);
573 GNUNET_assert (NULL != data->peer);
575 GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
576 peer->state = TESTBED_PS_CREATED;
577 GNUNET_TESTBED_peer_register_ (peer);
581 GNUNET_free (opc->data);
582 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
583 opc->state = OPC_STATE_FINISHED;
586 cb (cb_cls, peer, NULL);
587 /* You could have marked the operation as done by now */
588 GNUNET_break (GNUNET_NO == exop_check (op));
593 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT message from
594 * controller (testbed service)
596 * @param c the controller handler
597 * @param msg message received
600 handle_peer_event (void *cls, const struct GNUNET_TESTBED_PeerEventMessage *msg)
602 struct GNUNET_TESTBED_Controller *c = cls;
603 struct OperationContext *opc;
604 struct GNUNET_TESTBED_Peer *peer;
605 struct PeerEventData *data;
606 GNUNET_TESTBED_PeerChurnCallback pcc;
608 struct GNUNET_TESTBED_EventInformation event;
612 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerEventMessage) ==
613 ntohs (msg->header.size));
614 op_id = GNUNET_ntohll (msg->operation_id);
615 if (NULL == (opc = find_opc (c, op_id)))
617 LOG_DEBUG ("Operation not found\n");
620 if (OP_FORWARDED == opc->type)
622 handle_forwarded_operation_msg (c,
624 (const struct GNUNET_MessageHeader *) msg);
627 GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
629 GNUNET_assert (NULL != data);
631 GNUNET_assert (NULL != peer);
632 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
634 event.op_cls = opc->op_cls;
637 case GNUNET_TESTBED_ET_PEER_START:
638 peer->state = TESTBED_PS_STARTED;
639 event.details.peer_start.host = peer->host;
640 event.details.peer_start.peer = peer;
643 case GNUNET_TESTBED_ET_PEER_STOP:
644 peer->state = TESTBED_PS_STOPPED;
645 event.details.peer_stop.peer = peer;
649 GNUNET_assert (0); /* We should never reach this state */
652 pcc_cls = data->pcc_cls;
654 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
655 opc->state = OPC_STATE_FINISHED;
656 exop_insert (event.op);
657 mask = 1LL << GNUNET_TESTBED_ET_PEER_START;
658 mask |= 1LL << GNUNET_TESTBED_ET_PEER_STOP;
659 if (0 != (mask & c->event_mask))
662 c->cc (c->cc_cls, &event);
663 if (GNUNET_NO == exop_check (event.op))
668 /* You could have marked the operation as done by now */
669 GNUNET_break (GNUNET_NO == exop_check (event.op));
674 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT message from
675 * controller (testbed service)
677 * @param c the controller handler
678 * @param msg message received
681 handle_peer_conevent (void *cls,
682 const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
684 struct GNUNET_TESTBED_Controller *c = cls;
685 struct OperationContext *opc;
686 struct OverlayConnectData *data;
687 GNUNET_TESTBED_OperationCompletionCallback cb;
689 struct GNUNET_TESTBED_EventInformation event;
693 op_id = GNUNET_ntohll (msg->operation_id);
694 if (NULL == (opc = find_opc (c, op_id)))
696 LOG_DEBUG ("Operation not found\n");
699 if (OP_FORWARDED == opc->type)
701 handle_forwarded_operation_msg (c,
703 (const struct GNUNET_MessageHeader *) msg);
706 GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
707 GNUNET_assert (NULL != (data = opc->data));
708 GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
709 (ntohl (msg->peer2) == data->p2->unique_id));
710 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
712 event.op_cls = opc->op_cls;
715 case GNUNET_TESTBED_ET_CONNECT:
716 event.details.peer_connect.peer1 = data->p1;
717 event.details.peer_connect.peer2 = data->p2;
720 case GNUNET_TESTBED_ET_DISCONNECT:
721 GNUNET_assert (0); /* FIXME: implement */
725 GNUNET_assert (0); /* Should never reach here */
729 cb_cls = data->cb_cls;
730 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
731 opc->state = OPC_STATE_FINISHED;
732 exop_insert (event.op);
733 mask = 1LL << GNUNET_TESTBED_ET_CONNECT;
734 mask |= 1LL << GNUNET_TESTBED_ET_DISCONNECT;
735 if (0 != (mask & c->event_mask))
738 c->cc (c->cc_cls, &event);
739 if (GNUNET_NO == exop_check (event.op))
743 cb (cb_cls, opc->op, NULL);
744 /* You could have marked the operation as done by now */
745 GNUNET_break (GNUNET_NO == exop_check (event.op));
750 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
751 * controller (testbed service)
753 * @param c the controller handler
754 * @param msg message received
759 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
767 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
768 * controller (testbed service)
770 * @param c the controller handler
771 * @param msg message received
776 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
778 struct GNUNET_TESTBED_Controller *c = cls;
779 struct OperationContext *opc;
780 struct GNUNET_TESTBED_Peer *peer;
781 struct PeerInfoData *data;
782 struct GNUNET_TESTBED_PeerInformation *pinfo;
783 GNUNET_TESTBED_PeerInfoCallback cb;
787 op_id = GNUNET_ntohll (msg->operation_id);
788 if (NULL == (opc = find_opc (c, op_id)))
790 LOG_DEBUG ("Operation not found\n");
793 if (OP_FORWARDED == opc->type)
795 handle_forwarded_operation_msg (c, opc, &msg->header);
799 GNUNET_assert (NULL != data);
801 GNUNET_assert (NULL != peer);
802 GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
803 pinfo = GNUNET_new (struct GNUNET_TESTBED_PeerInformation);
804 pinfo->pit = data->pit;
806 cb_cls = data->cb_cls;
807 GNUNET_assert (NULL != cb);
812 case GNUNET_TESTBED_PIT_IDENTITY:
813 pinfo->result.id = GNUNET_new (struct GNUNET_PeerIdentity);
814 GNUNET_memcpy (pinfo->result.id,
816 sizeof(struct GNUNET_PeerIdentity));
819 case GNUNET_TESTBED_PIT_CONFIGURATION:
820 pinfo->result.cfg = /* Freed in oprelease_peer_getinfo */
821 GNUNET_TESTBED_extract_config_ (&msg->header);
824 case GNUNET_TESTBED_PIT_GENERIC:
825 GNUNET_assert (0); /* never reach here */
829 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
830 opc->state = OPC_STATE_FINISHED;
831 cb (cb_cls, opc->op, pinfo, NULL);
832 /* We dont check whether the operation is marked as done here as the
833 operation contains data (cfg/identify) which will be freed at a later point
839 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
840 * controller (testbed service)
842 * @param c the controller handler
843 * @param msg message received
844 * @return #GNUNET_OK if message is well-formed
847 check_op_fail_event (
849 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
851 /* we accept anything as a valid error message */
857 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
858 * controller (testbed service)
860 * @param c the controller handler
861 * @param msg message received
864 handle_op_fail_event (
866 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
868 struct GNUNET_TESTBED_Controller *c = cls;
869 struct OperationContext *opc;
873 struct GNUNET_TESTBED_EventInformation event;
875 op_id = GNUNET_ntohll (msg->operation_id);
876 if (NULL == (opc = find_opc (c, op_id)))
878 LOG_DEBUG ("Operation not found\n");
881 if (OP_FORWARDED == opc->type)
883 handle_forwarded_operation_msg (c,
885 (const struct GNUNET_MessageHeader *) msg);
888 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
889 opc->state = OPC_STATE_FINISHED;
890 emsg = GNUNET_TESTBED_parse_error_string_ (msg);
892 emsg = "Unknown error";
893 if (OP_PEER_INFO == opc->type)
895 struct PeerInfoData *data;
898 if (NULL != data->cb)
899 data->cb (data->cb_cls, opc->op, NULL, emsg);
901 return; /* We do not call controller callback for peer info */
903 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
905 event.op_cls = opc->op_cls;
906 event.details.operation_finished.emsg = emsg;
907 event.details.operation_finished.generic = NULL;
908 mask = (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
909 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
911 exop_insert (event.op);
912 c->cc (c->cc_cls, &event);
913 if (GNUNET_NO == exop_check (event.op))
918 case OP_PEER_CREATE: {
919 struct PeerCreateData *data;
922 GNUNET_free (data->peer);
923 if (NULL != data->cb)
924 data->cb (data->cls, NULL, emsg);
931 struct PeerEventData *data;
934 if (NULL != data->pcc)
935 data->pcc (data->pcc_cls, emsg);
940 case OP_PEER_DESTROY:
946 case OP_OVERLAY_CONNECT: {
947 struct OverlayConnectData *data;
950 GNUNET_TESTBED_operation_mark_failed (opc->op);
951 if (NULL != data->cb)
952 data->cb (data->cb_cls, opc->op, emsg);
959 case OP_LINK_CONTROLLERS: /* No secondary callback */
962 case OP_SHUTDOWN_PEERS: {
963 struct ShutdownPeersData *data;
966 GNUNET_free (data); /* FIXME: Decide whether we call data->op_cb */
971 case OP_MANAGE_SERVICE: {
972 struct ManageServiceData *data = opc->data;
973 GNUNET_TESTBED_OperationCompletionCallback cb;
976 GNUNET_assert (NULL != data);
978 cb_cls = data->cb_cls;
981 exop_insert (event.op);
983 cb (cb_cls, opc->op, emsg);
984 /* You could have marked the operation as done by now */
985 GNUNET_break (GNUNET_NO == exop_check (event.op));
996 * Function to build GET_SLAVE_CONFIG message
998 * @param op_id the id this message should contain in its operation id field
999 * @param slave_id the id this message should contain in its slave id field
1000 * @return newly allocated SlaveGetConfigurationMessage
1002 static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
1003 GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
1005 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1008 msize = sizeof(struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
1009 msg = GNUNET_malloc (msize);
1010 msg->header.size = htons (msize);
1012 htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
1013 msg->operation_id = GNUNET_htonll (op_id);
1014 msg->slave_id = htonl (slave_id);
1020 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_INFORMATION message from
1021 * controller (testbed service)
1023 * @param c the controller handler
1024 * @param msg message received
1027 check_slave_config (void *cls,
1028 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1030 /* anything goes? */
1036 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION message from controller
1039 * @param c the controller handler
1040 * @param msg message received
1043 handle_slave_config (void *cls,
1044 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1046 struct GNUNET_TESTBED_Controller *c = cls;
1047 struct OperationContext *opc;
1050 struct GNUNET_TESTBED_EventInformation event;
1052 op_id = GNUNET_ntohll (msg->operation_id);
1053 if (NULL == (opc = find_opc (c, op_id)))
1055 LOG_DEBUG ("Operation not found\n");
1058 if (OP_GET_SLAVE_CONFIG != opc->type)
1063 opc->state = OPC_STATE_FINISHED;
1064 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1065 mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
1066 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
1068 opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
1069 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1071 event.op_cls = opc->op_cls;
1072 event.details.operation_finished.generic = opc->data;
1073 event.details.operation_finished.emsg = NULL;
1074 c->cc (c->cc_cls, &event);
1080 * Check #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1083 * @param c the controller handler
1084 * @param msg message received
1085 * @return #GNUNET_OK if @a msg is well-formed
1088 check_link_controllers_result (
1090 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1092 /* actual check to be implemented */
1098 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1101 * @param c the controller handler
1102 * @param msg message received
1105 handle_link_controllers_result (
1107 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1109 struct GNUNET_TESTBED_Controller *c = cls;
1110 struct OperationContext *opc;
1111 struct ControllerLinkData *data;
1112 struct GNUNET_CONFIGURATION_Handle *cfg;
1113 struct GNUNET_TESTBED_Host *host;
1116 struct GNUNET_TESTBED_EventInformation event;
1118 op_id = GNUNET_ntohll (msg->operation_id);
1119 if (NULL == (opc = find_opc (c, op_id)))
1121 LOG_DEBUG ("Operation not found\n");
1124 if (OP_FORWARDED == opc->type)
1126 handle_forwarded_operation_msg (c,
1128 (const struct GNUNET_MessageHeader *) msg);
1131 if (OP_LINK_CONTROLLERS != opc->type)
1136 GNUNET_assert (NULL != (data = opc->data));
1137 host = GNUNET_TESTBED_host_lookup_by_id_ (data->host_id);
1138 GNUNET_assert (NULL != host);
1141 opc->state = OPC_STATE_FINISHED;
1142 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1143 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1145 event.op_cls = opc->op_cls;
1146 event.details.operation_finished.emsg = NULL;
1147 event.details.operation_finished.generic = NULL;
1150 if (GNUNET_NO == ntohs (msg->success))
1153 GNUNET_malloc (ntohs (msg->header.size)
1154 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse)
1156 GNUNET_memcpy (emsg,
1158 ntohs (msg->header.size)
1159 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse));
1160 event.details.operation_finished.emsg = emsg;
1164 if (0 != ntohs (msg->config_size))
1166 cfg = GNUNET_TESTBED_extract_config_ (
1167 (const struct GNUNET_MessageHeader *) msg);
1168 GNUNET_assert (NULL != cfg);
1169 GNUNET_TESTBED_host_replace_cfg_ (host, cfg);
1172 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
1175 c->cc (c->cc_cls, &event);
1178 LOG_DEBUG ("Not calling callback\n");
1180 GNUNET_CONFIGURATION_destroy (cfg);
1181 GNUNET_free_non_null (emsg);
1186 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS message.
1188 * @param cls the controller handle to determine the connection this message
1190 * @param msg the barrier status message
1191 * @return #GNUNET_OK if the message is valid; #GNUNET_SYSERR to tear it
1192 * down signalling an error (message malformed)
1195 check_barrier_status (void *cls,
1196 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1204 msize = ntohs (msg->header.size);
1206 name_len = ntohs (msg->name_len);
1208 if (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
1210 GNUNET_break_op (0);
1211 return GNUNET_SYSERR;
1213 if ('\0' != name[name_len])
1215 GNUNET_break_op (0);
1216 return GNUNET_SYSERR;
1218 status = ntohs (msg->status);
1219 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1221 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1222 + name_len + 1); /* +1!? */
1225 GNUNET_break_op (0);
1226 return GNUNET_SYSERR;
1234 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
1236 * @param cls the controller handle to determine the connection this message
1238 * @param msg the barrier status message
1241 handle_barrier_status (void *cls,
1242 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1244 struct GNUNET_TESTBED_Controller *c = cls;
1245 struct GNUNET_TESTBED_Barrier *barrier;
1248 struct GNUNET_HashCode key;
1256 msize = ntohs (msg->header.size);
1257 if (msize <= sizeof(struct GNUNET_TESTBED_BarrierStatusMsg))
1259 GNUNET_break_op (0);
1263 name_len = ntohs (msg->name_len);
1264 if (name_len >= // name_len is strlen(barrier_name)
1265 (msize - ((sizeof msg->header) + sizeof(msg->status))))
1267 GNUNET_break_op (0);
1270 if ('\0' != name[name_len])
1272 GNUNET_break_op (0);
1275 LOG_DEBUG ("Received BARRIER_STATUS msg\n");
1276 status = ntohs (msg->status);
1277 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1280 // unlike name_len, emsg_len includes the trailing zero
1281 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1285 GNUNET_break_op (0);
1288 if ('\0' != (msg->data[(name_len + 1) + (emsg_len - 1)]))
1290 GNUNET_break_op (0);
1293 emsg = GNUNET_malloc (emsg_len);
1294 GNUNET_memcpy (emsg, msg->data + name_len + 1, emsg_len);
1296 if (NULL == c->barrier_map)
1298 GNUNET_break_op (0);
1301 GNUNET_CRYPTO_hash (name, name_len, &key);
1302 barrier = GNUNET_CONTAINER_multihashmap_get (c->barrier_map, &key);
1303 if (NULL == barrier)
1305 GNUNET_break_op (0);
1308 GNUNET_assert (NULL != barrier->cb);
1309 if ((GNUNET_YES == barrier->echo) &&
1310 (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status))
1311 GNUNET_TESTBED_queue_message_ (c, GNUNET_copy_message (&msg->header));
1312 barrier->cb (barrier->cls, name, barrier, status, emsg);
1313 if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED == status)
1314 return; /* just initialised; skip cleanup */
1317 GNUNET_free_non_null (emsg);
1319 * Do not remove the barrier if we did not echo the status back; this is
1320 * required at the chained testbed controller setup to ensure the only the
1321 * test-driver echos the status and the controller hierarchy properly
1322 * propagates the status.
1323 */if ((NULL != barrier) && (GNUNET_YES == barrier->echo))
1324 GNUNET_TESTBED_barrier_remove_ (barrier);
1329 * Queues a message in send queue for sending to the service
1331 * @param controller the handle to the controller
1332 * @param msg the message to queue
1335 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1336 struct GNUNET_MessageHeader *msg)
1338 struct GNUNET_MQ_Envelope *env;
1339 struct GNUNET_MessageHeader *m2;
1343 type = ntohs (msg->type);
1344 size = ntohs (msg->size);
1345 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1346 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1347 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1348 GNUNET_memcpy (m2, msg, size);
1350 GNUNET_MQ_send (controller->mq, env);
1355 * Sends the given message as an operation. The given callback is called when a
1356 * reply for the operation is available. Call
1357 * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1358 * operation context if the cc hasn't been called
1360 * @param controller the controller to which the message has to be sent
1361 * @param operation_id the operation id of the message
1362 * @param msg the message to send
1363 * @param cc the callback to call when reply is available
1364 * @param cc_cls the closure for the above callback
1365 * @return the operation context which can be used to cancel the forwarded
1368 struct OperationContext *
1369 GNUNET_TESTBED_forward_operation_msg_ (
1370 struct GNUNET_TESTBED_Controller *controller,
1371 uint64_t operation_id,
1372 const struct GNUNET_MessageHeader *msg,
1373 GNUNET_MQ_MessageCallback cc,
1376 struct OperationContext *opc;
1377 struct ForwardedOperationData *data;
1378 struct GNUNET_MQ_Envelope *env;
1379 struct GNUNET_MessageHeader *m2;
1380 uint16_t type = ntohs (msg->type);
1381 uint16_t size = ntohs (msg->size);
1383 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1384 GNUNET_memcpy (m2, msg, size);
1385 GNUNET_MQ_send (controller->mq, env);
1386 data = GNUNET_new (struct ForwardedOperationData);
1388 data->cc_cls = cc_cls;
1389 opc = GNUNET_new (struct OperationContext);
1390 opc->c = controller;
1391 opc->type = OP_FORWARDED;
1393 opc->id = operation_id;
1394 GNUNET_TESTBED_insert_opc_ (controller, opc);
1400 * Function to cancel an operation created by simply forwarding an operation
1403 * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1406 GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1408 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1409 GNUNET_free (opc->data);
1415 * Function to call to start a link-controllers type operation once all queues
1416 * the operation is part of declare that the operation can be activated.
1418 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1421 opstart_link_controllers (void *cls)
1423 struct OperationContext *opc = cls;
1424 struct ControllerLinkData *data;
1425 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1427 GNUNET_assert (NULL != opc->data);
1431 opc->state = OPC_STATE_STARTED;
1432 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1433 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1438 * Callback which will be called when link-controllers type operation is released
1440 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1443 oprelease_link_controllers (void *cls)
1445 struct OperationContext *opc = cls;
1446 struct ControllerLinkData *data;
1451 case OPC_STATE_INIT:
1452 GNUNET_free (data->msg);
1455 case OPC_STATE_STARTED:
1456 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1459 case OPC_STATE_FINISHED:
1462 GNUNET_free_non_null (data);
1468 * Function to be called when get slave config operation is ready
1470 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1473 opstart_get_slave_config (void *cls)
1475 struct OperationContext *opc = cls;
1476 struct GetSlaveConfigData *data = opc->data;
1477 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1479 GNUNET_assert (NULL != data);
1480 msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1481 GNUNET_free (opc->data);
1484 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1485 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1486 opc->state = OPC_STATE_STARTED;
1491 * Function to be called when get slave config operation is cancelled or finished
1493 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1496 oprelease_get_slave_config (void *cls)
1498 struct OperationContext *opc = cls;
1502 case OPC_STATE_INIT:
1503 GNUNET_free (opc->data);
1506 case OPC_STATE_STARTED:
1507 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1510 case OPC_STATE_FINISHED:
1511 if (NULL != opc->data)
1512 GNUNET_CONFIGURATION_destroy (opc->data);
1520 * Generic error handler, called with the appropriate error code and
1521 * the same closure specified at the creation of the message queue.
1522 * Not every message queue implementation supports an error handler.
1524 * @param cls closure, a `struct GNUNET_TESTBED_Controller *`
1525 * @param error error code
1528 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
1530 /* struct GNUNET_TESTBED_Controller *c = cls; */
1532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encountered MQ error: %d\n", error);
1534 GNUNET_SCHEDULER_shutdown (); /* seems most reasonable */
1539 * Start a controller process using the given configuration at the
1542 * @param host host to run the controller on; This should be the same host if
1543 * the controller was previously started with
1544 * GNUNET_TESTBED_controller_start()
1545 * @param event_mask bit mask with set of events to call 'cc' for;
1546 * or-ed values of "1LL" shifted by the
1547 * respective 'enum GNUNET_TESTBED_EventType'
1548 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1549 * @param cc controller callback to invoke on events
1550 * @param cc_cls closure for cc
1551 * @return handle to the controller
1553 struct GNUNET_TESTBED_Controller *
1554 GNUNET_TESTBED_controller_connect (struct GNUNET_TESTBED_Host *host,
1555 uint64_t event_mask,
1556 GNUNET_TESTBED_ControllerCallback cc,
1559 struct GNUNET_TESTBED_Controller *controller =
1560 GNUNET_new (struct GNUNET_TESTBED_Controller);
1561 struct GNUNET_MQ_MessageHandler handlers[] =
1562 { GNUNET_MQ_hd_var_size (add_host_confirm,
1563 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS,
1564 struct GNUNET_TESTBED_HostConfirmedMessage,
1566 GNUNET_MQ_hd_fixed_size (peer_conevent,
1567 GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT,
1568 struct GNUNET_TESTBED_ConnectionEventMessage,
1570 GNUNET_MQ_hd_fixed_size (opsuccess,
1571 GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS,
1573 GNUNET_TESTBED_GenericOperationSuccessEventMessage,
1575 GNUNET_MQ_hd_var_size (op_fail_event,
1576 GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT,
1577 struct GNUNET_TESTBED_OperationFailureEventMessage,
1579 GNUNET_MQ_hd_fixed_size (peer_create_success,
1580 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS,
1582 GNUNET_TESTBED_PeerCreateSuccessEventMessage,
1584 GNUNET_MQ_hd_fixed_size (peer_event,
1585 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT,
1586 struct GNUNET_TESTBED_PeerEventMessage,
1588 GNUNET_MQ_hd_var_size (peer_config,
1589 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
1591 GNUNET_TESTBED_PeerConfigurationInformationMessage,
1593 GNUNET_MQ_hd_var_size (slave_config,
1594 GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
1595 struct GNUNET_TESTBED_SlaveConfiguration,
1597 GNUNET_MQ_hd_var_size (link_controllers_result,
1598 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
1599 struct GNUNET_TESTBED_ControllerLinkResponse,
1601 GNUNET_MQ_hd_var_size (barrier_status,
1602 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
1603 struct GNUNET_TESTBED_BarrierStatusMsg,
1605 GNUNET_MQ_handler_end () };
1606 struct GNUNET_TESTBED_InitMessage *msg;
1607 struct GNUNET_MQ_Envelope *env;
1608 const struct GNUNET_CONFIGURATION_Handle *cfg;
1609 const char *controller_hostname;
1610 unsigned long long max_parallel_operations;
1611 unsigned long long max_parallel_service_connections;
1612 unsigned long long max_parallel_topology_config_operations;
1615 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1617 GNUNET_CONFIGURATION_get_value_number (cfg,
1619 "MAX_PARALLEL_OPERATIONS",
1620 &max_parallel_operations))
1623 GNUNET_free (controller);
1627 GNUNET_CONFIGURATION_get_value_number (cfg,
1629 "MAX_PARALLEL_SERVICE_CONNECTIONS",
1630 &max_parallel_service_connections))
1633 GNUNET_free (controller);
1636 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (
1639 "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1640 &max_parallel_topology_config_operations))
1643 GNUNET_free (controller);
1646 controller->cc = cc;
1647 controller->cc_cls = cc_cls;
1648 controller->event_mask = event_mask;
1649 controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1650 controller->mq = GNUNET_CLIENT_connect (controller->cfg,
1655 if (NULL == controller->mq)
1658 GNUNET_TESTBED_controller_disconnect (controller);
1661 GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1662 controller->host = host;
1663 controller->opq_parallel_operations =
1664 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1666 max_parallel_operations);
1667 controller->opq_parallel_service_connections =
1668 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1670 max_parallel_service_connections);
1671 controller->opq_parallel_topology_config_operations =
1672 GNUNET_TESTBED_operation_queue_create_ (
1673 OPERATION_QUEUE_TYPE_FIXED,
1674 (unsigned int) max_parallel_topology_config_operations);
1675 controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1676 if (NULL == controller_hostname)
1677 controller_hostname = "127.0.0.1";
1678 slen = strlen (controller_hostname) + 1;
1679 env = GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1680 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1681 msg->event_mask = GNUNET_htonll (controller->event_mask);
1682 GNUNET_memcpy (&msg[1], controller_hostname, slen);
1683 GNUNET_MQ_send (controller->mq, env);
1689 * Iterator to free opc map entries
1691 * @param cls closure
1692 * @param key current key code
1693 * @param value value in the hash map
1694 * @return #GNUNET_YES if we should continue to iterate,
1695 * #GNUNET_NO if not.
1698 opc_free_iterator (void *cls, uint32_t key, void *value)
1700 struct GNUNET_CONTAINER_MultiHashMap32 *map = cls;
1701 struct OperationContext *opc = value;
1703 GNUNET_assert (NULL != opc);
1705 GNUNET_assert (GNUNET_YES ==
1706 GNUNET_CONTAINER_multihashmap32_remove (map, key, value));
1713 * Stop the given controller (also will terminate all peers and
1714 * controllers dependent on this controller). This function
1715 * blocks until the testbed has been fully terminated (!).
1717 * @param c handle to controller to stop
1720 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *c)
1724 GNUNET_MQ_destroy (c->mq);
1727 if (NULL != c->host)
1728 GNUNET_TESTBED_deregister_host_at_ (c->host, c);
1729 GNUNET_CONFIGURATION_destroy (c->cfg);
1730 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_operations);
1731 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_service_connections);
1732 GNUNET_TESTBED_operation_queue_destroy_ (
1733 c->opq_parallel_topology_config_operations);
1734 if (NULL != c->opc_map)
1736 GNUNET_assert (GNUNET_SYSERR !=
1737 GNUNET_CONTAINER_multihashmap32_iterate (c->opc_map,
1740 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map));
1741 GNUNET_CONTAINER_multihashmap32_destroy (c->opc_map);
1748 * Compresses given configuration using zlib compress
1750 * @param config the serialized configuration
1751 * @param size the size of config
1752 * @param xconfig will be set to the compressed configuration (memory is fresly
1754 * @return the size of the xconfig
1757 GNUNET_TESTBED_compress_config_ (const char *config,
1763 xsize = compressBound ((uLong) size);
1764 *xconfig = GNUNET_malloc (xsize);
1765 GNUNET_assert (Z_OK == compress2 ((Bytef *) *xconfig,
1767 (const Bytef *) config,
1775 * Function to serialize and compress using zlib a configuration through a
1776 * configuration handle
1778 * @param cfg the configuration
1779 * @param size the size of configuration when serialize. Will be set on success.
1780 * @param xsize the sizeo of the compressed configuration. Will be set on success.
1781 * @return the serialized and compressed configuration
1784 GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
1793 config = GNUNET_CONFIGURATION_serialize (cfg, &size_);
1794 xsize_ = GNUNET_TESTBED_compress_config_ (config, size_, &xconfig);
1795 GNUNET_free (config);
1803 * Create a link from slave controller to delegated controller. Whenever the
1804 * master controller is asked to start a peer at the delegated controller the
1805 * request will be routed towards slave controller (if a route exists). The
1806 * slave controller will then route it to the delegated controller. The
1807 * configuration of the delegated controller is given and is used to either
1808 * create the delegated controller or to connect to an existing controller. Note
1809 * that while starting the delegated controller the configuration will be
1810 * modified to accommodate available free ports. the 'is_subordinate' specifies
1811 * if the given delegated controller should be started and managed by the slave
1812 * controller, or if the delegated controller already has a master and the slave
1813 * controller connects to it as a non master controller. The success or failure
1814 * of this operation will be signalled through the
1815 * GNUNET_TESTBED_ControllerCallback() with an event of type
1816 * GNUNET_TESTBED_ET_OPERATION_FINISHED
1818 * @param op_cls the operation closure for the event which is generated to
1819 * signal success or failure of this operation
1820 * @param master handle to the master controller who creates the association
1821 * @param delegated_host requests to which host should be delegated; cannot be NULL
1822 * @param slave_host which host is used to run the slave controller; use NULL to
1823 * make the master controller connect to the delegated host
1824 * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1825 * be started by the slave controller; GNUNET_NO if the slave
1826 * controller has to connect to the already started delegated
1827 * controller via TCP/IP
1828 * @return the operation handle
1830 struct GNUNET_TESTBED_Operation *
1831 GNUNET_TESTBED_controller_link (void *op_cls,
1832 struct GNUNET_TESTBED_Controller *master,
1833 struct GNUNET_TESTBED_Host *delegated_host,
1834 struct GNUNET_TESTBED_Host *slave_host,
1837 struct OperationContext *opc;
1838 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1839 struct ControllerLinkData *data;
1840 uint32_t slave_host_id;
1841 uint32_t delegated_host_id;
1844 GNUNET_assert (GNUNET_YES ==
1845 GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1846 slave_host_id = GNUNET_TESTBED_host_get_id_ (
1847 (NULL != slave_host) ? slave_host : master->host);
1848 delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
1849 if ((NULL != slave_host) && (0 != slave_host_id))
1850 GNUNET_assert (GNUNET_YES ==
1851 GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1852 msg_size = sizeof(struct GNUNET_TESTBED_ControllerLinkRequest);
1853 msg = GNUNET_malloc (msg_size);
1854 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
1855 msg->header.size = htons (msg_size);
1856 msg->delegated_host_id = htonl (delegated_host_id);
1857 msg->slave_host_id = htonl (slave_host_id);
1858 msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1859 data = GNUNET_new (struct ControllerLinkData);
1861 data->host_id = delegated_host_id;
1862 opc = GNUNET_new (struct OperationContext);
1865 opc->type = OP_LINK_CONTROLLERS;
1866 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1867 opc->state = OPC_STATE_INIT;
1868 opc->op_cls = op_cls;
1869 msg->operation_id = GNUNET_htonll (opc->id);
1870 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1871 &opstart_link_controllers,
1872 &oprelease_link_controllers);
1873 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1875 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1881 * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
1882 * check. Another difference is that this function takes the id of the slave
1885 * @param op_cls the closure for the operation
1886 * @param master the handle to master controller
1887 * @param slave_host_id id of the host where the slave controller is running to
1888 * the slave_host should remain valid until this operation is cancelled
1889 * or marked as finished
1890 * @return the operation handle;
1892 struct GNUNET_TESTBED_Operation *
1893 GNUNET_TESTBED_get_slave_config_ (void *op_cls,
1894 struct GNUNET_TESTBED_Controller *master,
1895 uint32_t slave_host_id)
1897 struct OperationContext *opc;
1898 struct GetSlaveConfigData *data;
1900 data = GNUNET_new (struct GetSlaveConfigData);
1901 data->slave_id = slave_host_id;
1902 opc = GNUNET_new (struct OperationContext);
1903 opc->state = OPC_STATE_INIT;
1905 opc->id = GNUNET_TESTBED_get_next_op_id (master);
1906 opc->type = OP_GET_SLAVE_CONFIG;
1908 opc->op_cls = op_cls;
1909 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1910 &opstart_get_slave_config,
1911 &oprelease_get_slave_config);
1912 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1914 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1920 * Function to acquire the configuration of a running slave controller. The
1921 * completion of the operation is signalled through the controller_cb from
1922 * GNUNET_TESTBED_controller_connect(). If the operation is successful the
1923 * handle to the configuration is available in the generic pointer of
1924 * operation_finished field of struct GNUNET_TESTBED_EventInformation.
1926 * @param op_cls the closure for the operation
1927 * @param master the handle to master controller
1928 * @param slave_host the host where the slave controller is running; the handle
1929 * to the slave_host should remain valid until this operation is
1930 * cancelled or marked as finished
1931 * @return the operation handle; NULL if the slave_host is not registered at
1934 struct GNUNET_TESTBED_Operation *
1935 GNUNET_TESTBED_get_slave_config (void *op_cls,
1936 struct GNUNET_TESTBED_Controller *master,
1937 struct GNUNET_TESTBED_Host *slave_host)
1939 if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
1941 return GNUNET_TESTBED_get_slave_config_ (op_cls,
1943 GNUNET_TESTBED_host_get_id_ (
1949 * Ask the testbed controller to write the current overlay topology to
1950 * a file. Naturally, the file will only contain a snapshot as the
1951 * topology may evolve all the time.
1953 * @param controller overlay controller to inspect
1954 * @param filename name of the file the topology should
1958 GNUNET_TESTBED_overlay_write_topology_to_file (
1959 struct GNUNET_TESTBED_Controller *controller,
1960 const char *filename)
1967 * Creates a helper initialization message. This function is here because we
1968 * want to use this in testing
1970 * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1971 * HOST(all connections form this ip are permitted by the testbed) when
1972 * starting testbed controller at host. This can either be a single ip
1973 * address or a network address in CIDR notation.
1974 * @param hostname the hostname of the destination this message is intended for
1975 * @param cfg the configuration that has to used to start the testbed service
1977 * @return the initialization message
1979 struct GNUNET_TESTBED_HelperInit *
1980 GNUNET_TESTBED_create_helper_init_msg_ (
1981 const char *trusted_ip,
1982 const char *hostname,
1983 const struct GNUNET_CONFIGURATION_Handle *cfg)
1985 struct GNUNET_TESTBED_HelperInit *msg;
1989 size_t xconfig_size;
1990 uint16_t trusted_ip_len;
1991 uint16_t hostname_len;
1994 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1995 GNUNET_assert (NULL != config);
1997 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1998 GNUNET_free (config);
1999 trusted_ip_len = strlen (trusted_ip);
2000 hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
2001 msg_size = xconfig_size + trusted_ip_len + 1
2002 + sizeof(struct GNUNET_TESTBED_HelperInit);
2003 msg_size += hostname_len;
2004 msg = GNUNET_realloc (xconfig, msg_size);
2005 (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len,
2008 msg->header.size = htons (msg_size);
2009 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
2010 msg->trusted_ip_size = htons (trusted_ip_len);
2011 msg->hostname_size = htons (hostname_len);
2012 msg->config_size = htons (config_size);
2013 (void) strcpy ((char *) &msg[1], trusted_ip);
2014 if (0 != hostname_len)
2015 GNUNET_memcpy ((char *) &msg[1] + trusted_ip_len + 1,
2023 * This function is used to signal that the event information (struct
2024 * GNUNET_TESTBED_EventInformation) from an operation has been fully processed
2025 * i.e. if the event callback is ever called for this operation. If the event
2026 * callback for this operation has not yet been called, calling this function
2027 * cancels the operation, frees its resources and ensures the no event is
2028 * generated with respect to this operation. Note that however cancelling an
2029 * operation does NOT guarantee that the operation will be fully undone (or that
2030 * nothing ever happened).
2032 * This function MUST be called for every operation to fully remove the
2033 * operation from the operation queue. After calling this function, if
2034 * operation is completed and its event information is of type
2035 * GNUNET_TESTBED_ET_OPERATION_FINISHED, the 'op_result' becomes invalid (!).
2037 * If the operation is generated from GNUNET_TESTBED_service_connect() then
2038 * calling this function on such as operation calls the disconnect adapter if
2039 * the connect adapter was ever called.
2041 * @param operation operation to signal completion or cancellation
2044 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
2046 (void) exop_check (operation);
2047 GNUNET_TESTBED_operation_release_ (operation);
2052 * Generates configuration by uncompressing configuration in given message. The
2053 * given message should be of the following types:
2054 * #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
2055 * #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
2056 * #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
2057 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
2058 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
2060 * FIXME: This API is incredibly ugly.
2062 * @param msg the message containing compressed configuration
2063 * @return handle to the parsed configuration; NULL upon error while parsing the message
2065 struct GNUNET_CONFIGURATION_Handle *
2066 GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
2068 struct GNUNET_CONFIGURATION_Handle *cfg;
2075 switch (ntohs (msg->type))
2077 case GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION: {
2078 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
2081 (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
2082 data_len = (uLong) ntohs (imsg->config_size);
2084 ntohs (imsg->header.size)
2085 - sizeof(struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2086 xdata = (const Bytef *) &imsg[1];
2090 case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION: {
2091 const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
2093 imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
2094 data_len = (uLong) ntohs (imsg->config_size);
2095 xdata_len = ntohs (imsg->header.size)
2096 - sizeof(struct GNUNET_TESTBED_SlaveConfiguration);
2097 xdata = (const Bytef *) &imsg[1];
2101 case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST: {
2102 const struct GNUNET_TESTBED_AddHostMessage *imsg;
2105 imsg = (const struct GNUNET_TESTBED_AddHostMessage *) msg;
2106 data_len = (uLong) ntohs (imsg->config_size);
2107 osize = sizeof(struct GNUNET_TESTBED_AddHostMessage)
2108 + ntohs (imsg->username_length) + ntohs (imsg->hostname_length);
2109 xdata_len = ntohs (imsg->header.size) - osize;
2110 xdata = (const Bytef *) ((const void *) imsg + osize);
2114 case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT: {
2115 const struct GNUNET_TESTBED_ControllerLinkResponse *imsg;
2117 imsg = (const struct GNUNET_TESTBED_ControllerLinkResponse *) msg;
2118 data_len = ntohs (imsg->config_size);
2119 xdata_len = ntohs (imsg->header.size)
2120 - sizeof(const struct GNUNET_TESTBED_ControllerLinkResponse);
2121 xdata = (const Bytef *) &imsg[1];
2125 case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER: {
2126 const struct GNUNET_TESTBED_PeerCreateMessage *imsg;
2128 imsg = (const struct GNUNET_TESTBED_PeerCreateMessage *) msg;
2129 data_len = ntohs (imsg->config_size);
2130 xdata_len = ntohs (imsg->header.size)
2131 - sizeof(struct GNUNET_TESTBED_PeerCreateMessage);
2132 xdata = (const Bytef *) &imsg[1];
2136 case GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER: {
2137 const struct GNUNET_TESTBED_PeerReconfigureMessage *imsg;
2139 imsg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) msg;
2140 data_len = ntohs (imsg->config_size);
2141 xdata_len = ntohs (imsg->header.size)
2142 - sizeof(struct GNUNET_TESTBED_PeerReconfigureMessage);
2143 xdata = (const Bytef *) &imsg[1];
2150 data = GNUNET_malloc (data_len);
2151 if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
2154 GNUNET_break_op (0); /* Un-compression failure */
2157 cfg = GNUNET_CONFIGURATION_create ();
2158 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg,
2159 (const char *) data,
2164 GNUNET_break_op (0); /* De-serialization failure */
2173 * Checks the integrity of the OperationFailureEventMessage and if good returns
2174 * the error message it contains.
2176 * @param msg the OperationFailureEventMessage
2177 * @return the error message
2180 GNUNET_TESTBED_parse_error_string_ (
2181 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
2186 msize = ntohs (msg->header.size);
2187 if (sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
2189 msize -= sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage);
2190 emsg = (const char *) &msg[1];
2191 if ('\0' != emsg[msize - 1])
2201 * Function to return the operation id for a controller. The operation id is
2202 * created from the controllers host id and its internal operation counter.
2204 * @param controller the handle to the controller whose operation id has to be incremented
2205 * @return the incremented operation id.
2208 GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller)
2212 op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
2213 op_id = op_id << 32;
2214 op_id |= (uint64_t) controller->operation_counter++;
2220 * Function called when a shutdown peers operation is ready
2222 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2225 opstart_shutdown_peers (void *cls)
2227 struct OperationContext *opc = cls;
2228 struct GNUNET_MQ_Envelope *env;
2229 struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2231 opc->state = OPC_STATE_STARTED;
2232 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS);
2233 msg->operation_id = GNUNET_htonll (opc->id);
2234 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
2235 GNUNET_MQ_send (opc->c->mq, env);
2240 * Callback which will be called when shutdown peers operation is released
2242 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2245 oprelease_shutdown_peers (void *cls)
2247 struct OperationContext *opc = cls;
2251 case OPC_STATE_STARTED:
2252 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
2254 /* no break; continue */
2255 case OPC_STATE_INIT:
2256 GNUNET_free (opc->data);
2259 case OPC_STATE_FINISHED:
2267 * Stops and destroys all peers. Is equivalent of calling
2268 * GNUNET_TESTBED_peer_stop() and GNUNET_TESTBED_peer_destroy() on all peers,
2269 * except that the peer stop event and operation finished event corresponding to
2270 * the respective functions are not generated. This function should be called
2271 * when there are no other pending operations. If there are pending operations,
2272 * it will return NULL
2274 * @param c the controller to send this message to
2275 * @param op_cls closure for the operation
2276 * @param cb the callback to call when all peers are stopped and destroyed
2277 * @param cb_cls the closure for the callback
2278 * @return operation handle on success; NULL if any pending operations are
2281 struct GNUNET_TESTBED_Operation *
2282 GNUNET_TESTBED_shutdown_peers (struct GNUNET_TESTBED_Controller *c,
2284 GNUNET_TESTBED_OperationCompletionCallback cb,
2287 struct OperationContext *opc;
2288 struct ShutdownPeersData *data;
2290 if (0 != GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
2292 data = GNUNET_new (struct ShutdownPeersData);
2294 data->cb_cls = cb_cls;
2295 opc = GNUNET_new (struct OperationContext);
2297 opc->op_cls = op_cls;
2299 opc->id = GNUNET_TESTBED_get_next_op_id (c);
2300 opc->type = OP_SHUTDOWN_PEERS;
2301 opc->state = OPC_STATE_INIT;
2302 opc->op = GNUNET_TESTBED_operation_create_ (opc,
2303 &opstart_shutdown_peers,
2304 &oprelease_shutdown_peers);
2305 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
2307 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2313 * Return the index of the peer inside of the total peer array,
2314 * aka. the peer's "unique ID".
2316 * @param peer Peer handle.
2318 * @return The peer's unique ID.
2321 GNUNET_TESTBED_get_index (const struct GNUNET_TESTBED_Peer *peer)
2323 return peer->unique_id;
2328 * Remove a barrier and it was the last one in the barrier hash map, destroy the
2331 * @param barrier the barrier to remove
2334 GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier)
2336 struct GNUNET_TESTBED_Controller *c = barrier->c;
2338 GNUNET_assert (NULL != c->barrier_map); /* No barriers present */
2339 GNUNET_assert (GNUNET_OK ==
2340 GNUNET_CONTAINER_multihashmap_remove (c->barrier_map,
2343 GNUNET_free (barrier->name);
2344 GNUNET_free (barrier);
2345 if (0 == GNUNET_CONTAINER_multihashmap_size (c->barrier_map))
2347 GNUNET_CONTAINER_multihashmap_destroy (c->barrier_map);
2348 c->barrier_map = NULL;
2354 * Initialise a barrier and call the given callback when the required percentage
2355 * of peers (quorum) reach the barrier OR upon error.
2357 * @param controller the handle to the controller
2358 * @param name identification name of the barrier
2359 * @param quorum the percentage of peers that is required to reach the barrier.
2360 * Peers signal reaching a barrier by calling
2361 * GNUNET_TESTBED_barrier_reached().
2362 * @param cb the callback to call when the barrier is reached or upon error.
2364 * @param cls closure for the above callback
2365 * @param echo GNUNET_YES to echo the barrier crossed status message back to the
2367 * @return barrier handle; NULL upon error
2369 struct GNUNET_TESTBED_Barrier *
2370 GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
2372 unsigned int quorum,
2373 GNUNET_TESTBED_barrier_status_cb cb,
2377 struct GNUNET_TESTBED_BarrierInit *msg;
2378 struct GNUNET_MQ_Envelope *env;
2379 struct GNUNET_TESTBED_Barrier *barrier;
2380 struct GNUNET_HashCode key;
2383 GNUNET_assert (quorum <= 100);
2384 GNUNET_assert (NULL != cb);
2385 name_len = strlen (name);
2386 GNUNET_assert (0 < name_len);
2387 GNUNET_CRYPTO_hash (name, name_len, &key);
2388 if (NULL == controller->barrier_map)
2389 controller->barrier_map =
2390 GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
2392 GNUNET_CONTAINER_multihashmap_contains (controller->barrier_map, &key))
2397 LOG_DEBUG ("Initialising barrier `%s'\n", name);
2398 barrier = GNUNET_new (struct GNUNET_TESTBED_Barrier);
2399 barrier->c = controller;
2400 barrier->name = GNUNET_strdup (name);
2403 barrier->echo = echo;
2404 GNUNET_memcpy (&barrier->key, &key, sizeof(struct GNUNET_HashCode));
2405 GNUNET_assert (GNUNET_OK ==
2406 GNUNET_CONTAINER_multihashmap_put (
2407 controller->barrier_map,
2410 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
2412 env = GNUNET_MQ_msg_extra (msg,
2414 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT);
2415 msg->quorum = (uint8_t) quorum;
2416 GNUNET_memcpy (msg->name, barrier->name, name_len);
2417 GNUNET_MQ_send (barrier->c->mq, env);
2423 * Initialise a barrier and call the given callback when the required percentage
2424 * of peers (quorum) reach the barrier OR upon error.
2426 * @param controller the handle to the controller
2427 * @param name identification name of the barrier
2428 * @param quorum the percentage of peers that is required to reach the barrier.
2429 * Peers signal reaching a barrier by calling
2430 * GNUNET_TESTBED_barrier_reached().
2431 * @param cb the callback to call when the barrier is reached or upon error.
2433 * @param cls closure for the above callback
2434 * @return barrier handle; NULL upon error
2436 struct GNUNET_TESTBED_Barrier *
2437 GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
2439 unsigned int quorum,
2440 GNUNET_TESTBED_barrier_status_cb cb,
2443 return GNUNET_TESTBED_barrier_init_ (controller,
2455 * @param barrier the barrier handle
2458 GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
2460 struct GNUNET_MQ_Envelope *env;
2461 struct GNUNET_TESTBED_BarrierCancel *msg;
2464 slen = strlen (barrier->name);
2466 GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL);
2467 GNUNET_memcpy (msg->name, barrier->name, slen);
2468 GNUNET_MQ_send (barrier->c->mq, env);
2469 GNUNET_TESTBED_barrier_remove_ (barrier);
2473 /* end of testbed_api.c */