/** * \brief Initialize a connection to a terminal server and block until * connection is established. * * \param client Terminal client state, initialized by function to default * values. * \param session_id The session the domain is part of. * * Dispatches the monitor waitset until all the bindings to the terminal server * are established. */ errval_t term_client_blocking_init(struct term_client *client, struct capref session_id) { errval_t err; iref_t in_iref; iref_t out_iref; iref_t conf_iref; /* Initialize client state to default values. */ struct_term_client_init(client); /* Get the interface references from octopus. */ err = get_irefs(session_id, &in_iref, &out_iref, &conf_iref); if (err_is_fail(err)) { return err; } /* Bind to interface for incoming characters. */ err = terminal_bind(in_iref, in_bind_cb, client, client->read_ws, IDC_BIND_FLAGS_DEFAULT); if (err_is_fail(err)) { return err_push(err, TERM_ERR_BIND_IN_INTERFACE); } TERM_DEBUG("Binding to terminal interface for incoming characters.\n"); /* Bind to interface for outgoing characters. */ err = terminal_bind(out_iref, out_bind_cb, client, client->write_ws, IDC_BIND_FLAGS_DEFAULT); if (err_is_fail(err)) { return err_push(err, TERM_ERR_BIND_OUT_INTERFACE); } TERM_DEBUG("Binding to terminal interface for outgoing characters.\n"); /* Bind to interface for incoming characters. */ err = terminal_config_bind(conf_iref, conf_bind_cb, client, client->conf_ws, IDC_BIND_FLAGS_DEFAULT); if (err_is_fail(err)) { return err_push(err, TERM_ERR_BIND_CONF_INTERFACE); } TERM_DEBUG("Binding to terminal configuration interface for configuration " "messages.\n"); /* * Dispatch on the monitor binding until the bind completes. Otherwise, we * would have to check before every term_client_blocking_read and * term_client_blocking_write if we're already connected. */ struct monitor_binding *monitor_b = get_monitor_binding(); struct waitset *monitor_ws = monitor_b->waitset; while (!client->connected) { err = event_dispatch(monitor_ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Error dispatching events."); } } TERM_DEBUG("Connection to terminal server successfully established.\n"); return SYS_ERR_OK; }
/** * \brief Retrieve interface references for incoming and outgoing characters * as well as for configuration messages from octopus. */ static errval_t get_irefs(struct capref session_id, iref_t *in_iref, iref_t *out_iref, iref_t *conf_iref) { errval_t err; struct octopus_rpc_client *r = get_octopus_rpc_client(); assert(r != NULL); char *record; errval_t error_code; octopus_trigger_id_t tid; err = r->vtbl.get_with_idcap(r, session_id, NOP_TRIGGER, &record, &tid, &error_code); if (err_is_fail(err)) { err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD); goto out; } err = error_code; if (err_is_fail(err)) { err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD); goto out; } TERM_DEBUG("Record retrieved from octopus: %s\n", record); int64_t session_oct; int64_t in_oct; int64_t out_oct; int64_t conf_oct; // oct_read can only parse 64-bit values, we need to parse the irefs as 64bit // then cast to 32bit err = oct_read(record, "_ { session_iref: %d, in_iref: %d, out_iref: %d, " "conf_iref: %d }", &session_oct, &in_oct, &out_oct, &conf_oct); //iref_t session_iref = (iref_t)session_oct; *in_iref = (iref_t)in_oct; *out_iref = (iref_t)out_oct; *conf_iref = (iref_t)conf_oct; if (err_is_fail(err)) { err_push(err, TERM_ERR_PARSE_SESSION_RECORD); goto out; } if ((*in_iref == NULL_IREF) || (*out_iref == NULL_IREF) || (*conf_iref == NULL_IREF)) { err = TERM_ERR_PARSE_SESSION_RECORD; goto out; } TERM_DEBUG("Retrieved interface references from octopus. in_iref: %" PRIuIREF ", out_iref: %" PRIuIREF ", conf_iref: %" PRIuIREF "\n", *in_iref, *out_iref, *conf_iref); out: free(record); return err; }
static void exit_cb(void *arg) { struct term_client *client = arg; client->connected = false; TERM_DEBUG("Disconnect message sucessfully sent to terminal server.\n"); }
/** * \brief Retrieve interface references for incoming and outgoing characters * as well as for configuration messages from octopus. */ static errval_t get_irefs(struct capref session_id, iref_t *in_iref, iref_t *out_iref, iref_t *conf_iref) { errval_t err; struct octopus_rpc_client *r = get_octopus_rpc_client(); assert(r != NULL); char *record; errval_t error_code; octopus_trigger_id_t tid; err = r->vtbl.get_with_idcap(r, session_id, NOP_TRIGGER, &record, &tid, &error_code); if (err_is_fail(err)) { err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD); goto out; } err = error_code; if (err_is_fail(err)) { err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD); goto out; } TERM_DEBUG("Record retrieved from octopus: %s\n", record); iref_t session_iref; err = oct_read(record, "_ { session_iref: %d, in_iref: %d, out_iref: %d, " "conf_iref: %d }", &session_iref, in_iref, out_iref, conf_iref); if (err_is_fail(err)) { err_push(err, TERM_ERR_PARSE_SESSION_RECORD); goto out; } if ((*in_iref == NULL_IREF) || (*out_iref == NULL_IREF) || (*conf_iref == NULL_IREF)) { err = TERM_ERR_PARSE_SESSION_RECORD; goto out; } TERM_DEBUG("Retrieved interface references from octopus. in_iref: %" PRIuIREF ", out_iref: %" PRIuIREF ", conf_iref: %" PRIuIREF "\n", *in_iref, *out_iref, *conf_iref); out: free(record); return err; }
/** * \brief Tear down connection to terminal server. * * \param client Terminal client state. * * Dispatches the control waitset until the message is sent. */ void term_client_blocking_exit(struct term_client *client) { errval_t err; TERM_DEBUG("Sending disconnect message to terminal device.\n"); /* Inform terminal device (server), that domain terminated. */ err = client->conf_binding->tx_vtbl.disconnect(client->conf_binding, MKCONT(exit_cb, client)); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Error sending disconnect to terminal device.\n"); } /* Wait until message is sent. Necessary to ensure that message is sent * before we terminate. */ TERM_DEBUG("Waiting until disconnect message is sent.\n"); while (client->connected) { err = event_dispatch(client->conf_ws); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Error dispatching events."); } } }