From 9345f947cce9da0b9ec9ab8b2c6f0a072755b00d Mon Sep 17 00:00:00 2001 From: Falk Werner Date: Sat, 13 Apr 2019 21:44:53 +0200 Subject: [PATCH] allow clients to register filesystems --- example/daemon/www/js/connection_view.js | 4 +- example/daemon/www/js/startup.js | 4 +- example/daemon/www/js/webfuse/client.js | 13 ++- lib/webfuse/adapter/impl/filesystem.c | 44 ++++++++ lib/webfuse/adapter/impl/filesystem.h | 11 ++ lib/webfuse/adapter/impl/server_protocol.c | 45 +++++++- lib/webfuse/adapter/impl/session.c | 116 +++++++++++++++------ lib/webfuse/adapter/impl/session.h | 23 ++-- lib/webfuse/adapter/impl/session_manager.c | 17 +-- lib/webfuse/adapter/impl/session_manager.h | 3 +- 10 files changed, 217 insertions(+), 63 deletions(-) diff --git a/example/daemon/www/js/connection_view.js b/example/daemon/www/js/connection_view.js index c46b584..a1f36b6 100644 --- a/example/daemon/www/js/connection_view.js +++ b/example/daemon/www/js/connection_view.js @@ -1,5 +1,6 @@ export class ConnectionView { - constructor(client) { + constructor(client, provider) { + this._provider = provider; this._client = client; this._client.onopen = () => { this._onConnectionOpened(); }; this._client.onclose = () => { this._onConnectionClosed(); }; @@ -73,6 +74,7 @@ export class ConnectionView { } _onConnectionOpened() { + this._client.addProvider("test", this._provider); this.connectButton.value = "disconnect"; } diff --git a/example/daemon/www/js/startup.js b/example/daemon/www/js/startup.js index cdc0796..284d229 100644 --- a/example/daemon/www/js/startup.js +++ b/example/daemon/www/js/startup.js @@ -17,8 +17,8 @@ function startup() { "say_hello.sh": { inode: 3, mode: mode("0555"), type: "file", contents: "#!/bin/sh\necho hello\n"} } }); - const client = new Client(provider); - const connectionView = new ConnectionView(client); + const client = new Client(); + const connectionView = new ConnectionView(client, provider); document.getElementById('connection').appendChild(connectionView.element); } diff --git a/example/daemon/www/js/webfuse/client.js b/example/daemon/www/js/webfuse/client.js index 2838732..2505217 100644 --- a/example/daemon/www/js/webfuse/client.js +++ b/example/daemon/www/js/webfuse/client.js @@ -4,7 +4,7 @@ export class Client { static get _PROTOCOL() { return "fs"; } constructor(provider) { - this._provider = provider; + this._provider = { }; this._ws = null; this.onopen = () => { }; this.onclose = () => { }; @@ -34,6 +34,17 @@ export class Client { this._ws.send(JSON.stringify(request)); } + addProvider(name, provider) { + this._provider = provider; + const request = { + "method": "add_filesystem", + "params": [name], + "id": 23 + }; + + this._ws.send(JSON.stringify(request)); + } + disconnect() { if (this._ws) { this._ws.close(); diff --git a/lib/webfuse/adapter/impl/filesystem.c b/lib/webfuse/adapter/impl/filesystem.c index 0c8a1e4..22d18bf 100644 --- a/lib/webfuse/adapter/impl/filesystem.c +++ b/lib/webfuse/adapter/impl/filesystem.c @@ -1,5 +1,8 @@ #include "webfuse/adapter/impl/filesystem.h" #include "webfuse/adapter/impl/operations.h" +#include "webfuse/adapter/impl/session.h" + +#include #include #include @@ -16,6 +19,31 @@ static struct fuse_lowlevel_ops const filesystem_operations = .read = &wf_impl_operation_read }; +struct wf_impl_filesystem * wf_impl_filesystem_create( + struct wf_impl_session * session, + char const * mount_point) +{ + struct wf_impl_filesystem * filesystem = malloc(sizeof(struct wf_impl_filesystem)); + if (NULL != filesystem) + { + bool success = wf_impl_filesystem_init(filesystem, session, mount_point); + if (!success) + { + free(filesystem); + filesystem = NULL; + } + } + + return filesystem; +} + +void wf_impl_filesystem_dispose( + struct wf_impl_filesystem * filesystem) +{ + wf_impl_filesystem_cleanup(filesystem); + free(filesystem); +} + bool wf_impl_filesystem_init( struct wf_impl_filesystem * filesystem, @@ -23,6 +51,7 @@ bool wf_impl_filesystem_init( char const * mount_point) { bool result = false; + wf_dlist_item_init(&filesystem->item); char * argv[] = {"", NULL}; filesystem->args.argc = 1; @@ -43,6 +72,21 @@ bool wf_impl_filesystem_init( result = (0 == fuse_session_mount(filesystem->session, mount_point)); } + if (result) + { + lws_sock_file_fd_type fd; + fd.filefd = fuse_session_fd(filesystem->session); + struct lws_protocols const * protocol = lws_get_protocol(session->wsi); + filesystem->wsi = lws_adopt_descriptor_vhost(lws_get_vhost(session->wsi), LWS_ADOPT_RAW_FILE_DESC, fd, protocol->name, session->wsi); + + if (NULL == filesystem->wsi) + { + wf_impl_filesystem_cleanup(filesystem); + result = false; + } + + } + return result; } diff --git a/lib/webfuse/adapter/impl/filesystem.h b/lib/webfuse/adapter/impl/filesystem.h index db1ef81..7d13b07 100644 --- a/lib/webfuse/adapter/impl/filesystem.h +++ b/lib/webfuse/adapter/impl/filesystem.h @@ -7,6 +7,7 @@ #include "webfuse/adapter/impl/fuse_wrapper.h" #include "webfuse/adapter/impl/operations.h" +#include "webfuse/core/dlist.h" #ifdef __cplusplus extern "C" @@ -14,15 +15,25 @@ extern "C" #endif struct wf_impl_session; +struct lws; struct wf_impl_filesystem { + struct wf_dlist_item item; struct fuse_args args; struct fuse_session * session; struct fuse_buf buffer; struct wf_impl_operations_context user_data; + struct lws * wsi; }; +extern struct wf_impl_filesystem * wf_impl_filesystem_create( + struct wf_impl_session * session, + char const * mount_point); + +extern void wf_impl_filesystem_dispose( + struct wf_impl_filesystem * filesystem); + extern bool wf_impl_filesystem_init( struct wf_impl_filesystem * filesystem, struct wf_impl_session * session, diff --git a/lib/webfuse/adapter/impl/server_protocol.c b/lib/webfuse/adapter/impl/server_protocol.c index 16279ae..6a41b5a 100644 --- a/lib/webfuse/adapter/impl/server_protocol.c +++ b/lib/webfuse/adapter/impl/server_protocol.c @@ -31,8 +31,7 @@ static int wf_impl_server_protocol_callback( &protocol->authenticators, &protocol->timeout_manager, &protocol->server, - protocol->mount_point, - ws_protocol->name); + protocol->mount_point); if (NULL != session) { @@ -57,7 +56,7 @@ static int wf_impl_server_protocol_callback( case LWS_CALLBACK_RAW_RX_FILE: if (NULL != session) { - wf_impl_filesystem_process_request(&session->filesystem); + wf_impl_session_process_filesystem_request(session, wsi); } break; default: @@ -130,6 +129,45 @@ static void wf_impl_server_protocol_authenticate( } } +static void wf_impl_server_protocol_add_filesystem( + struct wf_impl_jsonrpc_request * request, + char const * WF_UNUSED_PARAM(method_name), + json_t * params, + void * WF_UNUSED_PARAM(user_data)) +{ + struct wf_impl_session * session = wf_impl_jsonrpc_request_get_userdata(request); + wf_status status = (session->is_authenticated) ? WF_GOOD : WF_BAD_ACCESS_DENIED; + + char const * name = NULL; + if (WF_GOOD == status) + { + json_t * name_holder = json_array_get(params, 0); + if (json_is_string(name_holder)) + { + name = json_string_value(name_holder); + bool const success = wf_impl_session_add_filesystem(session, name); + if (!success) + { + status = WF_BAD; + } + } + } + + if (WF_GOOD == status) + { + json_t * result = json_object(); + json_object_set_new(result, "id", json_string(name)); + wf_impl_jsonrpc_respond(request, result); + } + else + { + wf_impl_jsonrpc_respond_error(request, status); + } + + +} + + void wf_impl_server_protocol_init( struct wf_server_protocol * protocol, char * mount_point) @@ -142,6 +180,7 @@ void wf_impl_server_protocol_init( wf_impl_jsonrpc_server_init(&protocol->server); wf_impl_jsonrpc_server_add(&protocol->server, "authenticate", &wf_impl_server_protocol_authenticate, protocol); + wf_impl_jsonrpc_server_add(&protocol->server, "add_filesystem", &wf_impl_server_protocol_add_filesystem, protocol); } void wf_impl_server_protocol_cleanup( diff --git a/lib/webfuse/adapter/impl/session.c b/lib/webfuse/adapter/impl/session.c index 9f6bfd1..2aa5ab5 100644 --- a/lib/webfuse/adapter/impl/session.c +++ b/lib/webfuse/adapter/impl/session.c @@ -6,6 +6,11 @@ #include "webfuse/adapter/impl/jsonrpc/request.h" #include "webfuse/adapter/impl/jsonrpc/response.h" +#include "webfuse/core/container_of.h" +#include "webfuse/core/util.h" + +#include + #include #include #include @@ -40,66 +45,48 @@ struct wf_impl_session * wf_impl_session_create( struct wf_impl_authenticators * authenticators, struct wf_impl_timeout_manager * timeout_manager, struct wf_impl_jsonrpc_server * server, - char const * mount_point, - char const * protocol_name) + char const * mount_point) { - static int session_id = 0; struct wf_impl_session * session = malloc(sizeof(struct wf_impl_session)); if (NULL != session) { - snprintf(session->mount_point, PATH_MAX, "%s/%d", mount_point, session_id); - session_id++; - mkdir(session->mount_point, 0755); - wf_dlist_item_init(&session->item); + wf_dlist_init(&session->filesystems); + session->mount_point = strdup(mount_point); session->wsi = wsi; session->is_authenticated = false; session->authenticators = authenticators; session->server = server; wf_impl_jsonrpc_proxy_init(&session->rpc, timeout_manager, &wf_impl_session_send, session); wf_message_queue_init(&session->queue); - - bool success = wf_impl_filesystem_init(&session->filesystem, session, session->mount_point); - if (success) - { - lws_sock_file_fd_type fd; - fd.filefd = wf_impl_filesystem_get_fd(&session->filesystem); - session->wsi_fuse = lws_adopt_descriptor_vhost(lws_get_vhost(wsi), LWS_ADOPT_RAW_FILE_DESC, fd, protocol_name, wsi); - if (NULL == session->wsi_fuse) - { - success = false; - fprintf(stderr, "error: unable to adopt fd"); - } - } - - if (!success) - { - rmdir(session->mount_point); - wf_impl_jsonrpc_proxy_cleanup(&session->rpc); - wf_message_queue_cleanup(&session->queue); - free(session); - session = NULL; - } } return session; } +static void wf_impl_session_cleanup_filesystem( + struct wf_dlist_item * item, + void * WF_UNUSED_PARAM(user_data)) +{ + struct wf_impl_filesystem * filesystem = WF_CONTAINER_OF(item, struct wf_impl_filesystem, item); + wf_impl_filesystem_dispose(filesystem); + +} + void wf_impl_session_dispose( struct wf_impl_session * session) { - wf_impl_filesystem_cleanup(&session->filesystem); - rmdir(session->mount_point); + wf_dlist_cleanup(&session->filesystems, &wf_impl_session_cleanup_filesystem, NULL); wf_impl_jsonrpc_proxy_cleanup(&session->rpc); wf_message_queue_cleanup(&session->queue); session->is_authenticated = false; session->wsi = NULL; - session->wsi_fuse = NULL; session->authenticators = NULL; session->server = NULL; + free(session->mount_point); free(session); } @@ -112,6 +99,25 @@ bool wf_impl_session_authenticate( return session->is_authenticated; } +bool wf_impl_session_add_filesystem( + struct wf_impl_session * session, + char const * name) +{ + uuid_t uuid; + uuid_generate(uuid); + char id[UUID_STR_LEN]; + uuid_unparse(uuid, id); + + char mount_point[PATH_MAX]; + snprintf(mount_point, PATH_MAX, "%s/%s/%s", session->mount_point, name, id); + mkdir(mount_point, 0755); + + struct wf_impl_filesystem * filesystem = wf_impl_filesystem_create(session, mount_point); + wf_dlist_prepend(&session->filesystems, &filesystem->item); + return (NULL != filesystem); +} + + void wf_impl_session_onwritable( struct wf_impl_session * session) { @@ -149,4 +155,48 @@ void wf_impl_session_receive( json_decref(message); } -} \ No newline at end of file +} + +static struct wf_impl_filesystem * wf_impl_session_get_filesystem( + struct wf_impl_session * session, + struct lws * wsi) +{ + struct wf_impl_filesystem * filesystem = WF_CONTAINER_OF(session->filesystems.first, struct wf_impl_filesystem, item); + while (NULL != filesystem) + { + if (wsi == filesystem->wsi) + { + break; + } + else + { + filesystem = WF_CONTAINER_OF(filesystem->item.next, struct wf_impl_filesystem, item); + } + } + + return filesystem; +} + + +bool wf_impl_session_contains_wsi( + struct wf_dlist_item * item, + void * user_data) +{ + struct lws * wsi = user_data; + struct wf_impl_session * session = WF_CONTAINER_OF(item, struct wf_impl_session, item); + + bool const result = (NULL != wsi) && ((wsi == session->wsi) || (NULL != wf_impl_session_get_filesystem(session, wsi))); + return result; +} + + +void wf_impl_session_process_filesystem_request( + struct wf_impl_session * session, + struct lws * wsi) +{ + struct wf_impl_filesystem * filesystem = wf_impl_session_get_filesystem(session, wsi); + if (NULL != filesystem) + { + wf_impl_filesystem_process_request(filesystem); + } +} diff --git a/lib/webfuse/adapter/impl/session.h b/lib/webfuse/adapter/impl/session.h index 4fc8490..c0c3f96 100644 --- a/lib/webfuse/adapter/impl/session.h +++ b/lib/webfuse/adapter/impl/session.h @@ -9,8 +9,6 @@ using std::size_t; #endif -#include - #include "webfuse/core/message_queue.h" #include "webfuse/adapter/impl/jsonrpc/proxy.h" #include "webfuse/adapter/impl/jsonrpc/server.h" @@ -31,15 +29,14 @@ struct wf_impl_timeout_manager; struct wf_impl_session { struct wf_dlist_item item; - char mount_point[PATH_MAX]; + char * mount_point; struct lws * wsi; - struct lws * wsi_fuse; bool is_authenticated; struct wf_message_queue queue; - struct wf_impl_filesystem filesystem; struct wf_impl_authenticators * authenticators; struct wf_impl_jsonrpc_server * server; struct wf_impl_jsonrpc_proxy rpc; + struct wf_dlist filesystems; }; extern struct wf_impl_session * wf_impl_session_create( @@ -47,8 +44,7 @@ extern struct wf_impl_session * wf_impl_session_create( struct wf_impl_authenticators * authenticators, struct wf_impl_timeout_manager * timeout_manager, struct wf_impl_jsonrpc_server * server, - char const * mount_point, - char const * protocol_name); + char const * mount_point); extern void wf_impl_session_dispose( struct wf_impl_session * session); @@ -57,6 +53,10 @@ extern bool wf_impl_session_authenticate( struct wf_impl_session * session, struct wf_credentials * creds); +extern bool wf_impl_session_add_filesystem( + struct wf_impl_session * session, + char const * name); + extern void wf_impl_session_receive( struct wf_impl_session * session, char const * data, @@ -65,6 +65,15 @@ extern void wf_impl_session_receive( extern void wf_impl_session_onwritable( struct wf_impl_session * session); +extern bool wf_impl_session_contains_wsi( + struct wf_dlist_item * item, + void * user_data); + +extern void wf_impl_session_process_filesystem_request( + struct wf_impl_session * session, + struct lws * wsi); + + #ifdef __cplusplus } #endif diff --git a/lib/webfuse/adapter/impl/session_manager.c b/lib/webfuse/adapter/impl/session_manager.c index 91300bd..09a3a21 100644 --- a/lib/webfuse/adapter/impl/session_manager.c +++ b/lib/webfuse/adapter/impl/session_manager.c @@ -33,11 +33,10 @@ struct wf_impl_session * wf_impl_session_manager_add( struct wf_impl_authenticators * authenticators, struct wf_impl_timeout_manager * timeout_manager, struct wf_impl_jsonrpc_server * server, - char const * mount_point, - char const * protocol_name) + char const * mount_point) { struct wf_impl_session * session = wf_impl_session_create( - wsi, authenticators, timeout_manager, server, mount_point, protocol_name); + wsi, authenticators, timeout_manager, server, mount_point); if (NULL != session) { wf_dlist_prepend(&manager->sessions, &session->item); @@ -46,23 +45,13 @@ struct wf_impl_session * wf_impl_session_manager_add( return session; } -static bool wf_impl_session_manager_get_predicate( - struct wf_dlist_item * item, - void * user_data) -{ - struct lws * wsi = user_data; - struct wf_impl_session * session = WF_CONTAINER_OF(item, struct wf_impl_session, item); - - return ((wsi == session->wsi) || (wsi == session->wsi_fuse)); -} - struct wf_impl_session * wf_impl_session_manager_get( struct wf_impl_session_manager * manager, struct lws * wsi) { struct wf_impl_session * session = NULL; struct wf_dlist_item * item = wf_dlist_find_first( - &manager->sessions, &wf_impl_session_manager_get_predicate, wsi); + &manager->sessions, &wf_impl_session_contains_wsi, wsi); if (NULL != item) { session = WF_CONTAINER_OF(item, struct wf_impl_session, item); diff --git a/lib/webfuse/adapter/impl/session_manager.h b/lib/webfuse/adapter/impl/session_manager.h index fa0badd..10ac789 100644 --- a/lib/webfuse/adapter/impl/session_manager.h +++ b/lib/webfuse/adapter/impl/session_manager.h @@ -35,8 +35,7 @@ extern struct wf_impl_session * wf_impl_session_manager_add( struct wf_impl_authenticators * authenticators, struct wf_impl_timeout_manager * timeout_manager, struct wf_impl_jsonrpc_server * server, - char const * mount_point, - char const * protocol_name); + char const * mount_point); extern struct wf_impl_session * wf_impl_session_manager_get( struct wf_impl_session_manager * manager,