/** * Try to open a connection to the given neigbour. If the connection is open * already, then it is re-used. If not, the request is queued in the operation * queues responsible for bounding the total number of file descriptors. The * actual connection will happen when the operation queue marks the * corresponding operation as active. * * @param n the neighbour to open a connection to * @param cb the notification callback to call when the connection is opened * @param cb_cls the closure for the above callback */ struct NeighbourConnectNotification * GST_neighbour_get_connection (struct Neighbour *n, GST_NeigbourConnectNotifyCallback cb, void *cb_cls) { struct NeighbourConnectNotification *h; GNUNET_assert (NULL != cb); LOG_DEBUG ("Attempting to get connection to controller on host %u\n", n->host_id); h = GNUNET_new (struct NeighbourConnectNotification); h->n = n; h->cb = cb; h->cb_cls = cb_cls; GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h); if (NULL == n->conn_op) { GNUNET_assert (NULL == n->controller); n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn, &oprelease_neighbour_conn); GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op); GNUNET_TESTBED_operation_begin_wait_ (n->conn_op); return h; } trigger_notifications (n); return h; }
/** * Convenience method that iterates over all (running) peers * and retrieves all statistics from each peer. * * @param num_peers number of peers to iterate over * @param peers array of peers to iterate over * @param subsystem limit to the specified subsystem, NULL for all subsystems * @param name name of the statistic value, NULL for all values * @param proc processing function for each statistic retrieved * @param cont continuation to call once call is completed(?) * @param cls closure to pass to proc and cont * @return operation handle to cancel the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_get_statistics (unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, const char *subsystem, const char *name, GNUNET_TESTBED_StatisticsIterator proc, GNUNET_TESTBED_OperationCompletionCallback cont, void *cls) { struct GetStatsContext *sc; GNUNET_assert (NULL != proc); GNUNET_assert (NULL != cont); if (NULL == no_wait_queue) no_wait_queue = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, UINT_MAX); sc = GNUNET_new (struct GetStatsContext); sc->peers = peers; sc->subsystem = (NULL == subsystem) ? NULL : GNUNET_strdup (subsystem); sc->name = (NULL == name) ? NULL : GNUNET_strdup (name); sc->proc = proc; sc->cont = cont; sc->cb_cls = cls; sc->num_peers = num_peers; sc->main_op = GNUNET_TESTBED_operation_create_ (sc, &opstart_get_stats, &oprelease_get_stats); GNUNET_TESTBED_operation_queue_insert_ (no_wait_queue, sc->main_op); GNUNET_TESTBED_operation_begin_wait_ (sc->main_op); return sc->main_op; }
/** * Connect to a service offered by the given peer. Will ensure that * the request is queued to not overwhelm our ability to create and * maintain connections with other systems. The actual service * handle is then returned via the 'op_result' member in the event * callback. The 'ca' callback is used to create the connection * when the time is right; the 'da' callback will be used to * destroy the connection (upon 'GNUNET_TESTBED_operation_done'). * 'GNUNET_TESTBED_operation_done' can be used to abort this * operation until the event callback has been called. * * @param op_cls closure to pass in operation event * @param peer peer that runs the service * @param service_name name of the service to connect to * @param cb the callback to call when this operation finishes * @param cb_cls closure for the above callback * @param ca helper function to establish the connection * @param da helper function to close the connection * @param cada_cls closure for ca and da * @return handle for the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer, const char *service_name, GNUNET_TESTBED_ServiceConnectCompletionCallback cb, void *cb_cls, GNUNET_TESTBED_ConnectAdapter ca, GNUNET_TESTBED_DisconnectAdapter da, void *cada_cls) { struct ServiceConnectData *data; data = GNUNET_new (struct ServiceConnectData); data->ca = ca; data->da = da; data->cada_cls = cada_cls; data->op_cls = op_cls; data->peer = peer; data->state = INIT; data->cb = cb; data->cb_cls = cb_cls; data->operation = GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect, &oprelease_service_connect); GNUNET_TESTBED_operation_queue_insert_ (peer-> controller->opq_parallel_service_connections, data->operation); GNUNET_TESTBED_operation_queue_insert_ (peer-> controller->opq_parallel_operations, data->operation); GNUNET_TESTBED_operation_begin_wait_ (data->operation); return data->operation; }
/** * Both peers must have been started before calling this function. * This function then obtains a HELLO from 'p1', gives it to 'p2' * and asks 'p2' to connect to 'p1'. * * @param op_cls closure argument to give with the operation event * @param cb the callback to call when this operation has finished * @param cb_cls the closure for the above callback * @param p1 first peer * @param p2 second peer * @return handle to the operation, NULL if connecting these two * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_connect (void *op_cls, GNUNET_TESTBED_OperationCompletionCallback cb, void *cb_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2) { struct OperationContext *opc; struct OverlayConnectData *data; GNUNET_assert ((PS_STARTED == p1->state) && (PS_STARTED == p2->state)); data = GNUNET_malloc (sizeof (struct OverlayConnectData)); data->p1 = p1; data->p2 = p2; data->cb = cb; data->cb_cls = cb_cls; data->state = OCD_INIT; opc = GNUNET_malloc (sizeof (struct OperationContext)); opc->data = data; opc->c = p1->controller; opc->id = GNUNET_TESTBED_get_next_op_id (opc->c); opc->type = OP_OVERLAY_CONNECT; opc->op_cls = op_cls; opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect, &oprelease_overlay_connect); GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_overlay_connect_operations, opc->op); GNUNET_TESTBED_operation_begin_wait_ (opc->op); return opc->op; }
/** * Request information about a peer. The controller callback will not be called * with event type GNUNET_TESTBED_ET_OPERATION_FINISHED when result for this * operation is available. Instead, the GNUNET_TESTBED_PeerInfoCallback() will * be called. * * @param peer peer to request information about * @param pit desired information * @param cb the convenience callback to be called when results for this * operation are available * @param cb_cls the closure for the above callback * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer, enum GNUNET_TESTBED_PeerInformationType pit, GNUNET_TESTBED_PeerInfoCallback cb, void *cb_cls) { struct OperationContext *opc; struct PeerInfoData *data; GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit); data = GNUNET_malloc (sizeof (struct PeerInfoData)); data->peer = peer; data->pit = pit; data->cb = cb; data->cb_cls = cb_cls; opc = GNUNET_malloc (sizeof (struct OperationContext)); opc->c = peer->controller; opc->data = data; opc->type = OP_PEER_INFO; opc->id = GNUNET_TESTBED_get_next_op_id (opc->c); opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo, &oprelease_peer_getinfo); GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations, opc->op); GNUNET_TESTBED_operation_begin_wait_ (opc->op); return opc->op; }
/** * Stop the given peer. The handle remains valid (use * "GNUNET_TESTBED_peer_destroy" to fully clean up the * state of the peer). * * @param peer peer to stop * @param pcc function to call upon completion * @param pcc_cls closure for 'pcc' * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer, GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls) { struct OperationContext *opc; struct PeerEventData *data; data = GNUNET_malloc (sizeof (struct PeerEventData)); data->peer = peer; data->pcc = pcc; data->pcc_cls = pcc_cls; opc = GNUNET_malloc (sizeof (struct OperationContext)); opc->c = peer->controller; opc->data = data; opc->id = GNUNET_TESTBED_get_next_op_id (opc->c); opc->type = OP_PEER_STOP; opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop, &oprelease_peer_stop); GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations, opc->op); GNUNET_TESTBED_operation_begin_wait_ (opc->op); return opc->op; }
/** * Main run function. * * @param cls NULL * @param args arguments passed to GNUNET_PROGRAM_run * @param cfgfile the path to configuration file * @param cfg the configuration file handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { q1 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 1); GNUNET_assert (NULL != q1); q2 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 2); GNUNET_assert (NULL != q2); op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb); GNUNET_assert (NULL != op1); op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb); GNUNET_TESTBED_operation_queue_insert_ (q1, op1); GNUNET_TESTBED_operation_queue_insert_ (q2, op1); GNUNET_TESTBED_operation_begin_wait_ (op1); GNUNET_TESTBED_operation_queue_insert_ (q1, op2); GNUNET_TESTBED_operation_queue_insert_ (q2, op2); GNUNET_TESTBED_operation_begin_wait_ (op2); result = TEST_INIT; }
/** * Destroy the given peer; the peer should have been * stopped first (if it was started). * * @param peer peer to stop * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer) { struct OperationContext *opc; opc = GNUNET_malloc (sizeof (struct OperationContext)); opc->data = peer; opc->c = peer->controller; opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller); opc->type = OP_PEER_DESTROY; opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy, &oprelease_peer_destroy); GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations, opc->op); GNUNET_TESTBED_operation_begin_wait_ (opc->op); return opc->op; }
/** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target * host, it should find or create a controller at the target host and * delegate creating the peer. Explicit delegation paths can be setup * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation * path exists, a direct link with a subordinate controller is setup * for the first delegated peer to a particular host; the subordinate * controller is then destroyed once the last peer that was delegated * to the remote host is stopped. This function is used in particular * if some other controller has already assigned a unique ID to the * peer. * * Creating the peer only creates the handle to manipulate and further * configure the peer; use "GNUNET_TESTBED_peer_start" and * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's * processes. * * Note that the given configuration will be adjusted by the * controller to avoid port/path conflicts with other peers. * The "final" configuration can be obtained using * 'GNUNET_TESTBED_peer_get_information'. * * @param unique_id unique ID for this peer * @param controller controller process to use * @param host host to run the peer on * @param cfg Template configuration to use for the peer. Should exist until * operation is cancelled or GNUNET_TESTBED_operation_done() is called * @param cb the callback to call when the peer has been created * @param cls the closure to the above callback * @return the operation handle */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id, struct GNUNET_TESTBED_Controller *controller, struct GNUNET_TESTBED_Host *host, const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TESTBED_PeerCreateCallback cb, void *cls) { struct GNUNET_TESTBED_Peer *peer; struct PeerCreateData *data; struct OperationContext *opc; peer = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer)); peer->controller = controller; peer->host = host; peer->unique_id = unique_id; peer->state = PS_INVALID; data = GNUNET_malloc (sizeof (struct PeerCreateData)); data->host = host; data->cfg = cfg; data->cb = cb; data->cls = cls; data->peer = peer; opc = GNUNET_malloc (sizeof (struct OperationContext)); opc->c = controller; opc->data = data; opc->id = GNUNET_TESTBED_get_next_op_id (controller); opc->type = OP_PEER_CREATE; opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create, &oprelease_peer_create); GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations, opc->op); GNUNET_TESTBED_operation_begin_wait_ (opc->op); return opc->op; }
/** * Function to cancel an operation (release all associated resources). This can * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the * operation generated an event) or AFTER the operation generated an event due * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'. * Implementations of this function are expected to clean up whatever state is * in 'cls' and release all resources associated with the operation. */ static void release_cb (void *cls) { switch (result) { case TEST_OP1_STARTED: GNUNET_assert (&op1 == cls); result = TEST_OP1_RELEASED; op1 = NULL; step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL); break; case TEST_OP2_STARTED: GNUNET_assert (&op2 == cls); result = TEST_OP2_RELEASED; GNUNET_assert (NULL == step_task); break; case TEST_OP3_STARTED: GNUNET_assert (&op3 == cls); result = TEST_OP3_RELEASED; GNUNET_assert (NULL == step_task); break; case TEST_OP4_STARTED: GNUNET_assert (&op4 == cls); result = TEST_OP4_RELEASED; GNUNET_assert (NULL == step_task); op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1); GNUNET_TESTBED_operation_begin_wait_ (op5); op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1); GNUNET_TESTBED_operation_begin_wait_ (op6); op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1); GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1); GNUNET_TESTBED_operation_begin_wait_ (op7); break; case TEST_OP5_6_7_STARTED: result = TEST_OP5_RELEASED; op5 = NULL; GNUNET_TESTBED_operation_release_ (op6); break; case TEST_OP5_RELEASED: op6 = NULL; result = TEST_OP6_RELEASED; GNUNET_TESTBED_operation_inactivate_ (op7); step_task = GNUNET_SCHEDULER_add_now (&step, NULL); break; case TEST_OP8_WAITING: GNUNET_assert (&op7 == cls); op7 = NULL; result = TEST_OP7_RELEASED; break; case TEST_OP8_ACTIVE: result = TEST_OP8_RELEASED; op8 = NULL; break; case TEST_OP9_STARTED: GNUNET_assert (&op9 == cls); result = TEST_OP9_RELEASED; GNUNET_TESTBED_operation_queue_destroy_ (q1); GNUNET_TESTBED_operation_queue_destroy_ (q2); q1 = NULL; q2 = NULL; break; default: GNUNET_assert (0); } }
/** * Task to simulate artificial delay and change the test stage * * @param cls NULL */ static void step (void *cls) { GNUNET_assert (NULL != step_task); step_task = NULL; switch (result) { case TEST_OP1_STARTED: GNUNET_TESTBED_operation_release_ (op1); GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0); op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op3, 2); GNUNET_TESTBED_operation_queue_insert2_ (q2, op3, 2); GNUNET_TESTBED_operation_begin_wait_ (op3); op4 = GNUNET_TESTBED_operation_create_ (&op4, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op4, 2); GNUNET_TESTBED_operation_queue_insert2_ (q2, op4, 2); GNUNET_TESTBED_operation_begin_wait_ (op4); break; case TEST_OP1_RELEASED: result = TEST_PAUSE; GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 2); break; case TEST_OP2_STARTED: GNUNET_TESTBED_operation_release_ (op2); break; case TEST_OP3_STARTED: GNUNET_TESTBED_operation_release_ (op3); break; case TEST_OP4_STARTED: GNUNET_TESTBED_operation_release_ (op4); break; case TEST_OP6_RELEASED: op8 = GNUNET_TESTBED_operation_create_ (&op8, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op8, 2); GNUNET_TESTBED_operation_queue_insert2_ (q2, op8, 2); result = TEST_OP8_WAITING; GNUNET_TESTBED_operation_begin_wait_ (op8); break; case TEST_OP8_STARTED: GNUNET_TESTBED_operation_inactivate_ (op8); result = TEST_OP8_INACTIVE_1; step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL); break; case TEST_OP8_INACTIVE_1: GNUNET_TESTBED_operation_activate_ (op8); result = TEST_OP8_ACTIVE; op9 = GNUNET_TESTBED_operation_create_ (&op9, &start_cb, &release_cb); GNUNET_TESTBED_operation_queue_insert2_ (q1, op9, 1); GNUNET_TESTBED_operation_queue_insert2_ (q2, op9, 1); GNUNET_TESTBED_operation_begin_wait_ (op9); step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL); break; case TEST_OP8_ACTIVE: GNUNET_TESTBED_operation_inactivate_ (op8); /* op8 should be released by now due to above call */ GNUNET_assert (TEST_OP8_RELEASED == result); break; case TEST_OP9_STARTED: GNUNET_TESTBED_operation_release_ (op9); break; default: GNUNET_assert (0); } }