Add functionality to store caps with unique IDs.
authorGerd Zellweger <mail@gerdzellweger.com>
Thu, 20 Apr 2017 15:10:09 +0000 (17:10 +0200)
committerGerd Zellweger <mail@gerdzellweger.com>
Thu, 20 Apr 2017 15:15:53 +0000 (17:15 +0200)
This is similar to set_sequential in octopus that
allows to have unique record names generated by
the server.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>

if/octopus.if
include/octopus/capability_storage.h
include/octopus_server/service.h
lib/octopus/client/capability_storage.c
lib/octopus/server/capstorage.c
lib/octopus/server/init.c

index 87d1a81..ce0a787 100644 (file)
@@ -184,7 +184,8 @@ interface octopus "octopus RPC Interface" {
     //
 
     // Simple capability storage
-    rpc get_cap(in String key[2048], out cap retcap, out errval reterr);
-    rpc put_cap(in String key[2048], in cap storecap, out errval reterr);
-    rpc remove_cap(in String key[2048], out errval reterr);
+    rpc get_cap(in String key[256], out cap retcap, out errval reterr);
+    rpc put_cap(in String key[256], in cap storecap, out errval reterr);
+    rpc sput_cap(in String key[256], in cap storecap, out String retkey[256], out errval reterr);
+    rpc remove_cap(in String key[256], out errval reterr);
 };
index b1f5924..d101e83 100644 (file)
@@ -16,6 +16,7 @@
 
 errval_t oct_get_capability(const char*, struct capref*);
 errval_t oct_put_capability(const char*, struct capref);
+errval_t oct_sput_capability(const char*, struct capref, char** retkey);
 errval_t oct_remove_capability(const char*);
 
 #endif /* OCTOPUS_CAPABILITY_STORAGE_H_ */
index 8d4fbd5..104f186 100644 (file)
@@ -51,6 +51,7 @@ struct oct_reply_state {
 
     // For capability storage
     struct capref cap;
+    char* retkey;
 
     struct oct_reply_state *next;
 };
@@ -79,6 +80,7 @@ void identify_binding(struct octopus_binding*, uint64_t, octopus_binding_type_t)
 // Capability Storage
 void get_cap_handler(struct octopus_binding*, const char*);
 void put_cap_handler(struct octopus_binding*, const char*, struct capref);
+void sput_cap_handler(struct octopus_binding*, const char*, struct capref);
 void remove_cap_handler(struct octopus_binding*, const char*);
 
 #endif /* OCTOPUS_SERVICE_H_ */
index d35b79d..477d5d9 100644 (file)
@@ -64,6 +64,40 @@ errval_t oct_put_capability(const char *key, struct capref cap)
 }
 
 /**
+ * \brief Put a capability to the capability store with a generated identifier.
+ *
+ * The server appends a globally unique ID to the key and returns
+ * the generated ID as part of retkey.
+ * The caller is responsible to free retkey.
+ *
+ * \param[in] key           Base key (server appends this with unique ID).
+ * \param[in] cap           The capability to store
+ * \param[out] retkey       Allocated string of generated unique identifier.
+ */
+errval_t oct_sput_capability(const char *key, struct capref cap, char **outkey)
+{
+    errval_t err;
+    struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
+    assert(cl != NULL);
+
+    struct octopus_sput_cap_response__rx_args reply;
+    err = cl->call_seq.sput_cap(cl, key, cap, reply.retkey, &reply.reterr);
+    if(err_is_fail(err)) {
+        return err;
+    }
+    //printf("%s:%s:%d: stored key= %s retkey = %s\n", __FILE__, __FUNCTION__, __LINE__, key, reply.retkey);
+    if (err_is_fail(reply.reterr)) {
+        DEBUG_ERR(reply.reterr, "call failed.");
+    }
+
+    if (reply.retkey != NULL) {
+        *outkey = strdup(reply.retkey);
+    }
+
+    return reply.reterr;
+}
+
+/**
  * \brief Remove a capability from the capability store.
  *
  * \param key           String that identifies the capability
index d546131..32a2751 100644 (file)
@@ -112,6 +112,62 @@ void put_cap_handler(struct octopus_binding *b, const char *key,
     ns->reply(b, ns);
 }
 
+static void free_ns(void* arg) {
+    struct oct_reply_state* ns = (struct oct_reply_state*) arg;
+    free(ns->retkey);
+    free(ns);
+}
+
+static void sput_cap_reply(struct octopus_binding *b,
+        struct oct_reply_state* ns)
+{
+    errval_t err;
+    err = b->tx_vtbl.sput_cap_response(b, MKCONT(free_ns, ns), ns->retkey, ns->error);
+    if (err_is_fail(err)) {
+        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+            oct_rpc_enqueue_reply(b, ns);
+            return;
+        }
+        USER_PANIC_ERR(err, "SKB: sending %s failed!", __FUNCTION__);
+    }
+}
+
+void sput_cap_handler(struct octopus_binding *b, const char *key,
+                      struct capref cap)
+{
+    errval_t err, reterr = SYS_ERR_OK;
+    struct oct_reply_state* ns = NULL;
+    struct capref dbcap;
+    // Identfier to make sure all caps have a unique key
+    static uint32_t CAP_IDENT = 0;
+
+    char* uniquekey = NULL;
+    int r = asprintf(&uniquekey, "%s%d", key, CAP_IDENT++);
+    if (uniquekey == NULL || r == -1) {
+        reterr = LIB_ERR_MALLOC_FAIL;
+        goto out;
+    }
+
+    capdb->d.get_capability(&capdb->d, (CONST_CAST)key, &dbcap);
+    if(!capcmp(dbcap, NULL_CAP)) {
+        // This case is not intended to happen
+        // but can if a malicious client takes a key
+        reterr = OCT_ERR_CAP_OVERWRITE;
+    } else {
+        // we need to make our own copy of the key
+        char* dupkey = strdup(uniquekey);
+        r = capdb->d.put_capability(&capdb->d, (CONST_CAST)dupkey, cap);
+        assert(r == 0);
+    }
+
+out:
+    err = new_oct_reply_state(&ns, sput_cap_reply);
+    assert(err_is_ok(err));
+    ns->retkey = uniquekey;
+    ns->error = reterr;
+    ns->reply(b, ns);
+}
+
 static void remove_cap_reply(struct octopus_binding *b,
         struct oct_reply_state* ns)
 {
index 71fb07e..6d38dde 100644 (file)
@@ -52,6 +52,7 @@ static const struct octopus_rx_vtbl rpc_rx_vtbl = {
         // Cap storage
         .get_cap_call = get_cap_handler,
         .put_cap_call = put_cap_handler,
+        .sput_cap_call = sput_cap_handler,
         .remove_cap_call = remove_cap_handler,
 };