1/*
2 * Copyright (c) 2011, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14#include <barrelfish/barrelfish.h>
15#include <barrelfish/spawn_client.h>
16#include <posixcompat.h>
17#include <lwip/sock_serialise.h>
18#include <vfs/fdtab.h>
19
20struct fd_store {
21    int num;
22    enum fdtab_type	type;
23    void *handle;
24    int fd;
25};
26
27struct posixcompat_sockinfo {
28};
29
30/* Copying the actual handles is hard.
31 * We could try a deep copy, but really we should come up with a serialised
32 * format for each type.  It also involves implementing the underlying
33 * resources such that the descriptors can actually be used in the new
34 * dispatcher.
35 */
36
37static size_t copy_file_fd(void *dest, genpaddr_t offset, struct fd_store *fds)
38{
39    assert(!"NYI");
40    return 0;
41}
42
43static void debug_uipaddr_print(u32_t addr)
44{
45    debug_printf("%"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
46                 (u16_t)((ntohl(addr) >> 24) & 0xff),
47                 (u16_t)((ntohl(addr) >> 16) & 0xff),
48                 (u16_t)((ntohl(addr) >> 8) & 0xff),
49                 (u16_t)(ntohl(addr) & 0xff));
50}
51
52static void debug_ipaddr_print(struct ip_addr *ipaddr) {
53    u32_t addr = ipaddr->addr;
54    debug_uipaddr_print(addr);
55
56}
57
58static size_t copy_lwip_fd(void *dest, genpaddr_t offset, struct fd_store *fds)
59{
60    size_t size = sizeof(struct lwip_sockinfo);
61
62    struct lwip_sockinfo si;
63    lwip_serialise_sock(fds->fd, &si);
64
65    printf("LWIP socket\n\tfd: %d\n", fds->fd);
66    debug_printf("local port and ip: %u\n", si.local_port);
67    debug_ipaddr_print(&si.local_ip);
68    debug_printf("remote port and ip: %u\n", si.remote_port);
69    debug_ipaddr_print(&si.remote_ip);
70
71    printf("copying %zu bytes from %p to %p\n", size, &fds->handle, dest);
72    memcpy(dest, &si, size);
73    fds->handle = (void *)(uintptr_t)(offset);
74    printf("fd %d fixed handle is: %d\n", fds->num, fds->fd);
75
76    return size;
77}
78
79static size_t copy_unixsock_fd(void *dest, genpaddr_t offset,
80                                 struct fd_store *fds)
81{
82    assert(!"NYI");
83    return 0;
84}
85
86
87/**
88 * \brief Setup inherited file descriptors
89 *
90 */
91errval_t spawn_setup_fds(struct capref *frame, int rfd)
92{
93    errval_t err;
94    void *fdspg;
95
96    // Create frame (actually multiple pages) for fds
97    err = frame_alloc(frame, FDS_SIZE, NULL);
98    if (err_is_fail(err)) {
99        return err_push(err, SPAWN_ERR_CREATE_FDSPG);
100    }
101
102    // map it in so we can write to it
103    err = vspace_map_one_frame(&fdspg, FDS_SIZE, *frame, NULL, NULL);
104    if (err_is_fail(err)) {
105        return err_push(err, SPAWN_ERR_MAP_FDSPG_TO_SELF);
106    }
107
108    /* Layout of FD page:
109     * int num_fds
110     * struct fd_store fdtab[num_fds]
111     * uint8_t buf[] // store of actual handle data.  entries in fdtab above
112     *               // point here (relative offset from the beginning of buf).
113     * TODO: add the actual handle data!
114     */
115    int *num_fds = (int *)fdspg;
116    *num_fds = 0;
117    struct fd_store *fdtab = (struct fd_store *)(num_fds + 1);
118
119    /* first copy all the fd table entries */
120    struct fdtab_entry *fde;
121    struct fd_store *fds;
122    int i = 0;
123    for (i = MIN_FD; i < MAX_FD; i++) {
124        fde = fdtab_get(i);
125        if (fde->type == FDTAB_TYPE_LWIP_SOCKET) {
126            fds = &fdtab[*num_fds];
127            fds->num = i;
128            fds->type = fde->type;
129            fds->handle = fde->handle;
130            fds->fd = fde->fd;
131            // Mark the inherited fd accordingly
132            fde->inherited = 1;
133            printf("added fd %d to fdtabs[%d]: %p as fd_store (%p: num: %d, "
134                    "type: %d, (unfixed)handle: %p)\n",
135                    i, *num_fds, &fdtab[*num_fds], fds, fds->num, fds->type,
136                   fds->handle);
137            (*num_fds)++;
138        }
139    }
140
141    /* then copy all the handle data to the buffer */
142    char *buf = (char *)&fdtab[*num_fds];
143    char *dest = buf;
144    genpaddr_t offset;
145    size_t size;
146    for (i = 0; i < *num_fds; i++) {
147        fds =  &fdtab[i];
148        offset = (genpaddr_t)(dest - buf);
149        switch (fds->type) {
150        case FDTAB_TYPE_FILE:
151            size = copy_file_fd(dest, offset, fds);
152            break;
153        case FDTAB_TYPE_UNIX_SOCKET:
154            size = copy_unixsock_fd(dest, offset, fds);
155            break;
156        case FDTAB_TYPE_LWIP_SOCKET:
157            size = copy_lwip_fd(dest, offset, fds);
158            break;
159        default:
160            // nothing to copy
161            size = 0;
162            break;
163        }
164        dest += size;
165    }
166
167    // unmap frame
168    err = vspace_unmap(fdspg);
169
170    return err;
171}
172
173errval_t posixcompat_unpack_fds(void)
174{
175    errval_t err;
176
177    /* Map the FD buffer into our address space. */
178    struct capref frame = {
179        .cnode = cnode_task,
180        .slot = TASKCN_SLOT_FDSPAGE,
181    };
182
183    struct frame_identity fi;
184    err = frame_identify(frame, &fi);
185    if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
186        // we don't have a FD buffer, return OK
187        return SYS_ERR_OK;
188    } else if (!err_is_ok(err)) {
189        // frame identify failed, return error
190        return err_push(err, LIB_ERR_FRAME_IDENTIFY);
191    }
192
193    void *fdspg;
194    err = vspace_map_one_frame(&fdspg, FDS_SIZE, frame, NULL, NULL);
195    if (err_is_fail(err)) {
196        return err_push(err, SPAWN_ERR_MAP_FDSPG_TO_SELF);
197    }
198
199    int *num_fds = (int *)fdspg;
200    struct fd_store *fdtab = (struct fd_store *)(num_fds + 1);
201    char *buf = (char *)&fdtab[*num_fds];
202
203    /* first copy all the fd table entries */
204    int i;
205    for (i = 0; i < *num_fds; i++) {
206        struct fd_store *fds = &fdtab[i];
207        struct fdtab_entry fde;
208
209        assert(fds->type == FDTAB_TYPE_LWIP_SOCKET);
210
211        fde.type = FDTAB_TYPE_LWIP_SOCKET;
212        fde.fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
213
214        struct lwip_sockinfo *si = (struct lwip_sockinfo *)(buf + (uintptr_t)fds->handle);
215        lwip_deserialise_sock(fde.fd, si);
216        debug_printf("local port and ip: %u\n", si->local_port);
217        debug_ipaddr_print(&si->local_ip);
218        debug_printf("remote port and ip: %u\n", si->remote_port);
219        debug_ipaddr_print(&si->remote_ip);
220
221        int fd = fdtab_alloc_from(&fde, fds->num);
222        assert(fd == fds->num);
223
224        printf("restored fd %d from fdtabs[%d]: %p as fd_store (%p: num: %d, "
225               "type: %d, (unfixed)handle: %p)\n",
226               fds->num, i, &fdtab[i], fds, fds->num, fds->type,
227               fds->handle);
228
229    }
230
231    // unmap frame
232    err = vspace_unmap(fdspg);
233
234    return err;
235}
236