Initial, non-functional code drop.

This commit is contained in:
Jakub Klama 2016-01-23 18:45:17 +01:00
parent be76f4b73e
commit f46d2136e9
13 changed files with 1699 additions and 0 deletions

7
Makefile Normal file
View file

@ -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 <bsd.lib.mk>

173
backend/fs.c Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <maglione.k at Gmail>
*/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#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);
}

31
backend/fs.h Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 *);

122
connection.c Normal file
View file

@ -0,0 +1,122 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <stdlib.h>
#include <sys/queue.h>
#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);
}

48
example/server.c Normal file
View file

@ -0,0 +1,48 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <stdio.h>
#include <stdlib.h>
#include <err.h>
#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");
}

214
fcall.h Normal file
View file

@ -0,0 +1,214 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <maglione.k at Gmail>
*/
#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

366
lib9p.c Normal file
View file

@ -0,0 +1,366 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <maglione.k at Gmail>
*/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#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);
}

132
lib9p.h Normal file
View file

@ -0,0 +1,132 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <sys/types.h>
#include <sys/queue.h>
#include <pthread.h>
#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

41
log.c Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <stdio.h>
#include <stdarg.h>
#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);
}

41
log.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 */

251
request.c Normal file
View file

@ -0,0 +1,251 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <string.h>
#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)
{
}

256
transport/socket.c Normal file
View file

@ -0,0 +1,256 @@
/*
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
* 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 <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/event.h>
#include <netdb.h>
#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);
}

17
transport/socket.h Normal file
View file

@ -0,0 +1,17 @@
//
// Created by Jakub Klama on 28.12.2015.
//
#ifndef LIB9P_SOCKET_H
#define LIB9P_SOCKET_H
#include <sys/types.h>
#include <sys/socket.h>
#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