Octopus: Add ability to set and get records by id capability.
authorRaphael Fuchs <fuchs.raphael@gmail.com>
Tue, 25 Jun 2013 20:47:50 +0000 (22:47 +0200)
committerRaphael Fuchs <fuchs.raphael@gmail.com>
Tue, 25 Jun 2013 20:47:50 +0000 (22:47 +0200)
The intent with this patch is that only someone possesing a certain id cap
can retrieve records that were stored with this id cap.

To this end, two new functions were added to the client interface of octopus:

* oct_set_with_idcap(struct capref idcap, const char *attributes, ...)
  Sets a record using the id capability as the key/name of the record.

* oct_get_with_idcap(char **data, struct capref idcap)
  Retrieves a record using the id capability as the key/name.

Note that octopus and the SKB do not support dedicated namespaces atm.
Therefore a record saved with oct_set_with_idcap() could be retrieved by
oct_get().

Moreover, format octopus.if to 80 columns.

errors/errno.fugu
if/octopus.if
include/octopus/getset.h
include/octopus_server/service.h
lib/octopus/client/getset.c
lib/octopus/server/init.c
lib/octopus/server/service.c
usr/tests/octopus/Hakefile
usr/tests/octopus/d2getset_idcap.c [new file with mode: 0644]

index eca7b32..1ace86c 100644 (file)
@@ -835,6 +835,7 @@ errors octopus  OCT_ERR_ {
     failure INVALID_ID          "Invalid Trigger ID.",
     failure CAP_NAME_UNKNOWN    "Capability storage: Unknown name.",
     failure CAP_OVERWRITE       "Capability storage: Cap already exists.",
+    failure IDCAP_INVOKE        "Error invoking ID capability.",
 };
 
 // kaluga library errors
index d78c880..8b3907d 100644 (file)
@@ -1,10 +1,11 @@
 /*
- * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * Copyright (c) 2007, 2008, 2009, 2012, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
  */
 
 interface octopus "octopus RPC Interface" {
@@ -40,7 +41,8 @@ interface octopus "octopus RPC Interface" {
      * \param tid Id of registered trigger (0 in case no trigger registered).
      * \param error_code Error value of request.
      */
-    rpc get_names(in string query, in trigger t, out string output, out trigger_id tid, out errval error_code);
+    rpc get_names(in string query, in trigger t, out string output,
+                  out trigger_id tid, out errval error_code);
     
     /**
      * \param query Record to find.
@@ -49,7 +51,8 @@ interface octopus "octopus RPC Interface" {
      * \param tid Id of registered trigger (0 in case no trigger registered).
      * \param error_code Error value of request.
      */
-    rpc get(in string query, in trigger t, out string output, out trigger_id tid, out errval error_code);
+    rpc get(in string query, in trigger t, out string output,
+            out trigger_id tid, out errval error_code);
         
     /**
      * \param query Record to set.
@@ -61,7 +64,37 @@ interface octopus "octopus RPC Interface" {
      * \param tid Id of registered trigger (0 in case no trigger registered).
      * \param error_code Error value of request
      */
-    rpc set(in string query, in uint64 mode, in trigger t, in bool get, out string record, out trigger_id tid, out errval error_code);
+    rpc set(in string query, in uint64 mode, in trigger t, in bool get,
+            out string record, out trigger_id tid, out errval error_code);
+
+    /**
+     * Find a record using an ID capability as the key/name of the record.
+     *
+     * \param idcap ID capability used as the name of the record.
+     * \param t Additional trigger to watch for future events.
+     * \param output Retrieved record or NULL on error.
+     * \param tid Id of registered trigger (0 in case no trigger registered).
+     * \param error_code Error value of request.
+     */
+    rpc get_with_idcap(in cap idcap, in trigger t, out string output,
+                       out trigger_id tid, out errval error_code);
+
+    /**
+     * Set a record using an ID capability as the key/name of the record.
+     *
+     * \param idcap ID capability used as the key/name of the record.
+     * \param attributes Attributes to store in the record.
+     * \param mode Set mode (see getset.h).
+     * \param t Additional trigger to watch for future events.
+     * \param get Return record if it has been set.
+     * \param record In case get is true and no error_code is ok
+     *               contains record, otherwise NULL
+     * \param tid Id of registered trigger (0 in case no trigger registered).
+     * \param error_code Error value of request
+     */
+    rpc set_with_idcap(in cap idcap, in string attributes, in uint64 mode,
+                       in trigger t, in bool get, out string record,
+                       out trigger_id tid, out errval error_code);
     
     /**
      * \param query Record(s) to delete.
@@ -69,7 +102,8 @@ interface octopus "octopus RPC Interface" {
      * \param tid Id of registered trigger (0 in case no trigger registered).
      * \param error_code Error value of request
      */
-    rpc del(in string query, in trigger t, out trigger_id tid, out errval error_code);    
+    rpc del(in string query, in trigger t, out trigger_id tid,
+            out errval error_code);
     
     /**
      * \param query
@@ -77,7 +111,8 @@ interface octopus "octopus RPC Interface" {
      * \param tid Id of registered trigger (0 in case no trigger registered).
      * \param error_code Error value of request.
      */
-    rpc exists(in string query, in trigger t, out trigger_id tid, out errval error_code);
+    rpc exists(in string query, in trigger t, out trigger_id tid,
+               out errval error_code);
     
     /**
      * \brief Blocks until a record matching the provided query is registered.
@@ -118,7 +153,8 @@ interface octopus "octopus RPC Interface" {
      * \param id Identifier for this subscription supplied by server.
      * \param error_code Status of request.
      */
-    rpc subscribe(in string query, in uint64 trigger_fn, in uint64 state, out uint64 id, out errval error_code);
+    rpc subscribe(in string query, in uint64 trigger_fn, in uint64 state,
+                  out uint64 id, out errval error_code);
     
     /**
      * \param id Id for the subscription
@@ -136,8 +172,11 @@ interface octopus "octopus RPC Interface" {
     //
     // Async events (sent by server to client)
     //
-    message trigger(trigger_id id, uint64 trigger_fn, mode m, string record, uint64 state);
-    message subscription(trigger_id id, uint64 trigger_fn, mode m, string record, uint64 state);
+    message trigger(trigger_id id, uint64 trigger_fn, mode m, string record,
+                    uint64 state);
+
+    message subscription(trigger_id id, uint64 trigger_fn, mode m,
+                         string record, uint64 state);
     
 
     //
index 7095230..a987d7e 100644 (file)
@@ -34,6 +34,8 @@ void oct_free_names(char**, size_t);
 
 errval_t oct_get(char**, const char*, ...);
 errval_t oct_set(const char*, ...);
+errval_t oct_get_with_idcap(char**, struct capref);
+errval_t oct_set_with_idcap(struct capref, const char*, ...);
 errval_t oct_mset(oct_mode_t, const char*, ...);
 errval_t oct_set_get(oct_mode_t, char**, const char*, ...);
 errval_t oct_del(const char*, ...);
index 7ab1034..642e1b2 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2011, 2012, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
  */
 
 #ifndef OCTOPUS_SERVICE_H_
@@ -59,6 +60,10 @@ errval_t new_oct_reply_state(struct oct_reply_state**, oct_reply_handler_fn);
 void get_names_handler(struct octopus_binding*, char*, octopus_trigger_t);
 void get_handler(struct octopus_binding*, char*, octopus_trigger_t);
 void set_handler(struct octopus_binding*, char*, uint64_t, octopus_trigger_t, bool);
+void get_with_idcap_handler(struct octopus_binding*, struct capref,
+                            octopus_trigger_t);
+void set_with_idcap_handler(struct octopus_binding*, struct capref, char*,
+                            uint64_t, octopus_trigger_t, bool);
 void del_handler(struct octopus_binding*, char*, octopus_trigger_t);
 void exists_handler(struct octopus_binding*, char*, octopus_trigger_t);
 void wait_for_handler(struct octopus_binding*, char*);
index 9621c75..8931a30 100644 (file)
@@ -7,12 +7,13 @@
  */
 
 /*
- * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2011, 2012, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
  */
 
 #include <stdlib.h>
@@ -340,6 +341,77 @@ errval_t oct_set_get(oct_mode_t mode, char** record, const char* query, ...)
 }
 
 /**
+ * \brief Gets one record using the ID capability as the key/name.
+ *
+ * \param[out] data Record returned by the server.
+ * \param[in] idcap ID capability used as the key/name of the record.
+ *
+ * \retval SYS_ERR_OK
+ * \retval OCT_ERR_NO_RECORD
+ * \retval OCT_ERR_PARSER_FAIL
+ * \retval OCT_ERR_ENGINE_FAIL
+ */
+errval_t oct_get_with_idcap(char **data, struct capref idcap)
+{
+    assert(!capref_is_null(idcap));
+    errval_t error_code;
+    errval_t err = SYS_ERR_OK;
+    octopus_trigger_id_t tid;
+
+    struct octopus_thc_client_binding_t *cl = oct_get_thc_client();
+    assert(cl != NULL);
+    err = cl->call_seq.get_with_idcap(cl, idcap, NOP_TRIGGER, data, &tid,
+                                      &error_code);
+
+    if (err_is_ok(err)) {
+        err = error_code;
+    }
+
+    return err;
+}
+
+/**
+ * \brief Sets a record using the ID capability as the name/key of the record.
+ *
+ * \param idcap      ID capability used as the name/key of the record.
+ * \param attributes Attributes of the record.
+ * \param ...        Additional arguments to format the attributes using
+ *                   vsprintf.
+ *
+ * \retval SYS_ERR_OK
+ * \retval OCT_ERR_NO_RECORD_NAME
+ * \retval OCT_ERR_PARSER_FAIL
+ * \retval OCT_ERR_ENGINE_FAIL
+ */
+errval_t oct_set_with_idcap(struct capref idcap, const char *attributes, ...)
+{
+    assert(!capref_is_null(idcap));
+    assert(attributes != NULL);
+    errval_t err = SYS_ERR_OK;
+    va_list args;
+
+    char *buf = NULL;
+    FORMAT_QUERY(attributes, args, buf);
+
+    // Send to Server
+    struct octopus_thc_client_binding_t *cl = oct_get_thc_client();
+
+    char *record = NULL;
+    errval_t error_code;
+    octopus_trigger_id_t tid;
+    err = cl->call_seq.set_with_idcap(cl, idcap, buf, SET_DEFAULT, NOP_TRIGGER,
+                                      false, &record, &tid, &error_code);
+    assert(record == NULL);
+
+    if (err_is_ok(err)) {
+        err = error_code;
+    }
+
+    free(buf);
+    return err;
+}
+
+/**
  * \brief Deletes all records matching the given query.
  *
  * \param query Specifies the record(s) to be deleted.
index 7467289..cf4dec2 100644 (file)
@@ -6,12 +6,13 @@
  */
 
 /*
- * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2011, 2012, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
  */
 
 #include <barrelfish/barrelfish.h>
@@ -35,6 +36,8 @@ static const struct octopus_rx_vtbl rpc_rx_vtbl = {
         .get_names_call = get_names_handler,
         .get_call = get_handler,
         .set_call = set_handler,
+        .get_with_idcap_call = get_with_idcap_handler,
+        .set_with_idcap_call = set_with_idcap_handler,
         .del_call = del_handler,
         .exists_call = exists_handler,
         .wait_for_call = wait_for_handler,
index 89b7eb9..bc83059 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2009, 2010, ETH Zurich.
+ * Copyright (c) 2009, 2010, 2012, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
  */
 
 #include <stdio.h>
 
 #include "queue.h"
 
+/**
+ * Name prefix used to by the functions set_with_idcap_handler() and
+ * get_with_idcap_handler() to store and retrieve records by idcap.
+ *
+ * This essentially emulates a dedicated namespace for records stored with an
+ * id cap. Octopus and the SKB do not support dedicated namespaces atm.
+ * FIXME: store records set with the function 'set_with_idcap' in a dedicated
+ *        namespace.
+ */
+#define IDCAPID_NAME_PREFIX "idcapid."
+
 static uint64_t current_id = 1;
 
 static inline errval_t check_query_length(char* query) {
@@ -331,6 +343,160 @@ out:
     free(query);
 }
 
+static errval_t build_query_with_idcap(char **query_p, struct capref idcap,
+                                       char *attributes)
+{
+    errval_t err;
+    idcap_id_t id = 0;
+    size_t query_size, bytes_written;
+
+    // retrieve id from idcap
+    err = invoke_idcap_identify(idcap, &id);
+    if (err_is_fail(err)) {
+        return err_push(err, OCT_ERR_IDCAP_INVOKE);
+    }
+    cap_delete(idcap);
+
+    if (attributes == NULL) {
+        attributes = "";
+    }
+
+    // build query using the idcapid and the attributes
+    query_size = snprintf(NULL, 0, IDCAPID_NAME_PREFIX "%" PRIxIDCAPID "%s", id,
+                          attributes);
+    *query_p = (char *) malloc(query_size + 1); // include \0
+    if (*query_p == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+    bytes_written = snprintf(*query_p, query_size + 1, IDCAPID_NAME_PREFIX
+                             "%" PRIxIDCAPID "%s", id, attributes);
+
+    return SYS_ERR_OK;
+}
+
+static void get_with_idcap_reply(struct octopus_binding *b,
+                                 struct oct_reply_state *drt)
+{
+    errval_t err;
+    char *reply = err_is_ok(drt->error) ?
+                  drt->query_state.std_out.buffer : NULL;
+    err = b->tx_vtbl.get_with_idcap_response(b,
+                                             MKCONT(free_oct_reply_state, drt),
+                                             reply, drt->server_id, drt->error);
+    if (err_is_fail(err)) {
+        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+            oct_rpc_enqueue_reply(b, drt);
+            return;
+        }
+        USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
+    }
+}
+
+void get_with_idcap_handler(struct octopus_binding *b, struct capref idcap,
+                            octopus_trigger_t trigger)
+{
+    errval_t err;
+    char *query = NULL;
+    struct oct_reply_state *drs = NULL;
+    struct ast_object *ast = NULL;
+
+    err = build_query_with_idcap(&query, idcap, "");
+    if (err_is_fail(err)) {
+        goto out;
+    }
+
+    OCT_DEBUG("get_with_idcap_handler: %s\n", query);
+
+    err = new_oct_reply_state(&drs, get_with_idcap_reply);
+    assert(err_is_ok(err));
+
+    err = check_query_length(query);
+    if (err_is_fail(err)) {
+        goto out;
+    }
+
+    err = generate_ast(query, &ast);
+    if (err_is_ok(err)) {
+        err = get_record(ast, &drs->query_state);
+        drs->server_id = install_trigger(b, ast, trigger, err);
+    }
+
+out:
+    drs->error = err;
+    drs->reply(b, drs);
+
+    free_ast(ast);
+    if (query != NULL) {
+        free(query);
+    }
+}
+
+static void set_with_idcap_reply(struct octopus_binding *b,
+                                 struct oct_reply_state *drs)
+{
+    char *record = err_is_ok(drs->error) && drs->return_record ?
+            drs->query_state.std_out.buffer : NULL;
+
+    errval_t err;
+    err = b->tx_vtbl.set_with_idcap_response(b,
+                                             MKCONT(free_oct_reply_state, drs),
+                                             record, drs->server_id,
+                                             drs->error);
+    if (err_is_fail(err)) {
+        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+            oct_rpc_enqueue_reply(b, drs);
+            return;
+        }
+        USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
+    }
+}
+
+void set_with_idcap_handler(struct octopus_binding *b, struct capref idcap,
+                            char *attributes, uint64_t mode,
+                            octopus_trigger_t trigger, bool get)
+{
+    errval_t err;
+    char *query = NULL;
+    struct oct_reply_state *drs = NULL;
+    struct ast_object *ast = NULL;
+
+    err = build_query_with_idcap(&query, idcap, attributes);
+    if (err_is_fail(err)) {
+        goto out;
+    }
+    OCT_DEBUG(" set_with_idcap_handler: %s\n", query);
+
+    err = new_oct_reply_state(&drs, set_with_idcap_reply);
+    assert(err_is_ok(err));
+
+    err = check_query_length(query);
+    if (err_is_fail(err)) {
+        goto out;
+    }
+
+    err = generate_ast(query, &ast);
+    if (err_is_ok(err)) {
+        if (ast->u.on.name->type == nodeType_Ident) {
+            err = set_record(ast, mode, &drs->query_state);
+            drs->server_id = install_trigger(b, ast, trigger, err);
+        } else {
+            err = OCT_ERR_NO_RECORD_NAME;
+        }
+    }
+
+out:
+    drs->error = err;
+    drs->return_record = get;
+    drs->reply(b, drs);
+
+    free_ast(ast);
+    free(attributes);
+    if (query != NULL) {
+        free(query);
+    }
+
+}
+
 static void del_reply(struct octopus_binding* b, struct oct_reply_state* drs)
 {
     errval_t err;
index af685a8..37e040f 100644 (file)
@@ -1,10 +1,11 @@
 --------------------------------------------------------------------------
--- Copyright (c) 2007-2011, ETH Zurich.
+-- Copyright (c) 2007-2011, 2012, ETH Zurich.
 -- All rights reserved.
 --
 -- This file is distributed under the terms in the attached LICENSE file.
 -- If you do not find this file, copies can be found by writing to:
--- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+-- ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+-- Attn: Systems Group.
 --
 -- Hakefile for /usr/tests/octopus
 --
                       architectures = [ "x86_64", "x86_32" ]
                     },
 
+  build application { target = "d2getset_idcap",
+                      cFiles = [ "d2getset_idcap.c" ],
+                      flounderDefs = [ "octopus" ],
+                      flounderBindings = [ "octopus" ],
+                      flounderTHCStubs = [ "octopus" ],
+                      addLibraries = [ "octopus", "octopus_parser", "thc" ],
+                      architectures = [ "x86_64", "x86_32" ]
+                    },
+
   build application { target = "d2pubsub",
                       cFiles = [ "d2pubsub.c" ],
                       flounderDefs = [ "octopus" ],
diff --git a/usr/tests/octopus/d2getset_idcap.c b/usr/tests/octopus/d2getset_idcap.c
new file mode 100644 (file)
index 0000000..f540f16
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * \file
+ * \brief Tests for octopus get_with_idcap/set_with_idcap API
+ */
+
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
+ */
+
+#include <stdio.h>
+
+#include <barrelfish/barrelfish.h>
+#include <octopus/octopus.h>
+
+#include "common.h"
+
+struct capref idcap1, idcap2;
+
+static void set_records(void)
+{
+    errval_t err;
+
+    err = idcap_alloc(&idcap1);
+    ASSERT_ERR_OK(err);
+
+    err = idcap_alloc(&idcap2);
+    ASSERT_ERR_OK(err);
+
+    err = oct_set_with_idcap(idcap1, "{session_iref: %d, io_iref: %d}", 1, 2);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Error installing first record.");
+    }
+    ASSERT_ERR_OK(err);
+
+    err = oct_set_with_idcap(idcap2, "{session_iref: %d, io_iref: %d}", 3, 4);
+    ASSERT_ERR_OK(err);
+}
+
+static void get_records(void)
+{
+    errval_t err;
+
+    char *data = NULL;
+
+    err = oct_get_with_idcap(&data, idcap1);
+    printf("idcap1-record: %s\n", data);
+
+    err = oct_get_with_idcap(&data, idcap2);
+    printf("idcap2-record: %s\n", data);
+}
+
+int main(int argc, char *argv[])
+{
+    oct_init();
+
+    set_records();
+    get_records();
+
+    printf("d2getset SUCESS!\n");
+    return EXIT_SUCCESS;
+}