3 * \brief Contains handler functions for server-side octopus interface RPC call.
7 * Copyright (c) 2009, 2010, 2012, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
18 #include <barrelfish/barrelfish.h>
19 #include <barrelfish/nameservice_client.h>
20 #include <skb/skb.h> // read list
21 #include <if/octopus_defs.h>
23 #include <octopus_server/service.h>
24 #include <octopus_server/query.h>
25 #include <octopus_server/debug.h>
27 #include <octopus/parser/ast.h>
28 #include <octopus/definitions.h>
30 #include <bench/bench.h>
35 * Name prefix used to by the functions set_with_idcap_handler() and
36 * get_with_idcap_handler() to store and retrieve records by idcap.
38 * This essentially emulates a dedicated namespace for records stored with an
39 * id cap. Octopus and the SKB do not support dedicated namespaces atm.
40 * FIXME: store records set with the function 'set_with_idcap' in a dedicated
43 #define IDCAPID_NAME_PREFIX "idcapid."
45 static uint64_t current_id = 1;
47 static inline errval_t check_query_length(char* query) {
48 if (strlen(query) >= MAX_QUERY_LENGTH) {
49 return OCT_ERR_QUERY_SIZE;
55 errval_t new_oct_reply_state(struct oct_reply_state** drt,
56 oct_reply_handler_fn reply_handler)
59 *drt = malloc(sizeof(struct oct_reply_state));
61 return LIB_ERR_MALLOC_FAIL;
64 //memset(*drt, 0, sizeof(struct oct_reply_state));
65 (*drt)->query_state.std_out.buffer[0] = '\0';
66 (*drt)->query_state.std_out.length = 0;
67 (*drt)->query_state.std_err.buffer[0] = '\0';
68 (*drt)->query_state.std_err.length = 0;
71 (*drt)->return_record = false;
76 (*drt)->client_state = 0;
77 (*drt)->client_handler = 0;
78 (*drt)->server_id = 0;
80 (*drt)->reply = reply_handler;
86 static void free_oct_reply_state(void* arg)
89 struct oct_reply_state* drt = (struct oct_reply_state*) arg;
90 // In case we have to free things in oct_reply_state, free here...
94 assert(!"free_reply_state with NULL argument?");
98 static void trigger_send_handler(struct octopus_binding* b,
99 struct oct_reply_state* drs)
101 char* record = drs->query_state.std_out.buffer[0] != '\0' ?
102 drs->query_state.std_out.buffer : NULL;
105 err = b->tx_vtbl.trigger(b, MKCONT(free_oct_reply_state, drs),
111 if (err_is_fail(err)) {
112 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
113 oct_rpc_enqueue_reply(b, drs);
116 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
120 static inline bool can_install_trigger(octopus_trigger_t trigger, errval_t error)
122 OCT_DEBUG("%s:%s:%d: trigger.m > 0 = %d\n",
123 __FILE__, __FUNCTION__, __LINE__, trigger.m > 0);
124 OCT_DEBUG("%s:%s:%d: trigger.in_case == err_no(error) = %d\n",
125 __FILE__, __FUNCTION__, __LINE__, trigger.in_case == err_no(error));
127 return trigger.m > 0 &&
128 (trigger.in_case == err_no(error) ||
129 (trigger.m & OCT_ALWAYS_SET) != 0 );
132 static inline uint64_t install_trigger(struct octopus_binding* binding,
133 struct ast_object* ast, octopus_trigger_t trigger, errval_t error)
136 uint64_t watch_id = 0;
138 if (can_install_trigger(trigger, error)) {
139 struct oct_reply_state* trigger_reply = NULL;
140 err = new_oct_reply_state(&trigger_reply, trigger_send_handler);
141 assert(err_is_ok(err));
143 trigger_reply->client_handler = trigger.trigger;
144 trigger_reply->client_state = trigger.st;
146 trigger_reply->binding = (trigger.send_to == octopus_BINDING_RPC) ?
147 binding : get_event_binding(binding);
148 if (trigger_reply->binding == NULL) {
149 fprintf(stderr, "No event binding for trigger, send events "
150 "over regular binding.");
151 trigger_reply->binding = binding;
154 err = set_watch(binding, ast, trigger.m, trigger_reply, &watch_id);
155 assert(err_is_ok(err));
161 static void remove_trigger_reply(struct octopus_binding* b,
162 struct oct_reply_state* drs)
165 err = b->tx_vtbl.remove_trigger_response(b,
166 MKCONT(free_oct_reply_state, drs),
168 if (err_is_fail(err)) {
169 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
170 oct_rpc_enqueue_reply(b, drs);
173 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
177 void remove_trigger_handler(struct octopus_binding *b, octopus_trigger_id_t tid)
179 struct oct_reply_state* drs = NULL;
180 errval_t err = new_oct_reply_state(&drs, remove_trigger_reply);
181 assert(err_is_ok(err));
183 drs->error = del_watch(b, tid, &drs->query_state);
187 /*static inline void arrival_rate(void)
189 static cycles_t measure_time = 10000;
190 static uint64_t arrivals = 0;
191 static cycles_t start = 0;
193 if ( (arrivals % 100) == 0 && bench_tsc_to_ms(bench_tsc() - start) > measure_time) {
194 printf("Get Rate per sec: %lu\n", arrivals / (measure_time / 1000));
200 static void get_reply(struct octopus_binding* b, struct oct_reply_state* drt)
203 char* reply = err_is_ok(drt->error) ?
204 drt->query_state.std_out.buffer : NULL;
205 err = b->tx_vtbl.get_response(b, MKCONT(free_oct_reply_state, drt),
206 reply, drt->server_id, drt->error);
207 if (err_is_fail(err)) {
208 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
209 oct_rpc_enqueue_reply(b, drt);
212 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
216 void get_handler(struct octopus_binding *b, char *query, octopus_trigger_t trigger)
218 errval_t err = SYS_ERR_OK;
220 struct oct_reply_state* drs = NULL;
221 struct ast_object* ast = NULL;
222 err = new_oct_reply_state(&drs, get_reply);
223 assert(err_is_ok(err));
225 err = check_query_length(query);
226 if (err_is_fail(err)) {
230 err = generate_ast(query, &ast);
231 if (err_is_ok(err)) {
232 err = get_record(ast, &drs->query_state);
233 drs->server_id = install_trigger(b, ast, trigger, err);
243 static void get_names_reply(struct octopus_binding* b,
244 struct oct_reply_state* drt)
247 char* reply = err_is_ok(drt->error) ?
248 drt->query_state.std_out.buffer : NULL;
249 err = b->tx_vtbl.get_names_response(b, MKCONT(free_oct_reply_state, drt),
250 reply, drt->server_id, drt->error);
251 if (err_is_fail(err)) {
252 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
253 oct_rpc_enqueue_reply(b, drt);
256 if (err_no(err) == FLOUNDER_ERR_TX_MSG_SIZE) {
257 debug_printf("max msg size: %u, reply size: %zu\n",
258 octopus__get_names_response_output_MAX_ARGUMENT_SIZE,
259 drt->query_state.std_out.length);
261 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
265 void get_names_handler(struct octopus_binding *b, char *query, octopus_trigger_t t)
267 OCT_DEBUG(" get_names_handler: %s\n", query);
269 errval_t err = SYS_ERR_OK;
271 struct oct_reply_state* drs = NULL;
272 struct ast_object* ast = NULL;
274 err = new_oct_reply_state(&drs, get_names_reply);
275 assert(err_is_ok(err));
277 err = check_query_length(query);
278 if (err_is_fail(err)) {
282 err = generate_ast(query, &ast);
283 if (err_is_ok(err)) {
284 err = get_record_names(ast, &drs->query_state);
285 drs->server_id = install_trigger(b, ast, t, err);
295 static void set_reply(struct octopus_binding* b, struct oct_reply_state* drs)
297 char* record = err_is_ok(drs->error) && drs->return_record ?
298 drs->query_state.std_out.buffer : NULL;
301 err = b->tx_vtbl.set_response(b, MKCONT(free_oct_reply_state, drs), record,
302 drs->server_id, drs->error);
303 if (err_is_fail(err)) {
304 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
305 oct_rpc_enqueue_reply(b, drs);
308 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
312 void set_handler(struct octopus_binding *b, char *query, uint64_t mode,
313 octopus_trigger_t trigger, bool get)
315 OCT_DEBUG(" set_handler: %s\n", query);
316 errval_t err = SYS_ERR_OK;
318 struct oct_reply_state* drs = NULL;
319 struct ast_object* ast = NULL;
321 err = new_oct_reply_state(&drs, set_reply);
322 assert(err_is_ok(err));
324 err = check_query_length(query);
325 if (err_is_fail(err)) {
329 err = generate_ast(query, &ast);
330 if (err_is_ok(err)) {
331 if (ast->u.on.name->type == nodeType_Ident) {
332 err = set_record(ast, mode, &drs->query_state);
333 drs->server_id = install_trigger(b, ast, trigger, err);
336 // Since we don't have any ACLs atm. we do not
337 // allow name to be a regex/variable, because
338 // we it's not guaranteed which records get
339 // modified in this case.
340 err = OCT_ERR_NO_RECORD_NAME;
346 drs->return_record = get;
352 static errval_t build_query_with_idcap(char **query_p, struct capref idcap,
357 size_t query_size, bytes_written;
359 // retrieve id from idcap
360 err = invoke_idcap_identify(idcap, &id);
361 if (err_is_fail(err)) {
362 return err_push(err, OCT_ERR_IDCAP_INVOKE);
365 err = cap_delete(idcap);
366 assert(err_is_ok(err));
368 if (attributes == NULL) {
372 // build query using the idcapid and the attributes
373 query_size = snprintf(NULL, 0, IDCAPID_NAME_PREFIX "%" PRIxIDCAPID "%s", id,
375 *query_p = (char *) malloc(query_size + 1); // include \0
376 if (*query_p == NULL) {
377 return LIB_ERR_MALLOC_FAIL;
379 bytes_written = snprintf(*query_p, query_size + 1, IDCAPID_NAME_PREFIX
380 "%" PRIxIDCAPID "%s", id, attributes);
385 static void get_with_idcap_reply(struct octopus_binding *b,
386 struct oct_reply_state *drt)
389 char *reply = err_is_ok(drt->error) ?
390 drt->query_state.std_out.buffer : NULL;
391 err = b->tx_vtbl.get_with_idcap_response(b,
392 MKCONT(free_oct_reply_state, drt),
393 reply, drt->server_id, drt->error);
394 if (err_is_fail(err)) {
395 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
396 oct_rpc_enqueue_reply(b, drt);
399 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
403 void get_with_idcap_handler(struct octopus_binding *b, struct capref idcap,
404 octopus_trigger_t trigger)
408 struct oct_reply_state *drs = NULL;
409 struct ast_object *ast = NULL;
411 OCT_DEBUG("get_with_idcap_handler: %s\n", query);
413 err = new_oct_reply_state(&drs, get_with_idcap_reply);
414 assert(err_is_ok(err));
416 err = build_query_with_idcap(&query, idcap, "");
417 if (err_is_fail(err)) {
421 err = check_query_length(query);
422 if (err_is_fail(err)) {
426 err = generate_ast(query, &ast);
427 if (err_is_ok(err)) {
428 err = get_record(ast, &drs->query_state);
429 drs->server_id = install_trigger(b, ast, trigger, err);
442 static void set_with_idcap_reply(struct octopus_binding *b,
443 struct oct_reply_state *drs)
445 char *record = err_is_ok(drs->error) && drs->return_record ?
446 drs->query_state.std_out.buffer : NULL;
449 err = b->tx_vtbl.set_with_idcap_response(b,
450 MKCONT(free_oct_reply_state, drs),
451 record, drs->server_id,
453 if (err_is_fail(err)) {
454 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
455 oct_rpc_enqueue_reply(b, drs);
458 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
462 void set_with_idcap_handler(struct octopus_binding *b, struct capref idcap,
463 char *attributes, uint64_t mode,
464 octopus_trigger_t trigger, bool get)
468 struct oct_reply_state *drs = NULL;
469 struct ast_object *ast = NULL;
471 err = new_oct_reply_state(&drs, set_with_idcap_reply);
472 assert(err_is_ok(err));
474 err = build_query_with_idcap(&query, idcap, attributes);
475 if (err_is_fail(err)) {
478 OCT_DEBUG(" set_with_idcap_handler: %s\n", query);
480 err = check_query_length(query);
481 if (err_is_fail(err)) {
485 err = generate_ast(query, &ast);
486 if (err_is_ok(err)) {
487 if (ast->u.on.name->type == nodeType_Ident) {
488 err = set_record(ast, mode, &drs->query_state);
489 drs->server_id = install_trigger(b, ast, trigger, err);
491 err = OCT_ERR_NO_RECORD_NAME;
497 drs->return_record = get;
507 static void del_reply(struct octopus_binding* b, struct oct_reply_state* drs)
510 err = b->tx_vtbl.del_response(b, MKCONT(free_oct_reply_state, drs),
511 drs->server_id, drs->error);
512 if (err_is_fail(err)) {
513 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
514 oct_rpc_enqueue_reply(b, drs);
517 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
521 void del_handler(struct octopus_binding* b, char* query, octopus_trigger_t trigger)
523 OCT_DEBUG(" del_handler: %s\n", query);
524 errval_t err = SYS_ERR_OK;
526 struct oct_reply_state* drs = NULL;
527 struct ast_object* ast = NULL;
529 err = new_oct_reply_state(&drs, del_reply);
530 assert(err_is_ok(err));
532 err = check_query_length(query);
533 if (err_is_fail(err)) {
537 err = generate_ast(query, &ast);
538 if (err_is_ok(err)) {
539 if (ast->u.on.name->type == nodeType_Ident) {
540 err = del_record(ast, &drs->query_state);
541 drs->server_id = install_trigger(b, ast, trigger, err);
544 // Since we don't have any ACLs atm. we do not
545 // allow name to be a regex/variable
546 // (see set_handler).
547 err = OCT_ERR_NO_RECORD_NAME;
558 static void exists_reply(struct octopus_binding* b, struct oct_reply_state* drs)
561 err = b->tx_vtbl.exists_response(b, MKCONT(free_oct_reply_state, drs),
562 drs->server_id, drs->error);
564 if (err_is_fail(err)) {
565 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
566 oct_rpc_enqueue_reply(b, drs);
569 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
573 void exists_handler(struct octopus_binding* b, char* query,
574 octopus_trigger_t trigger)
576 errval_t err = SYS_ERR_OK;
578 struct oct_reply_state* drs = NULL;
579 struct ast_object* ast = NULL;
581 err = new_oct_reply_state(&drs, exists_reply);
582 assert(err_is_ok(err));
584 err = check_query_length(query);
585 if (err_is_fail(err)) {
589 err = generate_ast(query, &ast);
590 if (err_is_ok(err)) {
591 err = get_record(ast, &drs->query_state);
592 drs->server_id = install_trigger(b, ast, trigger, err);
602 static void wait_for_reply(struct octopus_binding* b, struct oct_reply_state* drs)
605 err = b->tx_vtbl.wait_for_response(b, MKCONT(free_oct_reply_state, drs),
606 drs->query_state.std_out.buffer, drs->error);
608 if (err_is_fail(err)) {
609 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
610 oct_rpc_enqueue_reply(b, drs);
613 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
617 // XXX: For compatibility reasons with nameserver API
618 void wait_for_handler(struct octopus_binding* b, char* query) {
619 errval_t err = SYS_ERR_OK;
620 errval_t set_watch_err = SYS_ERR_OK;
622 struct oct_reply_state* drs = NULL;
623 struct ast_object* ast = NULL;
625 err = new_oct_reply_state(&drs, wait_for_reply);
627 assert(err_is_ok(err));
629 err = check_query_length(query);
630 if (err_is_fail(err)) {
634 err = generate_ast(query, &ast);
635 if (err_is_ok(err)) {
636 err = get_record(ast, &drs->query_state);
637 if (err_no(err) == OCT_ERR_NO_RECORD) {
639 set_watch_err = set_watch(b, ast, OCT_ON_SET, drs, &wid);
644 if (err_no(err) != OCT_ERR_NO_RECORD || err_is_fail(set_watch_err)) {
646 if (err_is_fail(set_watch_err)) {
647 // implies err = OCT_ERR_NO_RECORD
648 drs->error = set_watch_err;
656 static void subscribe_reply(struct octopus_binding* b,
657 struct oct_reply_state* drs)
660 err = b->tx_vtbl.subscribe_response(b, MKCONT(free_oct_reply_state, drs),
661 drs->server_id, drs->error);
663 if (err_is_fail(err)) {
664 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
665 oct_rpc_enqueue_reply(b, drs);
668 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
672 void subscribe_handler(struct octopus_binding *b, char* query,
673 uint64_t trigger_fn, uint64_t state)
675 OCT_DEBUG("subscribe: query = %s\n", query);
676 errval_t err = SYS_ERR_OK;
678 struct oct_reply_state* drs = NULL;
679 struct ast_object* ast = NULL;
681 err = new_oct_reply_state(&drs, subscribe_reply);
682 assert(err_is_ok(err));
684 err = check_query_length(query);
685 if (err_is_fail(err)) {
689 err = generate_ast(query, &ast);
690 if (err_is_ok(err)) {
691 err = add_subscription(b, ast, trigger_fn, state, drs);
701 static void unsubscribe_reply(struct octopus_binding* b,
702 struct oct_reply_state* drs)
705 err = b->tx_vtbl.unsubscribe_response(b, MKCONT(free_oct_reply_state, drs),
707 if (err_is_fail(err)) {
708 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
709 oct_rpc_enqueue_reply(b, drs);
712 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
716 static void send_subscribed_message(struct octopus_binding* b, struct oct_reply_state* drs)
718 errval_t err = SYS_ERR_OK;
719 char* record = drs->query_state.std_out.buffer[0] != '\0' ?
720 drs->query_state.std_out.buffer : NULL;
722 err = b->tx_vtbl.subscription(b, MKCONT(free_oct_reply_state, drs),
723 drs->server_id, drs->client_handler,
724 drs->mode, record, drs->client_state);
725 if (err_is_fail(err)) {
726 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
727 oct_rpc_enqueue_reply(b, drs);
730 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
735 void unsubscribe_handler(struct octopus_binding *b, uint64_t id)
737 errval_t err = SYS_ERR_OK;
739 OCT_DEBUG("unsubscribe: id = %"PRIu64"\n", id);
741 struct oct_reply_state* srs = NULL;
742 err = new_oct_reply_state(&srs, unsubscribe_reply);
743 assert(err_is_ok(err));
745 err = del_subscription(b, id, &srs->query_state);
746 if (err_is_ok(err)) {
748 uint64_t client_handler;
749 uint64_t client_state;
752 skb_read_output_at(srs->query_state.std_out.buffer,
753 "subscriber(%"SCNu64", %"SCNu64", %"SCNu64", %"SCNu64")",
754 &binding, &client_handler, &client_state, &server_id);
756 struct oct_reply_state* subscriber = NULL;
757 err = new_oct_reply_state(&subscriber,
758 send_subscribed_message);
759 assert(err_is_ok(err));
761 #if defined(__i386__) || defined(__arm__)
762 subscriber->binding = (struct octopus_binding*)(uint32_t)binding;
764 subscriber->binding = (struct octopus_binding*)binding;
766 subscriber->client_handler = client_handler;
767 subscriber->client_state = client_state;
768 subscriber->server_id = server_id;
769 subscriber->mode = OCT_REMOVED;
771 OCT_DEBUG("publish msg to: recipient:%"PRIu64" id:%"PRIu64"\n", binding, server_id);
772 subscriber->reply(subscriber->binding, subscriber);
779 static void publish_reply(struct octopus_binding* b, struct oct_reply_state* drs)
782 err = b->tx_vtbl.publish_response(b, MKCONT(free_oct_reply_state, drs),
784 if (err_is_fail(err)) {
785 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
786 oct_rpc_enqueue_reply(b, drs);
789 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
793 void publish_handler(struct octopus_binding *b, char* record)
795 OCT_DEBUG("publish_handler query: %s\n", record);
796 errval_t err = SYS_ERR_OK;
798 struct oct_reply_state* drs = NULL;
799 err = new_oct_reply_state(&drs, publish_reply);
800 assert(err_is_ok(err));
802 err = check_query_length(record);
803 if (err_is_fail(err)) {
809 struct ast_object* ast = NULL;
810 err = generate_ast(record, &ast);
811 if (err_is_fail(err)) {
818 if (err_is_ok(err)) {
819 err = find_subscribers(ast, &drs->query_state);
820 if (err_is_ok(err)) {
821 // Reply to publisher
826 struct list_parser_status status;
827 skb_read_list_init_offset(&status, drs->query_state.std_out.buffer, 0);
829 // TODO remove skb list parser dependency
830 // Send to all subscribers
832 uint64_t client_handler;
833 uint64_t client_state;
836 while (skb_read_list(&status, "subscriber(%"SCNu64", %"SCNu64", %"SCNu64", %"SCNu64")",
837 &binding, &client_handler, &client_state, &server_id)) {
839 struct oct_reply_state* subscriber = NULL;
840 err = new_oct_reply_state(&subscriber,
841 send_subscribed_message);
842 assert(err_is_ok(err));
843 #if defined(__i386__) || defined(__arm__)
844 subscriber->binding = (struct octopus_binding*)(uint32_t)binding;
846 subscriber->binding = (struct octopus_binding*)binding;
848 subscriber->client_handler = client_handler;
849 strcpy(subscriber->query_state.std_out.buffer, record);
850 subscriber->client_state = client_state;
851 subscriber->server_id = server_id;
852 subscriber->mode = OCT_ON_PUBLISH;
854 OCT_DEBUG("publish msg to: recipient:%"PRIu64" id:%"PRIu64"\n", binding, server_id);
855 subscriber->reply(subscriber->binding, subscriber);
866 void get_identifier(struct octopus_binding* b)
868 errval_t err = b->tx_vtbl.get_identifier_response(b, NOP_CONT,
870 assert(err_is_ok(err));
873 static void identify_binding_reply(struct octopus_binding* b,
874 struct oct_reply_state* drs)
877 // TODO send drs->error back to client!
878 err = b->tx_vtbl.identify_response(b, MKCONT(free_oct_reply_state, drs));
879 if (err_is_fail(err)) {
880 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
881 oct_rpc_enqueue_reply(b, drs);
884 USER_PANIC_ERR(err, "SKB sending %s failed!", __FUNCTION__);
889 void identify_binding(struct octopus_binding* b, uint64_t id,
890 octopus_binding_type_t type)
892 assert(id <= current_id);
894 struct oct_reply_state* drs = NULL;
895 errval_t err = new_oct_reply_state(&drs, identify_binding_reply);
896 assert(err_is_ok(err));
898 OCT_DEBUG("set binding: id=%"PRIu64" type=%d\n", id, type);
899 drs->error = set_binding(type, id, b);