1/* 2 * Copyright (c) 2012, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, 8 * Attn: Systems Group. 9 */ 10 11#include <assert.h> 12#include <stdbool.h> 13#include <stdio.h> 14 15#include <angler/angler.h> 16#include <barrelfish/barrelfish.h> 17#include <barrelfish/domain.h> 18#include <barrelfish/nameservice_client.h> 19#include <barrelfish/waitset.h> 20#include <if/monitor_defs.h> 21#include <if/terminal_session_defs.h> 22#include <if/terminal_session_defs.h> 23#include <if/octopus_defs.h> 24#include <octopus/getset.h> /* For SET_DEFAULT */ 25#include <octopus/trigger.h> /* For NOP_TRIGGER */ 26 27/** 28 * Format of the session record stored at octopus. 29 */ 30#define SESSION_OCT_RECORD "{session_iref: %" PRIuIREF ", in_iref: %" PRIuIREF \ 31 ", out_iref: %" PRIuIREF ", conf_iref: %" PRIuIREF \ 32 "}" 33 34/* internal state */ 35struct _angler_state { 36 errval_t err; 37 struct terminal_session_binding *binding; 38}; 39 40/* internal functions */ 41static void bind_cb(void *st, errval_t err, struct terminal_session_binding *b); 42static errval_t store_session_state(struct capref *session_id, 43 iref_t session_iref, iref_t in_iref, 44 iref_t out_iref, iref_t conf_iref); 45 46/** 47 * \brief Start a new session. 48 * 49 * \param terminal Terminal used for the session. 50 * \param session_id ID capability representing the session. Filled-in by 51 * function. 52 */ 53errval_t angler_new_session(char *terminal, struct capref *session_id) 54{ 55 errval_t err; 56 iref_t iref; 57 58 assert(terminal != NULL); 59 assert(session_id != NULL); 60 61 /* Lookup terminal session iref at nameservice. */ 62 err = nameservice_blocking_lookup(terminal, &iref); 63 if (err_is_fail(err)) { 64 return err_push(err, ANGLER_ERR_LOOKUP_TERMINAL); 65 } 66 67 return angler_new_session_with_iref(iref, session_id); 68} 69 70/** 71 * \brief Start a new session. 72 * 73 * \param session_iref Interface reference of session interface of terminal that 74 * is used for the session. 75 * \param session_id ID capability representing the session. Filled-in by 76 * function. 77 */ 78errval_t angler_new_session_with_iref(iref_t session_iref, 79 struct capref *session_id) 80{ 81 errval_t err = SYS_ERR_OK; 82 errval_t error = SYS_ERR_OK; 83 struct _angler_state *state = NULL; 84 struct waitset ws; 85 iref_t in_iref; 86 iref_t out_iref; 87 iref_t conf_iref; 88 89 assert(session_id != NULL); 90 91 /* Create ID capability used to represent the session. */ 92 err = idcap_alloc(session_id); 93 if (err_is_fail(err)) { 94 return err_push(err, ANGLER_ERR_CREATE_SESSIONID); 95 } 96 97 /* Initialize internal state */ 98 state = malloc(sizeof(struct _angler_state)); 99 assert(state != NULL); 100 state->err = SYS_ERR_OK; 101 state->binding = NULL; 102 103 /* Bind to terminal session interface */ 104 waitset_init(&ws); 105 err = terminal_session_bind(session_iref, bind_cb, state, &ws, 106 IDC_BIND_FLAG_RPC_CAP_TRANSFER); 107 if (err_is_fail(err)) { 108 err = err_push(err, ANGLER_ERR_BIND_TERMINAL); 109 goto out; 110 } 111 112 /* Wait on the monitor until the bind completes. */ 113 struct monitor_binding *monitor_b = get_monitor_binding(); 114 struct waitset *monitor_ws = monitor_b->waitset; 115 while (state->binding == NULL) { 116 err = event_dispatch(monitor_ws); 117 if (err_is_fail(err) || err_is_fail(state->err)) { 118 err = err_push(err, ANGLER_ERR_BIND_TERMINAL); 119 goto out; 120 } 121 } 122 123 /* Initialize rpc client. */ 124 terminal_session_rpc_client_init(state->binding); 125 126 /* Associate session with terminal. */ 127 err = state->binding->rpc_tx_vtbl.session_associate_with_terminal 128 (state->binding, *session_id, &in_iref, &out_iref, &conf_iref, &error); 129 if (err_is_fail(err)) { 130 err = err_push(err, ANGLER_ERR_ASSOCIATE_WITH_TERMINAL); 131 goto out; 132 } 133 if (err_is_fail(error)) { 134 err = error; 135 err = err_push(err, ANGLER_ERR_ASSOCIATE_WITH_TERMINAL); 136 goto out; 137 } 138 139 /* Store session state at octopus using session id as access control. */ 140 err = store_session_state(session_id, session_iref, in_iref, out_iref, 141 conf_iref); 142 if (err_is_fail(err)) { 143 err = err_push(err, ANGLER_ERR_STORE_SESSION_STATE); 144 } 145 146out: 147 free(state); 148 return err; 149} 150 151/** 152 * \privatesection 153 * Internal functions and bind code follow. 154 */ 155static void bind_cb(void *st, errval_t err, struct terminal_session_binding *b) 156{ 157 struct _angler_state *state = st; 158 159 if (err_is_fail(err)) { 160 state->err = err; 161 } else { 162 state->binding = b; 163 } 164} 165 166static errval_t store_session_state(struct capref *session_id, 167 iref_t session_iref, iref_t in_iref, 168 iref_t out_iref, iref_t conf_iref) 169{ 170 errval_t err = SYS_ERR_OK; 171 errval_t error; 172 struct octopus_binding *rpc_client = NULL; 173 char *attributes = NULL; 174 size_t attributes_len = 0; 175 octopus_trigger_id_t tid; 176 177 rpc_client = get_octopus_binding(); 178 assert(rpc_client != NULL); 179 180 /* Build attributes. */ 181 attributes_len = snprintf(NULL, 0, SESSION_OCT_RECORD, session_iref, 182 in_iref, out_iref, conf_iref); 183 attributes = malloc(attributes_len + 1); 184 assert(attributes != NULL); 185 snprintf(attributes, attributes_len + 1, SESSION_OCT_RECORD, session_iref, 186 in_iref, out_iref, conf_iref); 187 188 189 /* Store record at octopus. */ 190 err = rpc_client->rpc_tx_vtbl.set_with_idcap(rpc_client, *session_id, attributes, 191 SET_DEFAULT, NOP_TRIGGER, false, 192 NULL, &tid, &error); 193 if (err_is_fail(err)) { 194 goto out; 195 } 196 if (err_is_fail(error)) { 197 err = error; 198 goto out; 199 } 200 201out: 202 free(attributes); 203 return err; 204} 205