From f46d2136e915ef2d859df35fbb3f2cb8f18abfb9 Mon Sep 17 00:00:00 2001 From: Jakub Klama Date: Sat, 23 Jan 2016 18:45:17 +0100 Subject: [PATCH] Initial, non-functional code drop. --- Makefile | 7 + backend/fs.c | 173 +++++++++++++++++++++ backend/fs.h | 31 ++++ connection.c | 122 +++++++++++++++ example/server.c | 48 ++++++ fcall.h | 214 ++++++++++++++++++++++++++ lib9p.c | 366 +++++++++++++++++++++++++++++++++++++++++++++ lib9p.h | 132 ++++++++++++++++ log.c | 41 +++++ log.h | 41 +++++ request.c | 251 +++++++++++++++++++++++++++++++ transport/socket.c | 256 +++++++++++++++++++++++++++++++ transport/socket.h | 17 +++ 13 files changed, 1699 insertions(+) create mode 100644 Makefile create mode 100644 backend/fs.c create mode 100644 backend/fs.h create mode 100644 connection.c create mode 100644 example/server.c create mode 100644 fcall.h create mode 100644 lib9p.c create mode 100644 lib9p.h create mode 100644 log.c create mode 100644 log.h create mode 100644 request.c create mode 100644 transport/socket.c create mode 100644 transport/socket.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2b1487d --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +LIB= 9p +SHLIB_MAJOR= 1 +SRCS= lib9p.c connection.c request.c log.c transport/socket.c backend/fs.c +INCS= lib9p.h fcall.h log.h backend/fs.h +CFLAGS= -g -O0 + +.include diff --git a/backend/fs.c b/backend/fs.c new file mode 100644 index 0000000..e4ca793 --- /dev/null +++ b/backend/fs.c @@ -0,0 +1,173 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Based on libixp code: ©2007-2010 Kris Maglione + */ + +#include +#include +#include +#include +#include "../lib9p.h" + +static void fs_attach(void *, struct l9p_request *); +static void fs_clunk(void *, struct l9p_request *); +static void fs_create(void *, struct l9p_request *); +static void fs_flush(void *, struct l9p_request *); +static void fs_open(void *, struct l9p_request *); +static void fs_read(void *, struct l9p_request *); +static void fs_remove(void *, struct l9p_request *); +static void fs_stat(void *, struct l9p_request *); +static void fs_walk(void *, struct l9p_request *); +static void fs_write(void *, struct l9p_request *); +static void fs_wstat(void *, struct l9p_request *); + +struct fs_softc +{ + const char *fs_rootpath; +}; + +struct openfile +{ + DIR *dir; + int fd; + char *name; +}; + +static struct openfile * +open_fid(const char *path) +{ + struct openfile *ret; + + ret = malloc(sizeof(*ret)); + ret->fd = -1; + ret->name = strdup(path); + return (ret); +} + +static void +fs_attach(void *softc, struct l9p_request *req) +{ + struct fs_softc *sc = (struct fs_softc *)softc; + + req->lr_fid->lo_qid.type = L9P_QTDIR; + req->lr_fid->lo_qid.path = (uintptr_t)req->lr_fid; + req->lr_fid->lo_aux = open_fid(sc->fs_rootpath); + req->lr_resp.rattach.qid = req->lr_fid->lo_qid; + + l9p_respond(req, NULL); +} + +static void +fs_clunk(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_create(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_flush(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_open(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_read(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_remove(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_stat(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_walk(void *softc, struct l9p_request *req) +{ + int i; + char *name; + + for (i = 0; i < req->lr_req.twalk.nwname; i++) { + strcat(name, "/"); + strcat(name, req->lr_req.twalk.wname[i]); + + } +} + +static void +fs_write(void *softc, struct l9p_request *req) +{ + +} + +static void +fs_wstat(void *softc, struct l9p_request *req) +{ + +} + +int +l9p_backend_fs_init(struct l9p_backend **backendp, const char *root) +{ + struct l9p_backend *backend; + + backend = malloc(sizeof(*backend)); + backend->attach = fs_attach; + backend->clunk = fs_clunk; + backend->create = fs_create; + backend->flush = fs_flush; + backend->open = fs_open; + backend->read = fs_read; + backend->remove = fs_remove; + backend->stat = fs_stat; + backend->walk = fs_walk; + backend->write = fs_write; + backend->wstat = fs_wstat; + + *backendp = backend; + return (0); +} diff --git a/backend/fs.h b/backend/fs.h new file mode 100644 index 0000000..9833469 --- /dev/null +++ b/backend/fs.h @@ -0,0 +1,31 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + #include "../lib9p.h" + + int l9p_backend_fs_init(struct l9p_backend **, const char *); + \ No newline at end of file diff --git a/connection.c b/connection.c new file mode 100644 index 0000000..45e9162 --- /dev/null +++ b/connection.c @@ -0,0 +1,122 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "lib9p.h" + +int +l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend) +{ + struct l9p_server *server; + + server = malloc(sizeof(*server)); + server->ls_backend = backend; + LIST_INIT(&server->ls_conns); + + *serverp = server; + return (0); +} + +int +l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn) +{ + struct l9p_connection *newconn; + + newconn = malloc(sizeof(*newconn)); + LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link); + *conn = newconn; + + return (0); +} + +void +l9p_connection_free(struct l9p_connection *conn) +{ + +} + +void +l9p_connection_on_send_request(struct l9p_connection *conn, + void (*cb)(void *, size_t, void *), void *softc) +{ + + conn->lc_send_request = cb; + conn->lc_send_request_aux = softc; +} + +void +l9p_connection_recv(struct l9p_connection *conn, void *buf, size_t len) +{ + struct l9p_message msg; + struct l9p_request *req; + + req = malloc(sizeof(struct l9p_request)); + req->lr_conn = conn; + msg.lm_buffer = buf; + msg.lm_pos = buf; + msg.lm_end = buf + len; + msg.lm_mode = L9P_UNPACK; + + if (l9p_pufcall(&msg, &req->lr_req) != 0) { + + } + + l9p_dispatch_request(req); +} + +void +l9p_connection_close(struct l9p_connection *conn) +{ + +} + +struct l9p_openfile * +l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid) +{ + struct l9p_openfile *i; + + LIST_FOREACH(i, &conn->lc_files, lo_link) { + if (i->lo_fid == fid) + return (i); + } + + return (NULL); +} + +struct l9p_request * +l9p_connection_find_tag(struct l9p_connection *conn, uint32_t tag) +{ + struct l9p_request *i; + + LIST_FOREACH(i, &conn->lc_requests, lr_link) { + if (i->lr_tag == tag) + return (i); + } + + return (NULL); +} diff --git a/example/server.c b/example/server.c new file mode 100644 index 0000000..7e5c530 --- /dev/null +++ b/example/server.c @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "../lib9p.h" +#include "../transport/socket.h" +#include "../backend/fs.h" + +int +main(int argc, const char *argv[]) +{ + struct l9p_backend *fs_backend; + struct l9p_server *server; + + if (l9p_backend_fs_init(&fs_backend, argv[1]) != 0) + errx(1, "Cannot init backend:"); + + if (l9p_server_init(&server, fs_backend) != 0) + errx(1, "Cannot create server:"); + + l9p_start_server(server, "0.0.0.0", "564"); +} diff --git a/fcall.h b/fcall.h new file mode 100644 index 0000000..b639986 --- /dev/null +++ b/fcall.h @@ -0,0 +1,214 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + /* + * Based on libixp code: ©2007-2010 Kris Maglione + */ + +#ifndef LIB9P_FCALL_H +#define LIB9P_FCALL_H + +#define L9P_MAX_WELEM 256 + +enum l9p_ftype { + L9P_TVERSION = 100, + L9P_RVERSION, + L9P_TAUTH = 102, + L9P_RAUTH, + L9P_TATTACH = 104, + L9P_RATTACH, + L9P_TERROR = 106, /* illegal */ + L9P_RERROR, + L9P_TFLUSH = 108, + L9P_RFLUSH, + L9P_TWALK = 110, + L9P_RWALK, + L9P_TOPEN = 112, + L9P_ROPEN, + L9P_TCREATE = 114, + L9P_RCREATE, + L9P_TREAD = 116, + L9P_RREAD, + L9P_TWRITE = 118, + L9P_RWRITE, + L9P_TCLUNK = 120, + L9P_RCLUNK, + L9P_TREMOVE = 122, + L9P_RREMOVE, + L9P_TSTAT = 124, + L9P_RSTAT, + L9P_TWSTAT = 126, + L9P_RWSTAT, +}; + +enum l9p_qid_type +{ + L9P_QTDIR = 0x80, /* type bit for directories */ + L9P_QTAPPEND = 0x40, /* type bit for append only files */ + L9P_QTEXCL = 0x20, /* type bit for exclusive use files */ + L9P_QTMOUNT = 0x10, /* type bit for mounted channel */ + L9P_QTAUTH = 0x08, /* type bit for authentication file */ + L9P_QTTMP = 0x04, /* type bit for non-backed-up file */ + L9P_QTSYMLINK = 0x02,/* type bit for symbolic link */ + L9P_QTFILE = 0x00 /* type bits for plain file */ +}; + +struct l9p_hdr +{ + uint8_t type; + uint16_t tag; + uint32_t fid; +}; + +struct l9p_qid +{ + enum l9p_qid_type type; + uint32_t version; + uint64_t path; +}; + +struct l9p_stat +{ + uint16_t type; + uint32_t dev; + struct l9p_qid qid; + uint32_t mode; + uint32_t atime; + uint32_t mtime; + uint64_t length; + char *name; + char *uid; + char *gid; + char *muid; +}; + +struct l9p_f_version +{ + struct l9p_hdr hdr; + uint32_t msize; + char *version; +}; + +struct l9p_f_tflush +{ + struct l9p_hdr hdr; + uint16_t oldtag; +}; + +struct l9p_f_error +{ + struct l9p_hdr hdr; + char *ename; +}; + +struct l9p_f_ropen +{ + struct l9p_hdr hdr; + struct l9p_qid qid; + uint32_t iounit; +}; + +struct l9p_f_rauth +{ + struct l9p_hdr hdr; + struct l9p_qid aqid; +}; + +struct l9p_f_attach +{ + struct l9p_hdr hdr; + uint32_t afid; + char *uname; + char *aname; +}; + +struct l9p_f_tcreate +{ + struct l9p_hdr hdr; + uint32_t perm; + char *name; + uint8_t mode; /* +Topen */ +}; + +struct l9p_f_twalk +{ + struct l9p_hdr hdr; + uint32_t newfid; + uint16_t nwname; + char *wname[L9P_MAX_WELEM]; +}; + +struct l9p_f_rwalk +{ + struct l9p_hdr hdr; + uint16_t nwqid; + struct l9p_qid wqid[L9P_MAX_WELEM]; +}; + +struct l9p_f_io +{ + struct l9p_hdr hdr; + uint64_t offset; /* Tread, Twrite */ + uint32_t count; /* Tread, Twrite, Rread */ + char *data; /* Twrite, Rread */ +}; + +struct l9p_f_rstat +{ + struct l9p_hdr hdr; + uint16_t nstat; + uint8_t *stat; +}; + +struct l9p_f_twstat +{ + struct l9p_hdr hdr; + struct l9p_stat stat; +}; + +union l9p_fcall +{ + struct l9p_hdr hdr; + struct l9p_f_version version; + struct l9p_f_tflush tflush; + struct l9p_f_ropen ropen; + struct l9p_f_ropen rcreate; + struct l9p_f_ropen rattach; + struct l9p_f_error error; + struct l9p_f_rauth rauth; + struct l9p_f_attach tattach; + struct l9p_f_attach tauth; + struct l9p_f_tcreate tcreate; + struct l9p_f_tcreate topen; + struct l9p_f_twalk twalk; + struct l9p_f_rwalk rwalk; + struct l9p_f_twstat twstat; + struct l9p_f_rstat rstat; + struct l9p_f_io io; +}; + +#endif //LIB9P_FCALL_H diff --git a/lib9p.c b/lib9p.c new file mode 100644 index 0000000..20b9591 --- /dev/null +++ b/lib9p.c @@ -0,0 +1,366 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + /* + * Based on libixp code: ©2007-2010 Kris Maglione + */ + +#include +#include +#include +#include "lib9p.h" + +#define N(ary) (sizeof(ary) / sizeof(*ary)) +#define STRING_SIZE(s) (L9P_WORD + strlen(s)) +#define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD) + +static void l9p_puint(struct l9p_message *, enum l9p_integer_type, uint32_t *); +static inline void l9p_pu8(struct l9p_message *, uint8_t *); +static inline void l9p_pu16(struct l9p_message *, uint16_t *); +static inline void l9p_pu32(struct l9p_message *, uint32_t *); +static inline void l9p_pu64(struct l9p_message *, uint64_t *); +static void l9p_pustring(struct l9p_message *, char **s); +static void l9p_pustrings(struct l9p_message *, uint16_t *,char *[], size_t); +static void l9p_pudata(struct l9p_message *, uint8_t **, size_t); +static void l9p_puqid(struct l9p_message *, struct l9p_qid *); +static void l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q, + size_t); +static void l9p_pustat(struct l9p_message *, struct l9p_stat *); +static uint16_t l9p_sizeof_stat(struct l9p_stat *); + + +static void +l9p_puint(struct l9p_message *msg, enum l9p_integer_type size, uint32_t *val) +{ + uint8_t *pos; + int v; + + if(msg->lm_pos + size <= msg->lm_end) { + pos = (uint8_t*)msg->lm_pos; + switch (msg->lm_mode) { + case L9P_PACK: + v = *val; + switch (size) { + case L9P_DWORD: + pos[3] = v>>24; + pos[2] = v>>16; + case L9P_WORD: + pos[1] = v>>8; + case L9P_BYTE: + pos[0] = v; + break; + } + case L9P_UNPACK: + v = 0; + switch (size) { + case L9P_DWORD: + v |= pos[3]<<24; + v |= pos[2]<<16; + case L9P_WORD: + v |= pos[1]<<8; + case L9P_BYTE: + v |= pos[0]; + break; + } + *val = v; + } + } + msg->lm_pos += size; +} + +static inline void +l9p_pu8(struct l9p_message *msg, uint8_t *val) +{ + uint32_t v; + + v = *val; + l9p_puint(msg, L9P_BYTE, &v); + *val = (uint8_t)v; +} + +static inline void +l9p_pu16(struct l9p_message *msg, uint16_t *val) +{ + uint32_t v; + + v = *val; + l9p_puint(msg, L9P_WORD, &v); + *val = (uint16_t)v; +} + +static inline void +l9p_pu32(struct l9p_message *msg, uint32_t *val) +{ + l9p_puint(msg, L9P_DWORD, val); +} + +static inline void +l9p_pu64(struct l9p_message *msg, uint64_t *val) +{ + uint32_t vl, vb; + + vl = (uint)*val; + vb = (uint)(*val>>32); + l9p_puint(msg, L9P_DWORD, &vl); + l9p_puint(msg, L9P_DWORD, &vb); + *val = vl | ((uint64_t)vb<<32); +} + +static void +l9p_pustring(struct l9p_message *msg, char **s) +{ + uint16_t len; + + if(msg->lm_mode == L9P_PACK) + len = strlen(*s); + l9p_pu16(msg, &len); + + if (msg->lm_pos + len <= msg->lm_end) { + if (msg->lm_mode == L9P_UNPACK) { + *s = malloc(len + 1); + memcpy(*s, msg->lm_pos, len); + (*s)[len] = '\0'; + } else + memcpy(msg->lm_pos, *s, len); + } + msg->lm_pos += len; +} + +static void +l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[], + size_t max) +{ + char *s; + uint i, size; + uint16_t len; + + l9p_pu16(msg, num); + if (*num > max) { + msg->lm_pos = msg->lm_end+1; + return; + } + + s = NULL; + + if (msg->lm_mode == L9P_UNPACK) { + s = msg->lm_pos; + size = 0; + for (i = 0; i < *num; i++) { + l9p_pu16(msg, &len); + msg->lm_pos += len; + size += len; + if (msg->lm_pos > msg->lm_end) + return; + } + msg->lm_pos = s; + size += *num; + s = malloc(size); + } + + for (i = 0; i < *num; i++) { + if (msg->lm_mode == L9P_PACK) + len = strlen(strings[i]); + l9p_pu16(msg, &len); + + if (msg->lm_mode == L9P_UNPACK) { + memcpy(s, msg->lm_pos, len); + strings[i] = (char*)s; + s += len; + msg->lm_pos += len; + *s++ = '\0'; + } else + l9p_pudata(msg, &strings[i], len); + } +} + +static void +l9p_pudata(struct l9p_message *msg, uint8_t **data, size_t len) +{ + if (msg->lm_pos + len <= msg->lm_end) { + if (msg->lm_mode == L9P_UNPACK) { + *data = malloc(len); + memcpy(*data, msg->lm_pos, len); + } else + memcpy(msg->lm_pos, *data, len); + } + msg->lm_pos += len; +} + +static void +l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid) +{ + l9p_pu8(msg, &qid->type); + l9p_pu32(msg, &qid->version); + l9p_pu64(msg, &qid->path); +} + +static void +l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids, + size_t max) +{ + int i; + l9p_pu16(msg, num); + if (*num > max) { + msg->lm_pos = msg->lm_end + 1; + return; + } + + for (i = 0; i < *num; i++) + l9p_puqid(msg, &qids[i]); +} + +static void +l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat) +{ + uint16_t size; + + if(msg->lm_mode == L9P_PACK) + size = l9p_sizeof_stat(stat) - 2; + + l9p_pu16(msg, &size); + l9p_pu16(msg, &stat->type); + l9p_pu32(msg, &stat->dev); + l9p_puqid(msg, &stat->qid); + l9p_pu32(msg, &stat->mode); + l9p_pu32(msg, &stat->atime); + l9p_pu32(msg, &stat->mtime); + l9p_pu64(msg, &stat->length); + l9p_pustring(msg, &stat->name); + l9p_pustring(msg, &stat->uid); + l9p_pustring(msg, &stat->gid); + l9p_pustring(msg, &stat->muid); +} + +int +l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall) +{ + l9p_pu8(msg, &fcall->hdr.type); + l9p_pu16(msg, &fcall->hdr.tag); + + switch (fcall->hdr.type) { + case L9P_TVERSION: + case L9P_RVERSION: + l9p_pu32(msg, &fcall->version.msize); + l9p_pustring(msg, &fcall->version.version); + break; + case L9P_TAUTH: + l9p_pu32(msg, &fcall->tauth.afid); + l9p_pustring(msg, &fcall->tauth.uname); + l9p_pustring(msg, &fcall->tauth.aname); + break; + case L9P_RAUTH: + l9p_puqid(msg, &fcall->rauth.aqid); + break; + case L9P_RATTACH: + l9p_puqid(msg, &fcall->rattach.qid); + break; + case L9P_TATTACH: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu32(msg, &fcall->tattach.afid); + l9p_pustring(msg, &fcall->tattach.uname); + l9p_pustring(msg, &fcall->tattach.aname); + break; + case L9P_RERROR: + l9p_pustring(msg, &fcall->error.ename); + break; + case L9P_TFLUSH: + l9p_pu16(msg, &fcall->tflush.oldtag); + break; + case L9P_TWALK: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu32(msg, &fcall->twalk.newfid); + l9p_pustrings(msg, &fcall->twalk.nwname, fcall->twalk.wname, + N(fcall->twalk.wname)); + break; + case L9P_RWALK: + l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid, + N(fcall->rwalk.wqid)); + break; + case L9P_TOPEN: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu8(msg, &fcall->topen.mode); + break; + case L9P_ROPEN: + case L9P_RCREATE: + l9p_puqid(msg, &fcall->ropen.qid); + l9p_pu32(msg, &fcall->ropen.iounit); + break; + case L9P_TCREATE: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pustring(msg, &fcall->tcreate.name); + l9p_pu32(msg, &fcall->tcreate.perm); + l9p_pu8(msg, &fcall->tcreate.mode); + break; + case L9P_TREMOVE: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu64(msg, &fcall->io.offset); + l9p_pu32(msg, &fcall->io.count); + break; + case L9P_RREAD: + l9p_pu32(msg, &fcall->io.count); + l9p_pudata(msg, &fcall->io.data, fcall->io.count); + break; + case L9P_TWRITE: + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu64(msg, &fcall->io.offset); + l9p_pu32(msg, &fcall->io.count); + l9p_pudata(msg, &fcall->io.data, fcall->io.count); + break; + case L9P_RWRITE: + l9p_pu32(msg, &fcall->io.count); + break; + case L9P_TCLUNK: + case L9P_TSTAT: + l9p_pu32(msg, &fcall->hdr.fid); + break; + case L9P_RSTAT: + l9p_pu16(msg, &fcall->rstat.nstat); + l9p_pudata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat); + break; + case L9P_TWSTAT: { + uint16_t size; + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu16(msg, &size); + l9p_pustat(msg, &fcall->twstat.stat); + break; + } + } +} + +static uint16_t +l9p_sizeof_stat(struct l9p_stat *stat) { + return L9P_WORD /* size */ + + L9P_WORD /* type */ + + L9P_DWORD /* dev */ + + QID_SIZE /* qid */ + + 3 * L9P_DWORD /* mode, atime, mtime */ + + L9P_DWORD /* length */ + + STRING_SIZE(stat->name) + + STRING_SIZE(stat->uid) + + STRING_SIZE(stat->gid) + + STRING_SIZE(stat->muid); +} diff --git a/lib9p.h b/lib9p.h new file mode 100644 index 0000000..bc4f828 --- /dev/null +++ b/lib9p.h @@ -0,0 +1,132 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#ifndef LIB9P_LIB9P_H +#define LIB9P_LIB9P_H + +#include +#include +#include +#include "fcall.h" + +#define L9P_ENOFID "FID does not exist" +#define L9P_ENOFUNC "Function not implemented" +#define L9P_EINTR "Interrupted" + +enum l9p_pack_mode +{ + L9P_PACK, + L9P_UNPACK +}; + +enum l9p_integer_type +{ + L9P_BYTE = 1, + L9P_WORD = 2, + L9P_DWORD = 4, + L9P_QWORD = 8 +}; + +struct l9p_message +{ + enum l9p_pack_mode lm_mode; + uint8_t *lm_buffer; + uint8_t *lm_pos; + uint8_t *lm_end; +}; + +struct l9p_request +{ + uint32_t lr_tag; + union l9p_fcall lr_req; + union l9p_fcall lr_resp; + struct l9p_openfile *lr_fid; + struct l9p_connection *lr_conn; + pthread_t lr_thread; + LIST_ENTRY(l9p_request) lr_link; +}; + +struct l9p_openfile +{ + char *lo_uid; + void *lo_aux; + uint32_t lo_fid; + struct l9p_qid lo_qid; + struct l9p_connection *lo_conn; + LIST_ENTRY(l9p_openfile) lo_link; +}; + +struct l9p_connection +{ + struct l9p_server *lc_server; + pthread_mutex_t lc_send_lock; + void (*lc_send_request)(const void *, const size_t, void *); + void *lc_send_request_aux; + void *lc_softc; + LIST_HEAD(, l9p_request) lc_requests; + LIST_HEAD(, l9p_openfile) lc_files; + LIST_ENTRY(l9p_connection) lc_link; +}; + +struct l9p_server +{ + struct l9p_backend *ls_backend; + LIST_HEAD(, l9p_connection) ls_conns; +}; + +struct l9p_backend +{ + void *softc; + void (*attach)(void *, struct l9p_request *); + void (*clunk)(void *, struct l9p_request *); + void (*create)(void *, struct l9p_request *); + void (*flush)(void *, struct l9p_request *); + void (*open)(void *, struct l9p_request *); + void (*read)(void *, struct l9p_request *); + void (*remove)(void *, struct l9p_request *); + void (*stat)(void *, struct l9p_request *); + void (*walk)(void *, struct l9p_request *); + void (*write)(void *, struct l9p_request *); + void (*wstat)(void *, struct l9p_request *); + void (*freefid)(void *, struct l9p_openfile *); +}; + +int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall); + +int l9p_server_init(struct l9p_server **, struct l9p_backend *backend); + +int l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn); +void l9p_connection_free(struct l9p_connection *conn); +void l9p_connection_on_send_request(struct l9p_connection *conn, void (*cb)(void *, size_t, void *), void *); +void l9p_connection_recv(struct l9p_connection *conn, void *buf, size_t len); +void l9p_connection_close(struct l9p_connection *conn); +struct l9p_openfile *l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid); +struct l9p_request *l9p_connection_find_tag(struct l9p_connection *conn, uint32_t tag); +void l9p_respond(struct l9p_request *req, const char *error); + +#endif //LIB9P_LIB9P_H diff --git a/log.c b/log.c new file mode 100644 index 0000000..f38d99d --- /dev/null +++ b/log.c @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "log.h" + +void +l9p_logf(enum l9p_log_level level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..1173826 --- /dev/null +++ b/log.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef LIB9P_LOG_H +#define LIB9P_LOG_H + +enum l9p_log_level +{ + L9P_DEBUG, + L9P_INFO, + L9P_WARNING, + L9P_ERROR +}; + +void l9p_logf(enum l9p_log_level level, const char *fmt, ...); + +#endif /* LIB9P_LOG_H */ \ No newline at end of file diff --git a/request.c b/request.c new file mode 100644 index 0000000..f9b5d18 --- /dev/null +++ b/request.c @@ -0,0 +1,251 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include "lib9p.h" +#include "fcall.h" +#include "log.h" + +#define N(x) (sizeof(x) / sizeof(x[0])) + +static void l9p_dispatch_tversion(struct l9p_request *req); +static void l9p_dispatch_tattach(struct l9p_request *req); +static void l9p_dispatch_tclunk(struct l9p_request *req); +static void l9p_dispatch_tflush(struct l9p_request *req); +static void l9p_dispatch_tcreate(struct l9p_request *req); +static void l9p_dispatch_topen(struct l9p_request *req); +static void l9p_dispatch_tread(struct l9p_request *req); +static void l9p_dispatch_tremove(struct l9p_request *req); +static void l9p_dispatch_tstat(struct l9p_request *req); +static void l9p_dispatch_twalk(struct l9p_request *req); +static void l9p_dispatch_twrite(struct l9p_request *req); +static void l9p_dispatch_twstat(struct l9p_request *req); + +static struct +{ + enum l9p_ftype type; + void (*handler)(struct l9p_request *); +} l9p_handlers[] = { + {L9P_TVERSION, l9p_dispatch_tversion}, + {L9P_TATTACH, l9p_dispatch_tattach}, + {L9P_TCLUNK, l9p_dispatch_tclunk}, + {L9P_TFLUSH, l9p_dispatch_tflush}, + {L9P_TCREATE, l9p_dispatch_tcreate}, + {L9P_TOPEN, l9p_dispatch_topen}, + {L9P_TREAD, l9p_dispatch_tread}, + {L9P_TWRITE, l9p_dispatch_twrite}, + {L9P_TREMOVE, l9p_dispatch_tremove}, + {L9P_TSTAT, l9p_dispatch_tstat}, + {L9P_TWALK, l9p_dispatch_twalk}, + {L9P_TWSTAT, l9p_dispatch_twstat} +}; + +void +l9p_dispatch_request(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + int i; + + l9p_logf(L9P_INFO, "new request of type %d", req->lr_req.hdr.type); + req->lr_tag = req->lr_req.hdr.tag; + + for (i = 0; i < N(l9p_handlers); i++) { + if (req->lr_req.hdr.type == l9p_handlers[i].type) { + l9p_handlers[i].handler(req); + return; + } + } +} + +void +l9p_respond(struct l9p_request *req, const char *error) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_message msg; + void *buf = malloc(1024 * 1024); + + msg.lm_buffer = buf; + msg.lm_pos = buf; + msg.lm_end = buf + (1024 * 1024); + msg.lm_mode = L9P_PACK; + + switch (req->lr_req.hdr.type) { + case L9P_TVERSION: + break; + } + + req->lr_resp.hdr.tag = req->lr_req.hdr.tag; + + if (error == NULL) + req->lr_resp.hdr.type = req->lr_req.hdr.type + 1; + else { + req->lr_resp.hdr.type = L9P_RERROR; + req->lr_resp.error.ename = error; + } + + if (l9p_pufcall(&msg, &req->lr_resp) != 0) { + + } + + conn->lc_send_request(msg.lm_buffer, msg.lm_pos - msg.lm_buffer, conn->lc_send_request_aux); +} + +static void +l9p_dispatch_tversion(struct l9p_request *req) +{ + if (!strcmp(req->lr_req.version.version, "9P")) + req->lr_resp.version.version = "9P"; + else if (!strcmp(req->lr_req.version.version, "9P2000")) + req->lr_resp.version.version = "9P2000"; + else + req->lr_resp.version.version = "unknown"; + + req->lr_resp.version.msize = req->lr_resp.version.msize; + l9p_respond(req, NULL); +} + +static void +l9p_dispatch_tattach(struct l9p_request *req) +{ + +} + +static void +l9p_dispatch_tclunk(struct l9p_request *req) +{ + +} + +static void +l9p_dispatch_tflush(struct l9p_request *req) +{ + +} + +static void +l9p_dispatch_tcreate(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_openfile *fid; + + if (l9p_connection_find_fid(conn, req->lr_req.tcreate.hdr.fid) != NULL) { + l9p_respond(req, "x"); + return; + } + + fid = malloc(sizeof(struct l9p_openfile)); + fid->lo_fid = req->lr_req.tcreate.hdr.fid; + fid->lo_conn = conn; + LIST_INSERT_HEAD(&conn->lc_files, fid, lo_link); + + conn->lc_server->ls_backend->create(conn->lc_server->ls_backend->softc, req); +} + +static void +l9p_dispatch_topen(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_openfile *fid; + + fid = l9p_connection_find_fid(conn, req->lr_req.topen.hdr.fid); + if (!fid) { + l9p_respond(req, L9P_ENOFID); + return; + } + + if (!conn->lc_server->ls_backend->open) { + l9p_respond(req, L9P_ENOFUNC); + return; + } + + conn->lc_server->ls_backend->open(conn->lc_server->ls_backend->softc, req); +} + +static void +l9p_dispatch_tread(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_openfile *fid; + + fid = l9p_connection_find_fid(conn, req->lr_req.tcreate.hdr.fid); + if (!fid) { + l9p_respond(req, L9P_ENOFID); + return; + } +} + +static void +l9p_dispatch_tremove(struct l9p_request *req) +{ + +} + +static void +l9p_dispatch_tstat(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_openfile *fid; + + +} + +static void +l9p_dispatch_twalk(struct l9p_request *req) +{ + struct l9p_connection *conn = req->lr_conn; + struct l9p_openfile *fid; + + fid = l9p_connection_find_fid(conn, req->lr_req.twalk.hdr.fid); + if (!fid) { + l9p_respond(req, L9P_ENOFID); + return; + } + + if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) { + + } + + if (!conn->lc_server->ls_backend->walk) { + l9p_respond(req, L9P_ENOFUNC); + return; + } + + conn->lc_server->ls_backend->walk(conn->lc_server->ls_backend->softc, req); +} + +static void +l9p_dispatch_twrite(struct l9p_request *req) +{ + +} + +static void +l9p_dispatch_twstat(struct l9p_request *req) +{ + +} diff --git a/transport/socket.c b/transport/socket.c new file mode 100644 index 0000000..602495a --- /dev/null +++ b/transport/socket.c @@ -0,0 +1,256 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../lib9p.h" +#include "../log.h" +#include "socket.h" + +static int l9p_socket_readmsg(int, void **, size_t *); +static void l9p_socket_sendmsg(void *, size_t, void *); +static void *l9p_socket_thread(void *); +static int xread(int, void *, size_t); +static int xwrite(int, void *, size_t); + +struct l9p_socket_softc +{ + struct l9p_connection *ls_conn; + struct sockaddr ls_sockaddr; + socklen_t ls_socklen; + pthread_t ls_thread; + int ls_fd; +}; + +int +l9p_start_server(struct l9p_server *server, const char *host, const char *port) +{ + struct addrinfo *res, *res0, hints; + struct kevent kev[2]; + struct kevent event[2]; + int err, kq, i, val, evs, nsockets = 0; + int sockets[2]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + err = getaddrinfo(host, port, &hints, &res0); + + if (err) + return (-1); + + for (res = res0; res; res = res->ai_next) { + int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + + val = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + if (s < 0) + continue; + + if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { + close(s); + continue; + } + + sockets[nsockets] = s; + EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + listen(s, 10); + } + + kq = kqueue(); + kevent(kq, kev, nsockets, NULL, 0, NULL); + + for (;;) { + evs = kevent(kq, NULL, 0, event, nsockets, NULL); + if (evs < 0) { + + } + + for (i = 0; i < evs; i++) { + struct sockaddr client_addr; + socklen_t client_addr_len; + int news = accept(event[i].ident, &client_addr, + &client_addr_len); + + if (news < 0) { + l9p_logf(L9P_WARNING, "accept(): %s", strerror(errno)); + continue; + } + + l9p_socket_accept(server, news, &client_addr, + client_addr_len); + } + } + +} + +void +l9p_socket_accept(struct l9p_server *server, int conn_fd, + struct sockaddr *client_addr, socklen_t client_addr_len) +{ + struct l9p_socket_softc *sc; + struct l9p_connection *conn; + char host[NI_MAXHOST + 1]; + char serv[NI_MAXSERV + 1]; + int err; + + err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv, + NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); + + if (err != 0) { + l9p_logf(L9P_WARNING, "cannot look up client name: %s", + gai_strerror(err)); + } else + l9p_logf(L9P_INFO, "new connection from %s:%s", host, serv); + + if (l9p_connection_init(server, &conn) != 0) { + l9p_logf(L9P_ERROR, "cannot create new connection"); + } + + sc = malloc(sizeof(sc)); + sc->ls_conn = conn; + sc->ls_fd = conn_fd; + + l9p_connection_on_send_request(conn, l9p_socket_sendmsg, sc); + pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc); +} + +static void * +l9p_socket_thread(void *arg) +{ + struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; + void *buf; + size_t length; + + for (;;) { + if (l9p_socket_readmsg(sc->ls_fd, &buf, &length) != 0) + break; + + l9p_connection_recv(sc->ls_conn, buf, length); + } + + return (NULL); +} + +static int +l9p_socket_readmsg(int fd, void **buf, size_t *size) +{ + uint32_t msize; + void *buffer; + + if (xread(fd, &msize, sizeof(uint32_t)) != sizeof(uint32_t)) { + l9p_logf(L9P_ERROR, "short read: %s", strerror(errno)); + return (-1); + } + + msize -= sizeof(msize); + buffer = malloc(msize); + + if (xread(fd, buffer, msize) != msize) { + l9p_logf(L9P_ERROR, "short read: %s", strerror(errno)); + return (-1); + } + + *size = msize; + *buf = buffer; + l9p_logf(L9P_INFO, "read complete message, size=%d", msize); + + return (0); +} + +static void +l9p_socket_sendmsg(void *buf, size_t len, void *arg) +{ + struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; + uint32_t msize = (uint32_t)len + sizeof(uint32_t); + + if (xwrite(sc->ls_fd, &msize, sizeof(uint32_t) != sizeof(uint32_t))) { + l9p_logf(L9P_ERROR, "short write: %s", strerror(errno)); + return; + } + + if (xwrite(sc->ls_fd, buf, len) != len) { + l9p_logf(L9P_ERROR, "short write: %s", strerror(errno)); + return; + } +} + +static int +xread(int fd, void *buf, size_t count) +{ + size_t done = 0; + int ret; + + while (done < count) { + ret = read(fd, buf + done, count - done); + if (ret < 0) { + if (errno == EINTR) + continue; + + return (-1); + } + + if (ret == 0) + return (done); + + done += ret; + } + + return (done); +} + +static int +xwrite(int fd, void *buf, size_t count) +{ + size_t done = 0; + int ret; + + while (done < count) { + ret = write(fd, buf + done, count - done); + if (ret < 0) { + if (errno == EINTR) + continue; + + return (-1); + } + + if (ret == 0) + return (done); + + done += ret; + } + + return (done); +} diff --git a/transport/socket.h b/transport/socket.h new file mode 100644 index 0000000..ea48833 --- /dev/null +++ b/transport/socket.h @@ -0,0 +1,17 @@ +// +// Created by Jakub Klama on 28.12.2015. +// + +#ifndef LIB9P_SOCKET_H +#define LIB9P_SOCKET_H + +#include +#include +#include "../lib9p.h" + +int l9p_start_server(struct l9p_server *server, const char *host, + const char *port); +void l9p_socket_accept(struct l9p_server *server, int conn_fd, + struct sockaddr *client_addr, socklen_t client_addr_len); + +#endif //LIB9P_SOCKET_H