obj.c 87.6 KB
Newer Older
Josh Kunz's avatar
Josh Kunz committed
1
#include <stdlib.h>
2
#include <stdbool.h>
3
#include <assert.h>
Josh Kunz's avatar
Josh Kunz committed
4 5
#include <libcap.h>
#include <glib.h>
6

7
#include "metadata.h"
8
#include "obj.h"
Josh Kunz's avatar
Josh Kunz committed
9
#include "obj_waiting.h"
10
#include "util.h"
11
#include "errors.h"
12 13
#include "dispatch.h"
#include "controller.h"
Josh Kunz's avatar
Josh Kunz committed
14

15
#include "capnet_ref.h"
16 17
#include "capnet_log.h"

18
/* Used as the declassifier on annotations that were added nominally by
19 20
 * the system itself. This is special cased in a bunch of cases in the code
 * below. */
21 22
static const void * OBJ_SYSTEM_DECLASSIFIER = (void *) 0xdeadc0deUL;

23
cap_type_t TYPE_MAP[__CN_MAX_TYPE];
Josh Kunz's avatar
Josh Kunz committed
24

25 26
/* objtype free function adapters */ 

27
#define OBJ_FREE(_type,objtype) \
28
    (cn_obj_t *p) { \
29 30 31
        assert(p->type == objtype && "Type is not a " #_type " type"); \
        cn_ ## _type ## _free((cn_ ## _type ## _t *) p); \
    }
Josh Kunz's avatar
Josh Kunz committed
32

33
/* Generic free function for all cn_obj_t objects */
34
REFCNT __OBJ_free(cn_obj_t *obj, int i) {
35 36
    obj->free(obj); 
    return 0; }
Josh Kunz's avatar
Josh Kunz committed
37

38
/* Return the cn_objtype_t for the given cap_type_t or abort */
39
static inline cn_objtype_t _captype_to_objtype(cap_type_t t) {
40
    for (int i = 0; i < __CN_MAX_TYPE; i++) {
41
        if (TYPE_MAP[i] == t) { return i; }
42 43
    }
    cn_abort("No obj_type_t equivalent to cap_type_t %#0x", t);
Josh Kunz's avatar
Josh Kunz committed
44
}
45

Josh Kunz's avatar
Josh Kunz committed
46 47
static const char * TYPE_NAMES[__CN_MAX_TYPE] = {
    "switch", "port", "principal", "node",
48 49
    "flow", "rp", "membrane", "broker", 
    "node-grant", "sealer-unsealer",
Josh Kunz's avatar
Josh Kunz committed
50 51 52 53
};

const char * cn_objtype_name(cn_objtype_t type) { return TYPE_NAMES[type]; }

54 55
/* typeops for each type */

Josh Kunz's avatar
Josh Kunz committed
56 57
#define DEFAULT_TYPE_OPS(typename)      \
    { .name = # typename,               \
58
      .insert = cn_default_insert_cb,   \
Josh Kunz's avatar
Josh Kunz committed
59 60 61
      .delete = cn_default_delete_cb,   \
      .grant = cn_default_grant_cb,     \
      .derive_src = NULL,               \
62
      .derive_dst = cn_default_derive_dst_cb }
Josh Kunz's avatar
Josh Kunz committed
63

64 65 66
static const struct cap_type_ops _flow_ops = {
    .name = "flow",
    .insert = cn_insert_flow_cb,
67
    .delete = cn_delete_flow_cb,
68
    .grant = cn_grant_flow_cb,
69 70
    .derive_src = NULL, 
    .derive_dst = cn_default_derive_dst_cb
Josh Kunz's avatar
Josh Kunz committed
71 72
};

73
static const struct cap_type_ops _node_ops = DEFAULT_TYPE_OPS(node);
74 75
static const struct cap_type_ops _rp_ops = DEFAULT_TYPE_OPS(rp);
static const struct cap_type_ops _membrane_ops = DEFAULT_TYPE_OPS(membrane);
David Johnson's avatar
David Johnson committed
76
static const struct cap_type_ops _broker_ops = DEFAULT_TYPE_OPS(broker);
Josh Kunz's avatar
Josh Kunz committed
77
static const struct cap_type_ops _node_grant_ops = DEFAULT_TYPE_OPS(node_grant);
Josh Kunz's avatar
Josh Kunz committed
78
static const struct cap_type_ops _sealer_unsealer_ops = DEFAULT_TYPE_OPS(sealer_unsealer);
Josh Kunz's avatar
Josh Kunz committed
79

80
int cn_init(void) {
81
#ifdef HAVE_CPTR_INIT
Josh Kunz's avatar
Josh Kunz committed
82
    cptr_init();
83
#endif
Josh Kunz's avatar
Josh Kunz committed
84
    if (cap_init() != 0) { return -1; }
85
    TYPE_MAP[CN_FLOW] = cap_register_type(0, &_flow_ops);
86 87 88
    TYPE_MAP[CN_NODE] = cap_register_type(0, &_node_ops);
    TYPE_MAP[CN_RP] = cap_register_type(0, &_rp_ops);
    TYPE_MAP[CN_MEMBRANE] = cap_register_type(0, &_membrane_ops);
David Johnson's avatar
David Johnson committed
89
    TYPE_MAP[CN_BROKER] = cap_register_type(0, &_broker_ops);
Josh Kunz's avatar
Josh Kunz committed
90
    TYPE_MAP[CN_NODE_GRANT] = cap_register_type(0, &_node_grant_ops);
Josh Kunz's avatar
Josh Kunz committed
91
    TYPE_MAP[CN_SEALER_UNSEALER] = cap_register_type(0, &_sealer_unsealer_ops);
Josh Kunz's avatar
Josh Kunz committed
92 93 94
    return 0;
}

95
void cn_fini(void) {
Josh Kunz's avatar
Josh Kunz committed
96 97 98
    cap_fini();
}

99 100 101
/* Initialize the given object. The given type and free method will
 * be used as the object's type and free method */
void _obj_init(cn_obj_t *obj, cn_objtype_t type, cn_obj_free_f free) {
102
    c_log_debug("Initing with type: %d", type);
103 104 105 106
    obj->type = type;
    OBJSNEW(obj);
    obj->refcnt = 0;

Josh Kunz's avatar
Josh Kunz committed
107 108 109 110
    (void) pthread_mutexattr_init(&obj->lock_attr);
    (void) pthread_mutexattr_settype(&obj->lock_attr, PTHREAD_MUTEX_RECURSIVE_NP);
    (void) pthread_mutex_init(&obj->lock, &obj->lock_attr);

111 112 113 114 115
    obj->free = free;
}

/* sec: Principals */

116 117
static void _cn_principal_free OBJ_FREE(principal, CN_PRINCIPAL)

118
int cn_principal_init(cn_principal_t *p) {
Josh Kunz's avatar
Josh Kunz committed
119 120 121 122
    struct cspace *cspace = cap_alloc_cspace();
    if (cspace == NULL) { return -1; }

    if (cap_init_cspace(cspace) != 0) { goto fail; }
123 124
    if (cptr_cache_alloc(&p->cache) != 0) { goto fail; }
    if (cptr_cache_init(p->cache) != 0) { goto fail; }
Josh Kunz's avatar
Josh Kunz committed
125 126

    p->cspace = cspace;
127
    cap_cspace_set_owner(p->cspace, (void *) p);
Josh Kunz's avatar
Josh Kunz committed
128

Josh Kunz's avatar
Josh Kunz committed
129 130
    p->owner = NULL;

Josh Kunz's avatar
Josh Kunz committed
131 132 133 134 135 136
    return 0;
fail:
    cap_free_cspace(cspace);
    return -1;
}

137
int cn_principal_new(cn_principal_t **out) {
138
    cn_principal_t *principal = calloc(1,sizeof(*principal));
Josh Kunz's avatar
Josh Kunz committed
139 140
    if (principal == NULL) { goto fail; }

141 142
    _obj_init(&principal->obj, CN_PRINCIPAL, _cn_principal_free);

143
    if (cn_principal_init(principal) != 0) { goto fail; }
Josh Kunz's avatar
Josh Kunz committed
144 145 146 147 148 149 150 151
    *out = principal;

    return 0;
fail:
    free(principal);
    return -1;
}

152
void cn_principal_free(cn_principal_t *p) {
Josh Kunz's avatar
Josh Kunz committed
153 154 155 156 157 158
    cap_destroy_cspace(p->cspace);
    cptr_cache_destroy(p->cache);
    free(p->cspace);
    free(p);
}

159
/* Re-initialize the given principal, i.e., clear all of its cptrs and cnodes. */
160
int cn_principal_clear(cn_principal_t *p) {
Josh Kunz's avatar
Josh Kunz committed
161 162
    cap_destroy_cspace(p->cspace);
    cptr_cache_destroy(p->cache);
163
    return cn_principal_init(p);
Josh Kunz's avatar
Josh Kunz committed
164 165
}

166 167
/* Insert the given object into the given principal. The resulting cptr
 * is stored in o_cptr. */
168
int cn_principal_insert(cn_principal_t *p, cn_obj_t *o, void * payload, cptr_t *o_cptr) {
Josh Kunz's avatar
Josh Kunz committed
169
    if (cptr_alloc(p->cache, o_cptr) != 0) { return -1; }
170
    if (cap_insert(p->cspace, *o_cptr, o, TYPE_MAP[o->type], payload) != 0) { goto fail; }
Josh Kunz's avatar
Josh Kunz committed
171 172 173
    /* Make either the owner of the principal, or the principal if it has no owner
     * hold a reference to the inserted object. */
    RHOLD_OBJ(o, p->owner != NULL ? p->owner : p);
Josh Kunz's avatar
Josh Kunz committed
174 175 176 177 178 179
    return 0;
fail:
    cptr_free(p->cache, *o_cptr);
    return -1;
}

180 181
void * cn_principal_owner(cn_principal_t *p) { return p->owner; }

182 183
/* sec: Objects */

184 185 186 187 188 189 190 191 192
/* subsec: Switch Objects */

static void _cn_switch_free OBJ_FREE(switch, CN_SWITCH)

int cn_switch_new(cn_switch_t **o_csw) {
    cn_switch_t *csw;

    csw = calloc(1,sizeof(cn_switch_t));
    if (csw == NULL) { return -1; }
David Johnson's avatar
David Johnson committed
193
    csw->uplink_port_no = -1;
194 195 196
    //csw->lan_to_ports = g_hash_table_new_full(g_str_hash,g_str_equal,
    //                                          NULL,NULL);
    //csw->port_to_lan = g_hash_table_new_full();
197 198
    csw->mac_to_node = g_hash_table_new_full(__mac_hash,__mac_equal,NULL,NULL);
    csw->ipv4_to_node = g_hash_table_new_full(g_direct_hash,g_direct_equal,
199
                                              NULL,NULL);
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

    _obj_init(&csw->obj, CN_SWITCH, _cn_switch_free);

    *o_csw = csw;
    return 0;
}

void cn_switch_free(cn_switch_t *csw) {
    metadata_fini_switch(csw);
    g_hash_table_destroy(csw->mac_to_node);
    g_hash_table_destroy(csw->ipv4_to_node);
    //c_app_switch_put(csw->mul_switch);
    csw->mul_switch = NULL;
    free(csw);
}

/* subsec: Port Objects */

static void _cn_port_free OBJ_FREE(port, CN_PORT)

int cn_port_new(cn_port_t **o_cport) {
    cn_port_t *cport;

    cport = calloc(1,sizeof(cn_port_t));
    if (cport == NULL) { return -1; }

    _obj_init(&cport->obj, CN_PORT, _cn_port_free);

228 229
    cport->nodes = g_list_alloc();
    if (cport->nodes == NULL) { goto fail; }
230 231 232 233 234 235 236 237 238

    *o_cport = cport;
    return -1;

fail:
    free(cport);
    return -1;
}

Josh Kunz's avatar
Josh Kunz committed
239

240
void cn_port_free(cn_port_t *cport) {
Josh Kunz's avatar
Josh Kunz committed
241 242 243 244 245 246 247
    GList *current = cport->nodes;
    while (current != NULL) {
        GList *next = g_list_next(current);
        RPUTs_OBJ(current->data, cport);
        cport->nodes = g_list_delete_link(cport->nodes, current);
        current = next;
    }
248 249 250
    free(cport);
}

251 252 253 254 255 256 257
static void _cn_flow_free OBJ_FREE(flow, CN_FLOW)

/* Make a new flow from the 'to' node with the given flow. contents of the passed
 * flow object are copied out of the flow into a local copy, so no refernce
 * is held. */
int cn_flow_new(cn_node_t *to, struct flow flow_spec, struct flow mask, 
                cn_flow_t **o_flow) {
258
    cn_flow_t *flow = calloc(1,sizeof(*flow));
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    if (flow == NULL) { return -1; }

    flow->flow = flow_spec;
    flow->mask = mask;

    RHOLD_OBJ(to, flow);
    flow->node = to;

    _obj_init(&flow->obj, CN_FLOW, _cn_flow_free);

    cnc_init_flow(flow);

    *o_flow = flow;

    return 0;
}

void cn_flow_free(cn_flow_t *flow) {
    RPUTs_OBJ(flow->node, flow);
    free(flow);
}

281 282
/* subsec: Node Objects */

283 284
static void _cn_node_free OBJ_FREE(node, CN_NODE)

285
int cn_node_new(cn_node_t **o_node) {
286
    cn_node_t *node = calloc(1,sizeof(*node));
Josh Kunz's avatar
Josh Kunz committed
287
    if (node == NULL) { return -1; }
288
    node->role = CN_NODE_ROLE_UNKNOWN;
Josh Kunz's avatar
Josh Kunz committed
289
    if (cn_principal_new(&node->principal) != 0) { goto fail; }
290
    RHOLD_OBJ(node->principal, node);
Josh Kunz's avatar
Josh Kunz committed
291 292 293 294
    /* XXX: Should the principal increment the reference count of the node
     * at this point? The principal is 1-1 with the node, so it should be OK
     * that we don't, and make our lives a little easier. */
    node->principal->owner = node;
295

296 297 298 299 300 301
    if (cn_principal_new(&node->secret) != 0) {
        goto fail1;
    }
    RHOLD_OBJ(node->secret, node);
    node->secret->owner = NULL;

302 303
    _obj_init(&node->obj, CN_NODE, _cn_node_free);

Josh Kunz's avatar
Josh Kunz committed
304 305
    cn_dispatch_result_cache_init(&node->cache);

Josh Kunz's avatar
Josh Kunz committed
306 307 308 309 310 311 312 313 314 315 316
    cn_node_grant_t * grant = NULL;
    if (cn_node_grant_new(node, &grant) != 0) {
        cncerr("Couldn't create node grant");
        goto fail2;
    }

    if (cn_principal_insert(node->secret, (cn_obj_t *) grant, NULL, &node->grant) != 0) {
        cncerr("Couldn't insert node grant into node's secret cspace");
        goto fail3;
    }

Josh Kunz's avatar
Josh Kunz committed
317 318
    /* Create the default rp0 and insert it into the node's cspace */
    cn_rp_t *rp0;
Josh Kunz's avatar
Josh Kunz committed
319
    if (cn_rp_new(&rp0) != 0) { goto fail3; }
320
    if (cn_principal_insert(node->secret, (cn_obj_t *) rp0, NULL, &node->rp0) != 0) { 
Josh Kunz's avatar
Josh Kunz committed
321
        goto fail4; 
Josh Kunz's avatar
Josh Kunz committed
322
    }
Josh Kunz's avatar
Josh Kunz committed
323

324
    node->name = NULL;
Josh Kunz's avatar
Josh Kunz committed
325
    node->flow_table = g_hash_table_new(g_direct_hash, g_direct_equal);
326
    node->node_table = g_hash_table_new(g_direct_hash, g_direct_equal);
Josh Kunz's avatar
Josh Kunz committed
327
    node->notify_wait = g_hash_table_new(g_int64_hash, g_int64_equal);
328

329
    *o_node = node;
Josh Kunz's avatar
Josh Kunz committed
330
    return 0;
Josh Kunz's avatar
Josh Kunz committed
331

Josh Kunz's avatar
Josh Kunz committed
332
fail4:
Josh Kunz's avatar
Josh Kunz committed
333
    cn_rp_free(rp0);
Josh Kunz's avatar
Josh Kunz committed
334 335
fail3:
    cn_node_grant_free(grant);
336 337
fail2:
    cn_principal_free(node->secret);
Josh Kunz's avatar
Josh Kunz committed
338
fail1:
Josh Kunz's avatar
Josh Kunz committed
339 340
    cn_principal_free(node->principal);
fail:
Josh Kunz's avatar
Josh Kunz committed
341 342 343 344
    free(node);
    return -1;
}

Josh Kunz's avatar
Josh Kunz committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
int cn_unordered_acquire_port_switch_lock(cn_port_t *port, cn_switch_t **o_sw) {
    cn_switch_t *sw = NULL;

    RHOLD_OBJ(port, OBJ_OWNER);

    cn_obj_lock(port);
    sw = port->csw;
    cn_obj_unlock(port);
    RHOLD_OBJ(sw, OBJ_OWNER);

    cn_obj_lock(sw);
    cn_obj_lock(port);

    int res = -1;
    if (port->csw != sw) {
        cncerr("port -- sw linkage modified while locking\n");
        cn_obj_unlock(port);
        cn_obj_unlock(sw);
        res = -1;
    } else {
        *o_sw = sw;
        res = 0;
    }
    RPUTs_OBJ(sw, OBJ_OWNER);
    RPUTs_OBJ(port, OBJ_OWNER);

    return res;
}

int cn_unordered_acquire_node_switch_lock(cn_node_t *node, cn_port_t **o_port, cn_switch_t **o_sw) {
    cn_switch_t *sw = NULL;
    cn_port_t *port = NULL;

    RHOLD_OBJ(node, OBJ_OWNER);

    cn_obj_lock(node);
    port = node->cn_port;
    cn_obj_unlock(node);
    RHOLD_OBJ(port, OBJ_OWNER);

    int res = cn_unordered_acquire_port_switch_lock(port, &sw);
    if (res != 0) { 
        res = -1;
        goto finish;
    }

    cn_obj_lock(node);

    if (node->cn_port != port) {
        cncerr("node -- port linkage modified while locking\n");
        cn_obj_unlock(node);
        res = -1;
    } else {
        *o_port = port;
        *o_sw = sw;
        res = 0;
    }

finish:
    RPUTs_OBJ(port, OBJ_OWNER);
    RPUTs_OBJ(node, OBJ_OWNER);
    return res;
}

int cn_unordered_acquire_flow_switch_lock(cn_flow_t *flow, cn_node_t **o_node, 
                                          cn_port_t **o_port, cn_switch_t **o_sw) {
    cn_switch_t *sw = NULL;
    cn_port_t *port = NULL;
    cn_node_t *node = NULL;

    RHOLD_OBJ(flow, OBJ_OWNER);

    cn_obj_lock(flow);
    node = flow->node;
    cn_obj_unlock(flow);
    RHOLD_OBJ(node, OBJ_OWNER);

    int res = cn_unordered_acquire_node_switch_lock(node, &port, &sw);
    if (res != 0) {
        res = -1;
        goto finish;
    }

    cn_obj_lock(flow);

    if (flow->node != node) {
        cncerr("flow -- node linkage modified while locking\n");
        cn_obj_unlock(flow);
        res = -1;
    } else {
        *o_node = node;
        *o_port = port;
        *o_sw = sw;
        res = 0;
    }

finish:
    RPUTs_OBJ(node, OBJ_OWNER);
    RPUTs_OBJ(flow, OBJ_OWNER);
    return res;
}

447 448
void cn_port_add_node(cn_port_t *port, cn_node_t *node) {
    RHOLD_OBJ(node, port);
Josh Kunz's avatar
Josh Kunz committed
449
    cn_obj_lock(port);
Josh Kunz's avatar
Josh Kunz committed
450
    port->nodes = g_list_prepend(port->nodes, node);
Josh Kunz's avatar
Josh Kunz committed
451
    cn_obj_unlock(port);
452 453
}

454 455 456 457
void cn_node_free(cn_node_t *node) {

    if (node->name)
        free(node->name);
Josh Kunz's avatar
Josh Kunz committed
458

459 460 461
    if (node->id)
        free(node->id);

462 463
    if (node->name) { free(node->name); }

Josh Kunz's avatar
Josh Kunz committed
464 465
    /* This should clean up any left-over flows when the principal gets
     * deleted. */
466
    RPUTs_OBJ(node->principal, node);
Josh Kunz's avatar
Josh Kunz committed
467 468 469 470

    /* Free the actual hash table. */
    g_hash_table_destroy(node->flow_table);

471
    free(node);
472 473 474 475
}

/* subsec: RP Objects */

476 477 478
enum cn_rp_elem_source {
    CN_RP_ELEM_SOURCE_INJECTED,
    CN_RP_ELEM_SOURCE_NORMAL,
479
    CN_RP_ELEM_SOURCE_MEMBRANE,
Josh Kunz's avatar
Josh Kunz committed
480
    CN_RP_ELEM_SOURCE_MESSAGE
481 482
};

483
enum cn_membrane_type cn_membrane_type_opposite(enum cn_membrane_type type) {
484 485 486 487 488 489 490 491 492 493
    switch (type) {
        case CN_MEMBRANE_TYPE_EXTERNAL:
            return CN_MEMBRANE_TYPE_INTERNAL;
        case CN_MEMBRANE_TYPE_INTERNAL:
            return CN_MEMBRANE_TYPE_EXTERNAL;
        default: break;
    }
    cn_abort("unreachable");
}

494
struct cn_rp_elem {
495
    enum cn_rp_elem_source source;
Josh Kunz's avatar
Josh Kunz committed
496 497
    bool has_msg;
    struct cn_rp_elem_message msg;
498 499 500 501 502 503 504 505
    union {
        struct {
            cn_principal_t *cap_owner;
            cptr_t cap;
        } normal;
        struct {
            cn_obj_t * object;
        } injected;
506 507 508
        struct {
            cn_principal_t *cap_owner;
            cptr_t cap;
509
            cn_cnode_meta_t * sender_meta;
510
        } membrane;
511
    };
512 513
};

Josh Kunz's avatar
Josh Kunz committed
514 515 516 517
static inline bool cn_rp_elem_is_normal(struct cn_rp_elem * elem) {
    return elem->source == CN_RP_ELEM_SOURCE_NORMAL;
}

518 519 520 521
static inline bool cn_rp_elem_is_injected(struct cn_rp_elem * elem) {
    return elem->source == CN_RP_ELEM_SOURCE_INJECTED;
}

522
static inline bool cn_rp_elem_is_membrane(struct cn_rp_elem * elem) {
523
    return elem->source == CN_RP_ELEM_SOURCE_MEMBRANE;
524 525
}

526 527 528
static void __cn_rp_elem_release_refs(void * who, struct cn_rp_elem *elem);
static void __cn_rp_elem_hold_refs(void * who, struct cn_rp_elem *elem);

529
void cn_rp_elem_free(struct cn_rp_elem * elem) { 
Josh Kunz's avatar
Josh Kunz committed
530 531 532
    if (elem->has_msg) { 
        free(elem->msg.data);
    }
533 534 535
    if (cn_rp_elem_is_membrane(elem)) {
        cn_cnode_meta_free(elem->membrane.sender_meta);
    }
536 537 538
    g_slice_free1(sizeof(struct cn_rp_elem), elem); 
}

539 540 541 542 543 544 545 546
static void __cn_rp_queue_free(cn_rp_t *rp) {
    while (! g_queue_is_empty(rp->queue)) {
        struct cn_rp_elem *elem = (struct cn_rp_elem *) g_queue_pop_head(rp->queue);
        __cn_rp_elem_release_refs(rp, elem);
        cn_rp_elem_free(elem);
    }
    g_queue_free(rp->queue);
    rp->queue = NULL;
547 548 549
}

void cn_rp_free(cn_rp_t *rp) {
550
    __cn_rp_queue_free(rp);
551 552 553
    free(rp);
}

554 555
static void _cn_rp_free OBJ_FREE(rp, CN_RP)

556
int cn_rp_new(cn_rp_t **o_rp) {
557
    cn_rp_t * rp = calloc(1,sizeof(*rp));
Josh Kunz's avatar
Josh Kunz committed
558 559 560
    if (rp == NULL) { return -1; }
    rp->queue = g_queue_new();
    if (rp->queue == NULL) { goto fail; }
561
    _obj_init(&rp->obj, CN_RP, _cn_rp_free);
Josh Kunz's avatar
Josh Kunz committed
562

Josh Kunz's avatar
Josh Kunz committed
563 564 565 566 567 568 569
    *o_rp = rp;
    return 0;
fail:
    free(rp);
    return -1;
}

David Johnson's avatar
David Johnson committed
570 571 572 573 574 575 576
/* subsec: Broker Objects */

struct cn_broker_elem {
    cn_principal_t *cap_owner;
    cptr_t cap;
};

Josh Kunz's avatar
Josh Kunz committed
577 578 579 580 581 582 583 584
static void __cn_broker_elem_hold_refs(const void *who, struct cn_broker_elem *elem) {
    RHOLD_OBJ(elem->cap_owner, who);
}

static void __cn_broker_elem_release_refs(const void *who, struct cn_broker_elem *elem) {
    RPUTs_OBJ(elem->cap_owner, who);
}

David Johnson's avatar
David Johnson committed
585 586 587 588 589
void cn_broker_elem_free(struct cn_broker_elem *elem) { 
    g_slice_free1(sizeof(*elem), elem); 
}

static void __cn_broker_elem_free_gpointer(gpointer elem) {
Josh Kunz's avatar
Josh Kunz committed
590
    __cn_broker_elem_release_refs(OBJ_OWNER, (struct cn_broker_elem *) elem);
David Johnson's avatar
David Johnson committed
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
    cn_broker_elem_free((struct cn_broker_elem *)elem);
}

int cn_broker_elem_new(cn_principal_t *p, cptr_t cap,
                       struct cn_broker_elem **o_elem) {
    struct cn_broker_elem *elem = g_slice_alloc(sizeof(*elem));
    if (elem == NULL) {
        return -1;
    }
    elem->cap_owner = p;
    elem->cap = cap;
    *o_elem = elem;

    return 0;
}

void cn_broker_free(cn_broker_t *broker) {
Josh Kunz's avatar
Josh Kunz committed
608
    /* XXX: This should clean up any left-over broker RP caps when the
David Johnson's avatar
David Johnson committed
609 610
     * principal gets deleted.
     */
Josh Kunz's avatar
Josh Kunz committed
611
    //RPUTs_OBJ(broker->principal, broker);
David Johnson's avatar
David Johnson committed
612 613 614 615 616 617 618 619 620 621 622 623 624
    g_hash_table_destroy(broker->registry);
    free(broker);
}

static void _cn_broker_free OBJ_FREE(broker, CN_BROKER)

int cn_broker_new(cn_broker_t **o_broker) {
    cn_broker_t * broker = calloc(1,sizeof(*broker));

    if (broker == NULL)
        return -1;

    /* XXX: how do we safely free the RP caps in the registry? */
Josh Kunz's avatar
Josh Kunz committed
625 626 627 628
    broker->registry = g_hash_table_new_full(g_str_hash, g_str_equal,
                                             free, __cn_broker_elem_free_gpointer);
    broker->waiting = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);

David Johnson's avatar
David Johnson committed
629 630 631 632 633 634
    _obj_init(&broker->obj, CN_BROKER, _cn_broker_free);

    *o_broker = broker;
    return 0;
}

635 636
/* subsec: Membranes */

637 638
static void _cn_membrane_free OBJ_FREE(membrane, CN_MEMBRANE)

639
int cn_membrane_new(cn_membrane_t **membrane) {
640
    cn_membrane_t *m = calloc(1,sizeof(*m));
641 642
    if (m == NULL) { return -1; }
    if (cn_rp_new(&m->rp) != 0) { goto fail; }
643
    if (cn_principal_new(&m->secret) != 0) { goto fail1; }
644

645
    m->wrapped = NULL;
646

647
    _obj_init(&m->obj, CN_MEMBRANE, _cn_membrane_free);
648

649 650
    *membrane = m;
    return 0;
651 652 653

fail1:
    cn_rp_free(m->rp);
654 655
fail:
    free(m);
Josh Kunz's avatar
Josh Kunz committed
656 657 658
    return -1;
}

659 660 661 662 663
void cn_membrane_free(cn_membrane_t *m) {
    cn_rp_free(m->rp);
    free(m);
}

664 665 666
/* private membrane interaface */

static void __cn_membrane_log(cn_membrane_t *m, cptr_t cptr) {
Josh Kunz's avatar
Josh Kunz committed
667
    c_log_debug("wrapped: %#0lx", cptr2ul(cptr));
668 669 670 671
    m->wrapped = g_list_append(m->wrapped, cptr2gptr(cptr));
}

static void __cn_membrane_log_free(cn_membrane_t *m) {
672
    c_log_debug("Free-ing: %p", m);
673 674 675 676
    g_list_free(m->wrapped);
    m->wrapped = NULL;
}

677 678 679
static bool __cn_cnode_is_not_annotated_by(struct cnode *c, void * _obj) {
    cn_obj_t * obj = (cn_obj_t *) _obj;
    bool wrapped = cn_cnode_is_annotated_by(c, obj);
680 681 682
    c_log_debug("[membrane] cptr %#lx is wrapped? %d", 
                cptr2ul(cap_cnode_cptr(c)), wrapped);
    return ! wrapped;
683 684 685 686 687 688 689
}

static void __cn_membrane_log_clear(cn_membrane_t *m) {
    GList * cur = g_list_first(m->wrapped);
    for (; cur; cur = g_list_next(cur)) {
        cptr_t cptr = gptr2cptr(cur->data);
        /* XXX: Does this fail? */
Josh Kunz's avatar
Josh Kunz committed
690
        c_log_debug("revoking %#0lx", cptr2ul(cptr));
691 692
        cn_revoke_till(m->secret, cptr, __cn_cnode_is_not_annotated_by, 
                       NULL, (void *) m);
693
    }
694
    c_log_debug("freeing the log %p", m);
695 696 697 698 699 700 701 702 703
    __cn_membrane_log_free(m);
}

struct cn_membrane_recv_grant_callback_payload {
    cn_membrane_t * membrane;
    enum cn_membrane_type send_type;
    enum cn_membrane_type recv_type;
};

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
STATIC_ASSERT(sizeof(enum cn_membrane_type) <= sizeof(void *), 
              cn_membrane_type_fits_in_ptr);
static inline void * cn_membrane_type_to_ptr(enum cn_membrane_type t) {
    return (void *) (unsigned long) t;
}

static inline enum cn_membrane_type cn_membrane_type_from_ptr(void * ptr) {
    return (enum cn_membrane_type) (unsigned long) ptr;
}

int cn_membrane_annotation_new(cn_membrane_t * membrane,
                               enum cn_membrane_type side,
                               cn_annotation_t **a_out) {
    cn_annotation_t * a;
    if (cn_annotation_new(&a) != 0) {
        return -1;
    }
    a->declassifier = (cn_obj_t *) membrane;
722
    RHOLD_OBJ(membrane, a);
723
    a->data.val = cn_membrane_type_to_ptr(side);
724
    cn_method_mask_permission_all(&a->method_mask);
725 726 727 728 729 730 731 732 733 734
    *a_out = a;
    return 0;
}

enum cn_membrane_type cn_membrane_annotation_type(cn_annotation_t *a) {
    assert(a->declassifier->type == CN_MEMBRANE 
            && "Can only find the side of a membrane annotation");
    return cn_membrane_type_from_ptr(a->data.val);
}

Josh Kunz's avatar
Josh Kunz committed
735 736 737 738 739 740 741 742 743 744 745 746
static const char * cn_membrane_type_name(enum cn_membrane_type t) {
    switch (t) {
        case CN_MEMBRANE_TYPE_INTERNAL:
            return "INTERNAL";
        case CN_MEMBRANE_TYPE_EXTERNAL:
            return "EXTERNAL";
        default:
            cn_abort("not a valid membrane type: %d", t);
    }
    return NULL;
}

747
static inline bool
748 749 750 751 752 753
cn_membrane_recv_grant_crosses_membrane(enum cn_membrane_type send_type, 
                                        enum cn_membrane_type recv_type) {
    return (send_type == CN_MEMBRANE_TYPE_INTERNAL
            && recv_type == CN_MEMBRANE_TYPE_EXTERNAL)
        || (send_type == CN_MEMBRANE_TYPE_EXTERNAL
            && recv_type == CN_MEMBRANE_TYPE_INTERNAL);
754 755 756 757 758 759 760
}

static int __cn_membrane_recv_grant_callback(struct cnode * ca, struct cnode *cb, 
                                             void * payload) {
    struct cn_membrane_recv_grant_callback_payload * args = 
        (struct cn_membrane_recv_grant_callback_payload *) payload;

761 762
    if (cn_ensure_target_meta(ca, cb) != 0) {
        cncerr("Couldn't ensure target metadata\n");
763 764
    }

765 766
    cn_cnode_meta_t * grantee = (cn_cnode_meta_t *) cap_cnode_metadata(ca);
    cn_cnode_meta_t * granted = (cn_cnode_meta_t *) cap_cnode_metadata(cb);
Josh Kunz's avatar
Josh Kunz committed
767

768
    /* crossing from inside -> outside */
769
    if (cn_membrane_recv_grant_crosses_membrane(args->send_type, args->recv_type)) {
770
        c_log_debug("[membrane single] Grant Crosses Membrane %p", args->membrane);
771 772 773 774 775 776 777 778 779 780

        cn_annotation_t *annotation = NULL;
        if (grantee != NULL) {
            if (cn_cnode_meta_get_annotation_by(grantee, 
                                                (cn_obj_t *) args->membrane, 
                                                &annotation) != 0) {
                // Need to re-set annotation 'cause it could've gotten messed
                // with during the call.
                annotation = NULL;
            }
781
        }
782 783 784 785 786 787 788

        /* If this is wrapped with this membrane, and the type of the wrap
         * mathces the type of the destination, unwrap. */
        if (annotation != NULL && 
                /* since send_type != recv_type, and there are only two types
                 * this is equivalent to annotation_type(...) != recv_type */
                cn_membrane_annotation_type(annotation) == args->send_type) {
789 790 791 792
            char * _cnode_str = cn_cnode_string(cb);
            c_log_debug("[membrane] UNwrapping %s", _cnode_str);
            free(_cnode_str);

793 794 795 796 797
            cn_cnode_meta_remove_annotation_by(granted, (cn_obj_t *) args->membrane);
        /* If the cptr is already wrapped by the membrane, but with the same
         * side that we're receiving, just let it pass. */
        } else if (annotation != NULL) {
        /* Otherwise, wrap. */
798
        } else {
799 800 801 802
            char * _cnode_str = cn_cnode_string(cb);
            c_log_debug("[membrane] wrapping %s", _cnode_str);
            free(_cnode_str);

803 804 805 806 807 808 809
            cn_annotation_t * wrap_annotation;
            if (cn_membrane_annotation_new(args->membrane, args->recv_type, 
                                           &wrap_annotation) != 0) {
                cncerr("Failed to create new annotation for the wrap\n");
                goto fail;
            }
            (void) cn_cnode_meta_add_annotation(granted, wrap_annotation);
810 811 812 813 814 815 816
            __cn_membrane_log(args->membrane, cap_cnode_cptr(cb));
        }
    }
    /* Otherise, we just treat it like a normal receive and perform no
     * special actions. */

    return 0;
817 818 819 820

fail:
    cn_ensure_target_meta_cleanup(ca, cb);
    return -1;
821 822
}

823 824 825 826 827
static int cn_membrane_grant_single(cn_membrane_t * membrane,
                                    enum cn_membrane_type send_type,
                                    enum cn_membrane_type recv_type,
                                    cn_principal_t * granter, cptr_t granted,
                                    cptr_t *o_cap) {
828

Josh Kunz's avatar
Josh Kunz committed
829 830
    struct cn_membrane_recv_grant_callback_payload recv_payload = {
        .membrane = membrane,
831 832
        .send_type = send_type,
        .recv_type = recv_type,
Josh Kunz's avatar
Josh Kunz committed
833
    };
834 835 836 837

    /* XXX: Most of the magic happens in this callback, look there. */
    struct cn_cb_payload cb_payload = {
        .binop = __cn_membrane_recv_grant_callback,
Josh Kunz's avatar
Josh Kunz committed
838
        .payload = (void *) &recv_payload 
839 840
    };

Josh Kunz's avatar
Josh Kunz committed
841 842 843 844
    int res = -1;

    cn_obj_lock(membrane);

845 846 847 848 849 850 851
    struct cnode * granted_cnode = NULL;
    if (cn_principal_get(granter, granted, &granted_cnode) != 0) {
        cncerr("Couldn't resolve cptr\n");
        goto finish;
    }

    /* Special case for sealers/unsealers, they skip the normal wrapping logic */
852
    /* TODO: Move check to cn_membrane_grant instead. */
853 854
    if (cn_cnode_type(granted_cnode) == CN_SEALER_UNSEALER) {
        cncwarn("skipping wrapping for sealer/unsealer\n");
855
        res = ESKIPPED;
856 857 858
        goto finish1;
    }

859 860 861 862
    c_log_debug("[membrane single] granting cnode of type %s", 
                cn_objtype_name(cn_cnode_type(granted_cnode)));

    c_log_debug("[membrane single] recv grant...");
863 864
    /* First we grant into a secret cspace specific to the membrane so
     * the capability can't be deleted out from under us. */
865
    cn_objtype_t type;
866
    if (cn_grant_cnode_extended(granted_cnode, membrane->secret, 
867
                                (void *) &cb_payload, o_cap, &type) != 0) {
868
        goto finish1;
869 870
    }

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
    c_log_debug("[membrane single] granted type: %s", cn_objtype_name(type));

    res = 0;

finish1:
    cap_cnode_put(granted_cnode);
finish:
    cn_obj_unlock(membrane);
    return res;
}

int cn_membrane_grant(cn_cnode_meta_t * send_meta,
                      cn_cnode_meta_t * recv_meta,
                      cn_principal_t *granter, cptr_t granted,
                      cn_principal_t *receiver, 
                      cptr_t *o_cap, cn_objtype_t *type) {

888 889 890 891 892 893 894 895 896 897 898 899 900

    char * _send_meta_str = send_meta ? cn_cnode_meta_string(send_meta) 
                                      : "(null)";
    char * _recv_meta_str = recv_meta ? cn_cnode_meta_string(recv_meta) 
                                      : "(null)";
    char * _send_cap = cn_cptr_string(granter, granted);
    c_log_debug("[membrane] send meta: %s", _send_meta_str);
    c_log_debug("[membrane] recv meta: %s", _recv_meta_str);
    c_log_debug("[membrane] send cap: %s", _send_cap);
    free(_send_cap);
    if (send_meta) { free(_send_meta_str); }
    if (recv_meta) { free(_recv_meta_str); }

901 902 903
    /* If there are actually no annotations at play, just do a normal grant. */
    if (! cn_cnode_meta_is_annotated(send_meta)
        && ! cn_cnode_meta_is_annotated(recv_meta)) {
904
        c_log_debug("[membrane] Fallback to grant");
905 906 907
        return cn_grant_extended(granter, granted, receiver, NULL, o_cap, type);
    }

908 909 910 911
    int res = -1;

    cn_cnode_meta_t * _allocated_meta = NULL;
    if (send_meta == NULL || recv_meta == NULL) {
912
        assert((send_meta != NULL || recv_meta != NULL) &&
913 914 915 916 917 918
                "Either sender meta or recv meta must not be null");
        if (cn_cnode_meta_new(&_allocated_meta) != 0) {
            cncerr("send or recv meta not given and allocating meta failed\n");
            return -1;
        }
        if (send_meta == NULL) {
919
            c_log_debug("[membrane] send meta set to null meta");
920 921
            send_meta = _allocated_meta;
        } else if (recv_meta == NULL) {
922
            c_log_debug("[membrane] recv meta set to null meta");
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
            recv_meta = _allocated_meta;
        }
    }

    /* There are three types of annotations:
     *
     * 1. Annotations that exist on the sender side, but not on 
     *    the receiver side.
     * 2. Annotations that exist on the receiver side, but not on the
     *    sender side.
     * 3. Annotations that exist on both sides.
     *
     * In the first loop we handle the first and third categories, and track
     * which annotations we handled in the hash table called 'handled'. Then,
     * in the second loop, we deal with annotations in the second group that
     * have not yet been handled. */

    cn_principal_t *prev_owner = granter;
    cptr_t prev_cap = granted;

    GHashTable * handled = g_hash_table_new(g_direct_hash, g_direct_equal);

    GHashTableIter iter;
    gpointer key, value;

    g_hash_table_iter_init(&iter, send_meta->annotations);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        cn_annotation_t * send_annotation = (cn_annotation_t *) value;
        if (send_annotation->declassifier->type != CN_MEMBRANE) {
            continue;
        }
        cn_annotation_t * recv_annotation = NULL;
        int ret = cn_cnode_meta_get_annotation_by(recv_meta, (cn_obj_t *) key, 
                                                  &recv_annotation);
        if (ret != 0 && ret == ENOTEXISTS) {
            recv_annotation = NULL;
        } else if (ret != 0) {
            cn_abort("unreachable");
        }

        cn_membrane_t * membrane = (cn_membrane_t *) key;
        assert(((cn_obj_t *) membrane)->type == CN_MEMBRANE
                && "Key should point to a membrane");

        enum cn_membrane_type send_type = cn_membrane_annotation_type(send_annotation);
        enum cn_membrane_type recv_type;

        if (recv_annotation == NULL) {
            recv_type = cn_membrane_type_opposite(send_type);
        } else {
            recv_type = cn_membrane_annotation_type(recv_annotation);
        }

976 977 978 979 980
#ifndef NDEBUG
        cptr_t _prev_prev_cap = prev_cap;
        cn_principal_t * _prev_prev_owner = prev_owner;
#endif

981 982 983 984 985 986 987 988 989 990
        res = cn_membrane_grant_single(membrane, send_type, recv_type,
                                       prev_owner, prev_cap,
                                       &prev_cap);
        if (res == 0) {
            cn_obj_lock(membrane);
            prev_owner = membrane->secret;
            cn_obj_unlock(membrane);
        } else if (res == ESKIPPED) {
            // pass
        } else {
991
            cncerr("Failed to do single grant with membrane %p\n", membrane);
992
            res = -1;
993 994 995 996
            goto fail;
        }

#ifndef NDEBUG
997 998 999 1000 1001 1002 1003 1004
        char * _grant_source_str = cn_cptr_string(_prev_prev_owner, 
                                                  _prev_prev_cap);
        char * _grant_dest_str = cn_cptr_string(prev_owner, prev_cap);
        c_log_debug("[membrane] Did Grant %s -> %s", _grant_source_str, 
                                                     _grant_dest_str);
        free(_grant_source_str);
        free(_grant_dest_str);

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        char * _annotation_string = cn_annotation_string(send_annotation);
        c_log_debug("[membrane]   handled annotation: %s", _annotation_string);
        free(_annotation_string);
#endif

        g_hash_table_insert(handled, key, NULL);
    }

    g_hash_table_iter_init(&iter, recv_meta->annotations);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        if (g_hash_table_contains(handled, key)) {
            continue;
        }
        cn_annotation_t * recv_annotation = (cn_annotation_t *) value;

        cn_membrane_t * membrane = (cn_membrane_t *) key;
        assert(((cn_obj_t *) membrane)->type == CN_MEMBRANE
                && "Key should point to a membrane");

        enum cn_membrane_type recv_type = cn_membrane_annotation_type(recv_annotation);
        enum cn_membrane_type send_type = cn_membrane_type_opposite(recv_type);

1027 1028 1029 1030 1031
#ifndef NDEBUG
        cptr_t _prev_prev_cap = prev_cap;
        cn_principal_t * _prev_prev_owner = prev_owner;
#endif

1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
        int res = cn_membrane_grant_single(membrane, send_type, recv_type, 
                                           prev_owner, prev_cap,
                                           &prev_cap);
        if (res == 0) {
            cn_obj_lock(membrane);
            prev_owner = membrane->secret;
            cn_obj_unlock(membrane);
        } else if (res == ESKIPPED) {
            // just pass
        } else {
1042 1043 1044 1045 1046 1047 1048
            cncerr("Failed to add membrane wrap for membrane %p\n", membrane);
            goto fail;
        }

                    
        /* Don't need to track handled state because the recv-ers hash table
         * guarantees uniqueness. */
1049 1050

#ifndef NDEBUG
1051 1052 1053 1054 1055 1056 1057 1058
        char * _grant_source_str = cn_cptr_string(_prev_prev_owner, 
                                                  _prev_prev_cap);
        char * _grant_dest_str = cn_cptr_string(prev_owner, prev_cap);
        c_log_debug("[membrane] Did Grant (pass 2) %s -> %s", _grant_source_str, 
                                                     _grant_dest_str);
        free(_grant_source_str);
        free(_grant_dest_str);

1059 1060 1061 1062
        char * _annotation_string = cn_annotation_string(recv_annotation);
        c_log_debug("[membrane]   handled annotation (pass 2): %s", _annotation_string);
        free(_annotation_string);
#endif
1063 1064
    }

1065 1066
    g_hash_table_destroy(handled);

1067 1068 1069 1070 1071 1072 1073 1074 1075
    /* XXX: WARNING! THIS DOES'T GUARANTEE ATOMICITY.
     * To do so, we'd have to put both grants in a single transaction. Currently,
     * we assume that cptrs are unguessable, so that there's no chance someone can
     * execute an operation on this cnode before we give them the cptr for it. 
     *
     * I think worst-case scenario, we'd just fail the grant, but I'm not sure.
     * Since we're granting out of the membrane's secret c-space (and the membrane
     * is locked) we don't have to worry about the source, only the destination. */

1076 1077 1078
    /* Then we do the normal grant to the actual destination. Its safe to do
     * this in two operations since we're the only ones that see the internal
     * c-space. */
1079
    if (cn_grant_extended(prev_owner, prev_cap,
1080
                          receiver, NULL, o_cap, type) != 0) {
1081 1082
        cncerr("Failed to do final grant out of membrane c-space\n");
        goto fail;
1083
    }
Josh Kunz's avatar
Josh Kunz committed
1084

1085 1086 1087 1088 1089 1090 1091 1092
    char * _final_source_str = cn_cptr_string(prev_owner, prev_cap);
    char * _final_dest_str = cn_cptr_string(receiver, *o_cap);
    c_log_debug("[membrane] Final Grant %s -> %s", _final_source_str, 
                                                   _final_dest_str);
    free(_final_source_str);
    free(_final_dest_str);

    c_log_debug("[membrane] Final Grant type: %s", cn_objtype_name(*type));
1093 1094 1095 1096 1097 1098 1099 1100

    if (_allocated_meta != NULL) { cn_cnode_meta_free(_allocated_meta); }
    return 0;

fail:
    cn_revoke(granter, granted, NULL);
    if (_allocated_meta != NULL) { cn_cnode_meta_free(_allocated_meta); }
    return -1;
1101 1102
}

1103 1104 1105 1106
/* subsec: node grants */

static void _cn_node_grant_free OBJ_FREE(node_grant, CN_NODE_GRANT)

Josh Kunz's avatar
Josh Kunz committed
1107
int cn_node_grant_new(cn_node_t *node, cn_node_grant_t ** o_grant) {
1108 1109
    cn_node_grant_t * grant = calloc(1,sizeof(*grant));
    if (grant == NULL) { return -1; }
Josh Kunz's avatar
Josh Kunz committed
1110
    RHOLD_OBJ(node, grant);
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    grant->node = node;

    _obj_init(&grant->obj, CN_NODE_GRANT, _cn_node_grant_free);

    *o_grant = grant;
    return 0;
}

/* Free the node grant. */
void cn_node_grant_free(cn_node_grant_t * grant) {
    RPUTs_OBJ(grant, node);
    free(grant);
}

Josh Kunz's avatar
Josh Kunz committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145

/* subsec: Sealer Unsealers */

void _cn_sealer_unsealer_free OBJ_FREE(sealer_unsealer, CN_SEALER_UNSEALER)

int cn_sealer_unsealer_new(cn_sealer_unsealer_t **su) {
    cn_sealer_unsealer_t * sealer_unsealer = calloc(1,sizeof(*sealer_unsealer));
    if (sealer_unsealer == NULL) {
        cncerr("Could not allocate sealer/unsealer");
        return -1;
    }
    _obj_init(&sealer_unsealer->obj, CN_SEALER_UNSEALER, _cn_sealer_unsealer_free);

    *su = sealer_unsealer;
    return 0;
}

void cn_sealer_unsealer_free(cn_sealer_unsealer_t * su) {
    free(su);
}

1146 1147
/* sec: cnode metadata */

Josh Kunz's avatar
Josh Kunz committed
1148
static void __cn_cnode_meta_compute_cache(cn_cnode_meta_t *m) {
1149
    method_mask_t method_mask_cache = METHOD_MASK_ALL;
Josh Kunz's avatar
Josh Kunz committed
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
    GHashTableIter iter;
    gpointer key, value;
    g_hash_table_iter_init(&iter, m->annotations);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        cn_annotation_t *a = (cn_annotation_t *) value;
        assert(a != NULL && "Null value for an annotation");
        method_mask_cache &= a->method_mask;
    }
    m->method_mask_cache = method_mask_cache;
}
1160

Josh Kunz's avatar
Josh Kunz committed
1161 1162
static void __cn_cnode_meta_destroy_annotation_value(gpointer v) {
    cn_annotation_free((cn_annotation_t *) v);
Josh Kunz's avatar
Josh Kunz committed
1163 1164
}

1165
/* Create a new meta object */
Josh Kunz's avatar
Josh Kunz committed
1166 1167 1168 1169 1170 1171 1172 1173 1174
static int __cn_cnode_meta_alloc(cn_cnode_meta_t **m_o) {
    cn_cnode_meta_t *m = calloc(1, sizeof(cn_cnode_meta_t));
    if (m == NULL) { 
        cncerr("Couldn't allocate new cnode meta struct, calloc failed\n");
        return -1; 
    }

    *m_o = m;

1175 1176 1177
    return 0;
}

Josh Kunz's avatar
Josh Kunz committed
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
static void __cn_cnode_meta_init_annotations(cn_cnode_meta_t *m) {
    m->annotations = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
                                           __cn_cnode_meta_destroy_annotation_value);

    __cn_cnode_meta_compute_cache(m);
}

int cn_cnode_meta_new(cn_cnode_meta_t **m_o) {
    int res = __cn_cnode_meta_alloc(m_o);
    if (res != 0) { 
        return res; 
    }
    __cn_cnode_meta_init_annotations(*m_o);
    return 0;
Josh Kunz's avatar
Josh Kunz committed
1192 1193
}

1194
void cn_cnode_meta_free(cn_cnode_meta_t *m) {
Josh Kunz's avatar
Josh Kunz committed
1195
    g_hash_table_destroy(m->annotations);