Changes for nameservice. Use RPC client for NS functionality.
[barrelfish] / lib / barrelfish / nameservice_client.c
1 /**
2  * \file
3  * \brief Client for interacting with the name service
4  */
5
6 /*
7  * Copyright (c) 2010, 2011, ETH Zurich.
8  * All rights reserved.
9  *
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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14 #include <stdio.h>
15
16 #include <barrelfish/barrelfish.h>
17 #include <barrelfish/nameservice_client.h>
18
19 #include <if/dist2_defs.h>
20 #include <if/dist2_rpcclient_defs.h>
21 #include <if/monitor_defs.h>
22 #include <dist2/getset.h> // for dist_read TODO
23 #include <dist2/trigger.h> // for NOP_TRIGGER
24
25 /**
26  * \brief Non-blocking name service lookup
27  *
28  * \param iface Name of interface for which to query name server
29  * \param retiref Returns pointer to IREF on success
30  */
31 errval_t nameservice_lookup(const char *iface, iref_t *retiref)
32 {
33     errval_t err;
34
35     struct dist2_rpc_client *r = get_nameservice_rpc_client();
36     if (r == NULL) {
37         return LIB_ERR_NAMESERVICE_NOT_BOUND;
38     }
39
40     char* record = NULL;
41     dist2_trigger_id_t tid;
42     errval_t error_code;
43     err = r->vtbl.get(r, iface, NOP_TRIGGER, &record, &tid, &error_code);
44     if (err_is_fail(err)) {
45         goto out;
46     }
47     err = error_code;
48     if (err_is_fail(err)) {
49         if (err_no(err) == DIST2_ERR_NO_RECORD) {
50             err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME);
51         }
52         goto out;
53     }
54
55     uint64_t iref_number = 0;
56     err = dist_read(record, "_ { iref: %d }", &iref_number);
57     if (err_is_fail(err) || iref_number == 0) {
58         err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME);
59         goto out;
60     }
61     if (retiref != NULL) {
62         *retiref = iref_number;
63     }
64
65 out:
66     free(record);
67     return err;
68 }
69
70 /**
71  * \brief Blocking name service lookup
72  *
73  * \param iface Name of interface for which to query name server
74  * \param retiref Returns pointer to IREF on success
75  */
76 errval_t nameservice_blocking_lookup(const char *iface, iref_t *retiref)
77 {
78     errval_t err;
79
80     struct dist2_rpc_client *r = get_nameservice_rpc_client();
81     if (r == NULL) {
82         return LIB_ERR_NAMESERVICE_NOT_BOUND;
83     }
84
85     char* record = NULL;
86     errval_t error_code;
87     err = r->vtbl.wait_for(r, iface, &record, &error_code);
88     if (err_is_fail(err)) {
89         goto out;
90     }
91     err = error_code;
92     if (err_is_fail(err)) {
93         if (err_no(err) == DIST2_ERR_NO_RECORD) {
94             err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME);
95         }
96         goto out;
97     }
98
99     uint64_t iref_number = 0;
100     err = dist_read(record, "_ { iref: %d }", &iref_number);
101     if (err_is_fail(err)) {
102         err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME);
103         goto out;
104     }
105     if (retiref != NULL) {
106         *retiref = iref_number;
107     }
108
109 out:
110     free(record);
111     return err;
112 }
113
114 /**
115  * \brief Register with name service
116  *
117  * \param iface Name of interface to register
118  * \param iref IREF to register
119  */
120 errval_t nameservice_register(const char *iface, iref_t iref)
121 {
122     errval_t err = SYS_ERR_OK;
123
124     struct dist2_rpc_client *r = get_nameservice_rpc_client();
125     if (r == NULL) {
126         return LIB_ERR_NAMESERVICE_NOT_BOUND;
127     }
128
129     // Format record
130     static const char* format = "%s { iref: %d }";
131     size_t len = snprintf(NULL, 0, format, iface, iref);
132     char* record = malloc(len+1);
133     if (record == NULL) {
134         return LIB_ERR_MALLOC_FAIL;
135     }
136     snprintf(record, len+1, format, iface, iref);
137
138     char* ret = NULL;
139     dist2_trigger_id_t tid;
140     errval_t error_code;
141     err = r->vtbl.set(r, record, 0, NOP_TRIGGER, 0, &ret, &tid, &error_code);
142     if (err_is_fail(err)) {
143         goto out;
144     }
145     err = error_code;
146
147 out:
148     free(record);
149     return err;
150 }
151
152 #ifdef NOT_YET_IMPLEMENTED
153 /**
154  * \brief Get a capability from the capability store.
155  *
156  * \param key           String that identifies the capability
157  * \param retcap        Pointer to structure holding capability
158  */
159 #include <stdio.h>
160 errval_t nameservice_get_capability(const char *key, struct capref *retcap)
161 {
162     errval_t reterr;
163     struct dist2_rpc_client *r = get_nameservice_rpc_client();
164     if (r == NULL) {
165         printf("nameservice not found\n");
166         return LIB_ERR_NAMESERVICE_NOT_BOUND;
167     }
168     printf("get cap %s\n", key);
169     errval_t err = r->vtbl.get_cap(r, key, retcap, &reterr);
170     if(err_is_fail(err)) {
171         printf("ERROR!\n");
172         return err_push(err, CHIPS_ERR_GET_CAP);
173     }
174     printf("nameservice_get_capability: about to return\n");
175     return reterr;
176 }
177
178 /**
179  * \brief Put a capability to the capability store.
180  *
181  * \param key           String that identifies the capability
182  * \param cap           The capability to store
183  */
184 errval_t nameservice_put_capability(const char *key, struct capref cap)
185 {
186     errval_t reterr;
187     struct dist2_rpc_client *r = get_nameservice_rpc_client();
188     if (r == NULL) {
189         return LIB_ERR_NAMESERVICE_NOT_BOUND;
190     }
191
192     errval_t err = r->vtbl.put_cap(r, key, cap, &reterr);
193     if(err_is_fail(err)) {
194         return err_push(err, CHIPS_ERR_PUT_CAP);
195     }
196
197     return reterr;
198 }
199 #endif
200
201 /* ----------------------- BIND/INIT CODE FOLLOWS ----------------------- */
202
203
204 static void error_handler(struct dist2_binding *b, errval_t err)
205 {
206     USER_PANIC_ERR(err, "asynchronous error in nameservice binding");
207 }
208
209 struct bind_state {
210     bool done;
211     errval_t err;
212 };
213
214 static void bind_continuation(void *st_arg, errval_t err,
215                               struct dist2_binding *b)
216 {
217     struct bind_state *st = st_arg;
218
219     if (err_is_ok(err)) {
220         b->error_handler = error_handler;
221
222         struct dist2_rpc_client *r;
223         r = malloc(sizeof(struct dist2_rpc_client));
224         assert(r != NULL);
225         err = dist2_rpc_client_init(r, b);
226         if (err_is_fail(err)) {
227             free(r);
228             USER_PANIC_ERR(err, "error in nameservice_rpc_client_init");
229         } else {
230             set_nameservice_rpc_client(r);
231         }
232     }
233
234     st->err = err;
235     st->done = true;
236 }
237
238 static void get_name_iref_reply(struct monitor_binding *mb, iref_t iref,
239                                 uintptr_t st_arg)
240 {
241     struct bind_state *st = (void *)st_arg;
242     errval_t err;
243
244     if (iref == 0) {
245         err = LIB_ERR_GET_NAME_IREF;
246     } else {
247         err = dist2_bind(iref, bind_continuation, st,
248                 get_default_waitset(), IDC_BIND_FLAG_RPC_CAP_TRANSFER);
249     }
250
251     if (err_is_fail(err)) {
252         st->err = err;
253         st->done = true;
254     }
255 }
256
257 /**
258  * \brief Blocking bind to the name service
259  *
260  * Should be called once only at init time on each dispatcher.
261  */
262 errval_t nameservice_client_blocking_bind(void)
263 {
264     errval_t err;
265
266     struct bind_state st = { .done = false };
267
268     /* fire off a request for the iref for the name service */
269     struct monitor_binding *mb = get_monitor_binding();
270     mb->rx_vtbl.get_name_iref_reply = get_name_iref_reply;
271     err = mb->tx_vtbl.get_name_iref_request(mb, NOP_CONT, (uintptr_t)&st);
272     if (err_is_fail(err)) {
273         return err_push(err, LIB_ERR_GET_NAME_IREF);
274     }
275
276     /* block on the default waitset until we're bound */
277     struct waitset *ws = get_default_waitset();
278     while (!st.done) {
279         err = event_dispatch(ws);
280         if (err_is_fail(err)) {
281             return err_push(err, LIB_ERR_EVENT_DISPATCH);
282         }
283     }
284
285     return st.err;
286 }
287