1/**
2 * \file
3 * \brief This code shall be intantiated as a service within kaluga.
4 * It's main purpose is to have a service where the applications network
5 * stack can requests endpoints of NIC drivers. From the NIC drivers the applicatons
6 * network stack can request to initalized a queue and in turn receives the
7 * resources to manage this queue.
8 *
9 */
10
11/*
12 * Copyright (c) 2018, ETH Zurich.
13 * All rights reserved.
14 *
15 * This file is distributed under the terms in the attached LICENSE file.
16 * If you do not find this file, copies can be found by writing to:
17 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
18 */
19
20#include <barrelfish/barrelfish.h>
21#include <barrelfish/nameservice_client.h>
22#include <queue_service/client.h>
23
24#include <if/queue_service_defs.h>
25
26#include "debug.h"
27#include "qs_internal.h"
28
29struct queue_service_client {
30    volatile bool connected;
31    coreid_t core;
32    struct capref* ep;
33    struct queue_service_binding* b;
34};
35
36
37static void bind_cb(void *st, errval_t err, struct queue_service_binding *b)
38{
39    struct queue_service_client* q = (struct queue_service_client*) st;
40    assert(err_is_ok(err));
41
42    b->st = q;
43    q->b = b;
44    queue_service_rpc_client_init(q->b);
45
46    q->connected = true;
47
48    QUEUE_SERVICE_DEBUG("%s:%s:%d: binding done\n", __FILE__, __FUNCTION__, __LINE__);
49}
50
51/**
52 * @brief initializes the queue service client using an endpoint
53 *
54 * @param q            returned queue service client state handle
55 * @param ep           the queue service endpoint to connect to
56 *
57 * @return SYS_ERR_OK on sucess, errval on failure
58 */
59
60errval_t queue_service_client_init_with_ep(struct queue_service_client** cl,
61                                           struct capref* ep)
62{
63    errval_t err;
64
65    struct queue_service_client* tmp = calloc(sizeof(struct queue_service_client), 1);
66    if (tmp == NULL) {
67        return LIB_ERR_MALLOC_FAIL;
68    }
69
70    if (ep == NULL || capref_is_null(*ep)) {
71        return QSERVICE_ERR_NO_VALID_EP;
72    }
73
74    tmp->connected = false;
75
76    err = queue_service_bind_to_endpoint(*ep, bind_cb, tmp, get_default_waitset(),
77                                         IDC_BIND_FLAGS_DEFAULT);
78    if (err_is_fail(err)) {
79        goto out;
80    }
81
82    tmp->core = disp_get_core_id();
83    tmp->ep = ep;
84
85    while(!tmp->connected) {
86        event_dispatch(get_default_waitset());
87    }
88
89    *cl = tmp;
90
91    return SYS_ERR_OK;
92out:
93    free(cl);
94    return err;
95}
96
97/**
98 * @brief initializes the queue service client using the nameservice
99 *
100 * @param q            returned queue service client state handle
101 *
102 * @return SYS_ERR_OK on sucess, errval on failure
103 */
104errval_t queue_service_client_init(struct queue_service_client** cl)
105{
106    errval_t err;
107    iref_t iref;
108
109    QUEUE_SERVICE_DEBUG("%s:%s:%d: nameservice lookup\n", __FILE__, __FUNCTION__, __LINE__);
110
111    err = nameservice_blocking_lookup(DEFAULT_SERVICE_NAME, &iref);
112    if (err_is_fail(err)) {
113        return err;
114    }
115
116    struct queue_service_client* tmp = calloc(sizeof(struct queue_service_client), 1);
117    if (tmp == NULL) {
118        return LIB_ERR_MALLOC_FAIL;
119    }
120
121    tmp->core = disp_get_core_id();
122    tmp->connected = false;
123
124    QUEUE_SERVICE_DEBUG("%s:%s:%d: binding\n", __FILE__, __FUNCTION__, __LINE__);
125    err = queue_service_bind(iref, bind_cb, tmp, get_default_waitset(),
126                             IDC_BIND_FLAGS_DEFAULT);
127    if (err_is_fail(err)) {
128        goto out;
129    }
130
131    while(!tmp->connected) {
132        event_dispatch(get_default_waitset());
133    }
134
135    QUEUE_SERVICE_DEBUG("%s:%s:%d: connected\n", __FILE__, __FUNCTION__, __LINE__);
136    *cl = tmp;
137
138    return SYS_ERR_OK;
139out:
140    free(cl);
141    return err;
142}
143
144/**
145 * @brief requests a endpoint to a NIC by name. Using the endpoint the queue
146 *        itself can be initalized.
147 *
148 * @param cl            queue service client
149 * @param name          name of the service we want an endpont from.
150 * @param ep            returned endpoint, slot has to be allocated beforehand
151 *
152 * @return SYS_ERR_OK on sucess, errval on failure
153 */
154errval_t queue_service_client_request_ep_by_name(struct queue_service_client* cl,
155                                                 char* name, struct capref* ep)
156{
157    errval_t err, err2;
158
159    if (cl == NULL || cl->b == NULL) {
160        return QSERVICE_ERR_INVALID_CLIENT;
161    }
162
163    if (strlen(name) > MAX_NAME_LEN) {
164        return QSERVICE_ERR_NAME;
165    }
166
167    QUEUE_SERVICE_DEBUG("%s:%s:%d: requesting queue by name %s \n", __FILE__, __FUNCTION__, __LINE__, name);
168    err = cl->b->rpc_tx_vtbl.request_queue_by_name(cl->b, name, cl->core, ep, &err2);
169    if (err_is_fail(err) || err_is_fail(err2)) {
170        err = err_is_fail(err) ? err: err2;
171        goto out;
172    }
173
174    return SYS_ERR_OK;
175out:
176    slot_free(*ep);
177    return err;
178}
179