1/*
2 * Copyright 2016, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(D61_BSD)
11 */
12
13#include <assert.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sel4/sel4.h>
18
19#include <refos-rpc/proc_client.h>
20#include <refos-rpc/proc_client_helper.h>
21#include <refos-rpc/serv_client.h>
22#include <refos-rpc/serv_client_helper.h>
23#include <refos-util/cspace.h>
24#include <refos-util/dprintf.h>
25
26/*! @brief Special helper function to handle the fact that the process server is connectionless. */
27static bool
28serv_special_connectless_server(seL4_CPtr anon) {
29    return (anon == REFOS_NAMESERV_EP || anon == REFOS_PROCSERV_EP);
30}
31
32static serv_connection_t
33serv_connect_internal(char *serverPath, bool paramBuffer)
34{
35    _svprintf("Connecting to server [%s]...\n", serverPath);
36    serv_connection_t sc;
37    memset(&sc, 0, sizeof(serv_connection_t));
38    sc.error = EINVALID;
39
40    /* Resolve server path to find the server's anon cap. */
41    _svprintf("    Querying nameserv to find anon cap for [%s]....\n", serverPath);
42    sc.serverMountPoint = nsv_resolve(serverPath);
43    if (!sc.serverMountPoint.success || ROS_ERRNO() != ESUCCESS) {
44        _svprintf("    WARNING: Server not found.\n");
45        sc.error = ESERVERNOTFOUND;
46        goto exit1;
47    }
48
49    _svprintf("    Result path prefix [%s] anon 0x%x dspace [%s]....\n",
50        sc.serverMountPoint.nameservPathPrefix, sc.serverMountPoint.serverAnon,
51        sc.serverMountPoint.dspaceName);
52    if (serv_special_connectless_server(sc.serverMountPoint.serverAnon)) {
53        /* Connectionless server. */
54        _svprintf("    Known connectionless server detected.\n");
55        sc.connectionLess = true;
56        sc.serverSession = sc.serverMountPoint.serverAnon;
57        sc.error = ESUCCESS;
58        return sc;
59    } else {
60        /* Make connection request to server using the anon cap. */
61        _svprintf("    Make connection request to server [%s] using the anon cap 0x%x...\n",
62                serverPath, sc.serverMountPoint.serverAnon);
63        sc.serverSession = serv_connect_direct(sc.serverMountPoint.serverAnon, REFOS_LIVENESS,
64                                               &sc.error);
65    }
66    if (!sc.serverSession || sc.error != ESUCCESS) {
67        _svprintf("    WARNING: Failed to anonymously connect to server.\n");
68        goto exit2;
69    }
70
71    /* Try pinging the server. */
72    int error = serv_ping(sc.serverSession);
73    if (error) {
74        _svprintf("    WARNING: Failed to ping file server.\n");
75        sc.error = error;
76        goto exit3;
77    }
78
79    /* Set up the parameter buffer between client (ie. us) and server. */
80    if (paramBuffer) {
81        sc.paramBuffer = data_open_map(REFOS_PROCSERV_EP, "anon", 0, 0,
82                                       PROCESS_PARAM_DEFAULTSIZE, -1);
83        if (sc.paramBuffer.err != ESUCCESS) {
84            _svprintf("    WARNING: Failed to create param buffer dspace.\n");
85            sc.error = sc.paramBuffer.err;
86            goto exit3;
87        }
88        assert(sc.paramBuffer.window && sc.paramBuffer.dataspace);
89        assert(sc.paramBuffer.vaddr != NULL);
90
91        /* Set this parameter buffer on server. */
92        error = serv_set_param_buffer(sc.serverSession, sc.paramBuffer.dataspace,
93                                      PROCESS_PARAM_DEFAULTSIZE);
94        if (error) {
95            _svprintf("    Failed to set remote server parameter buffer.");
96            sc.error = error;
97            goto exit4;
98        }
99    } else {
100        sc.paramBuffer.err = -1;
101    }
102
103    _svprintf("Successfully connected to server [%s]!\n", serverPath);
104    sc.error = ESUCCESS;
105    return sc;
106
107    /* Exit stack. */
108exit4:
109    assert(sc.paramBuffer.err == ESUCCESS);
110    data_mapping_release(sc.paramBuffer);
111exit3:
112    assert(sc.serverSession);
113    if (!sc.connectionLess) {
114        serv_disconnect_direct(sc.serverSession);
115        seL4_CNode_Delete(REFOS_CSPACE, sc.serverSession, REFOS_CDEPTH);
116        csfree(sc.serverSession);
117    }
118exit2:
119    nsv_mountpoint_release(&sc.serverMountPoint);
120exit1:
121    assert(sc.error != ESUCCESS);
122    return sc;
123}
124
125serv_connection_t
126serv_connect(char *serverPath)
127{
128    return serv_connect_internal(serverPath, true);
129}
130
131serv_connection_t
132serv_connect_no_pbuffer(char *serverPath)
133{
134    return serv_connect_internal(serverPath, false);
135}
136
137void
138serv_disconnect(serv_connection_t *sc)
139{
140    if (sc == NULL || sc->error != ESUCCESS) {
141        return;
142    }
143
144    /* Clean up the parameter buffer. */
145    if (sc->paramBuffer.err == ESUCCESS && sc->paramBuffer.vaddr != NULL) {
146        data_mapping_release(sc->paramBuffer);
147    }
148
149    /* Disconnect session. */
150    if (sc->serverSession && !sc->connectionLess) {
151        serv_disconnect_direct(sc->serverSession);
152        csfree_delete(sc->serverSession);
153    }
154
155    /* Release the mountpoint. */
156    nsv_mountpoint_release(&sc->serverMountPoint);
157    memset(sc, 0, sizeof(serv_connection_t));
158}
159