1
0
mirror of https://github.com/falk-werner/webfuse-provider synced 2024-10-27 20:44:10 +00:00

feat(authentication): provide an authentication mechanism (#19)

* moves server into session

* renames jsonrpc server to jsonrpc proxy

* moves server into session

* renames jsonrpc server to jsonrpc proxy

* adds json rpc server

* removes obsolete proxy from protocol

* changes interface of jsonrpc_proxy_onresult to accept previously parsed messages

* adds infrastructure to process incoming requests; fixes invalid read of ill formatted responses

* adds description of authentication request

* adds authentication request

* adds userdb for authentication purposes

* removes debug code: console.log()

* fixes cmake build error (missing openssl symbols)

* fixes typo

* replaces ASCII art by UML diagram

* renames BAD_NOACCESS to BAD_ACCESS_DENIED

* fixes style

* adds docu of authentication

* ignored false positives of flawfinder

* fixes style issues

* fixes javascript style issues
This commit is contained in:
Falk Werner 2019-04-01 22:15:12 +02:00 committed by nosamad
parent 1d413456a2
commit 87f34fa768
42 changed files with 954 additions and 481 deletions

View File

@ -74,6 +74,7 @@ add_library(webfuse-adapter-static STATIC
lib/webfuse/adapter/impl/authenticator.c
lib/webfuse/adapter/impl/authenticators.c
lib/webfuse/adapter/impl/credentials.c
lib/webfuse/adapter/impl/operations.c
lib/webfuse/adapter/impl/time/timepoint.c
lib/webfuse/adapter/impl/time/timer.c
lib/webfuse/adapter/impl/time/timeout_manager.c
@ -83,6 +84,7 @@ add_library(webfuse-adapter-static STATIC
lib/webfuse/adapter/impl/operation/open.c
lib/webfuse/adapter/impl/operation/close.c
lib/webfuse/adapter/impl/operation/read.c
lib/webfuse/adapter/impl/jsonrpc/proxy.c
lib/webfuse/adapter/impl/jsonrpc/server.c
lib/webfuse/adapter/impl/jsonrpc/method.c
lib/webfuse/adapter/impl/jsonrpc/request.c
@ -185,6 +187,8 @@ install(FILES "${PROJECT_BINARY_DIR}/libwebfuse-provider.pc" DESTINATION lib${LI
# examples
pkg_check_modules(OPENSSL REQUIRED openssl)
if(NOT WITHOUT_EXAMPLE)
# libuserdb
@ -211,9 +215,9 @@ add_executable(webfused
example/daemon/main.c
)
target_link_libraries(webfused PUBLIC webfuse-adapter ${EXTRA_LIBS})
target_link_libraries(webfused PUBLIC webfuse-adapter userdb ${OPENSSL_LIBRARIES} ${EXTRA_LIBS})
target_include_directories(webfused PUBLIC ${EXTRA_INCLUDE_DIRS})
target_compile_options(webfused PUBLIC ${EXTRA_CFLAGS})
target_compile_options(webfused PUBLIC ${C_WARNINGS} ${OPENSSL_CFLAGS_OTHER} ${EXTRA_CFLAGS})
# provider
@ -229,9 +233,6 @@ target_compile_options(webfuse-provider-app PUBLIC ${EXTRA_CFLAGS})
# webfuse-passwd
pkg_check_modules(OPENSSL REQUIRED openssl)
add_executable(webfuse-passwd
example/passwd/main.c
)

104
README.md
View File

@ -31,36 +31,9 @@ To avoid Steps 1 and 2, it would be great to keep the update file entirely in we
webfuse solves this problem by using the [WebSocket](https://en.wikipedia.org/wiki/WebSocket) protocol. The emdedded device runs a service, known as webfuse adapter, awaiting incoming connections, e.g. from a web browser. The browser acts as a file system provider, providing the update file to the device.
## Concecpt
## Concept
+---------------------+ +-------------+ +------+
| Filesystem Provider | | webfuse | | user |
| (e.g. Webbrowser) | | daemon | | |
+----------+----------+ +------+------+ +---+--+
| | |
| +-+-+ |
| | +--+ |
| | | | fuse_mount |
| | +<-+ |
| | | |
| | +--+ |
| | | | start ws |
| | +<-+ |
| +-+-+ |
| | |
+-+-+ connect +-+-+ |
| |--------------->| | |
+-+-+ +-+-+ |
| | |
| +-+-+ ls +-+-+
+-+-+ readdir | |<------------+ |
| |<---------------+ | | |
| | | | | |
| | readdir_resp | | | |
| +--------------->| | [., ..] | |
+-+-+ | +------------>| |
| +-+-+ +-+-+
| | |
![concept](doc/concept.png)
With webfuse it is possible to implement remote filesystems based on websockets.
A reference implementation of such a daemon is provided within the examples. The picture above describes the workflow:
@ -146,7 +119,7 @@ A response is used to answer a prior request. There are two kinds of responses:
| BAD_BUSY | 4 | resource busy |
| BAD_FORMAT | 5 | invalid formt |
| BAD_NOENTRY | 101 | invalid entry |
| BAD_NOACCESS | 102 | access not allowed |
| BAD_ACCESS_DENIED | 102 | access not allowed |
#### Notification
@ -162,7 +135,7 @@ Notfications are used to inform a receiver about something. Unlike requests, not
| method_name | string | name of the method to invoke |
| params | array | method specific parameters |
### Requests
### Requests (Adapter -> Provider)
#### lookup
@ -300,6 +273,73 @@ Read from an open file.
| "identiy" | Use data as is; note that JSON strings are UTF-8 encoded |
| "base64" | data is base64 encoded |
### Requests (Provider -> Adapter)
#### authtenticate
Authenticate the provider.
If authentication is enabled, a provider must be authenticated by the adapter before the adapter will send any messages.
fs provider: {"method": "authenticate", "params": [<type>, <credentials>], "id": <id>}
webfuse daemon: {"result": {}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ------------------------------- |
| type | string | authentication type (see below) |
| credentials | object | credentials to authenticate |
##### authentication types
- **username**: authenticate via username and password
`{"username": <username>, "password": <password>}`
## Authentication
By default, webfuse daemon will redirect each filesystem call to the first connected provider without any authentication.
This might be good for testing purposes or when an external authentication mechanism is used. In some use cases, explicit authentication is needed. Therefore, authentication can be enabled within webfuse daemon.
When authentication is enabled, filesystem calls are only redirected to a connected provider, after `authenticate`
has succeeded.
![authenticate](doc/authenticate.png)
### Enable authentication
Authentication is enabled, if one or more authenticators are registered via `wf_server_config`.
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
return ((NULL != username) && (0 == strcmp(username, "bob")) &&
(NULL != password) && (0 == strcmp(password, "???")));
}
wf_server_config * config = wf_server_config_create();
wf_server_config_add_authenticator(config, "username", &authenticate, NULL);
wf_server * server = wf_server_create(config);
//...
### Authenticator types and credentidals
Each authenticator is identified by a user defined string, called `type`. The type is provided by the `authenticate` request, so you can define different authenticators for different authentication types, e.g. username, certificate, token.
Actually, only one type is used: **username**
**It is strongly recommended to prefix custom authenticator types with an underscore (`_`) to avoid name clashes.**
The `wf_credentials`struct represents a map to access credentials as key-value pairs, where both, key and value, are of type string.
#### username
The authenticator type **username** is used to authenticate via username and password. Valid credentials should contain two keys.
- **username** refers to the name of the user
- **password** refers to the password of the user
**Note** that no further encryption is done, so this authenticator type should not be used over unencrypted websocket connections.
## Build and run
To install dependencies, see below.
@ -318,7 +358,7 @@ By default, unit tests and example application are enabled. You can disable them
- **WITHOUT_TESTS**: disable tests
`cmake -DWITHOUT_TESTS=ON ..`
- **WITHOUT_EXAMPLE**: disable example
- **WITHOUT_EXAMPLE**: disable example
`cmake -DWITHOUD_EXAMPLE=ON ..`
## Dependencies

BIN
doc/authenticate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

28
doc/authenticate.uml Normal file
View File

@ -0,0 +1,28 @@
@startuml
participant "Filesystem Provider\n(e.g. Webbrowser)" as provider
participant "webfuse\ndaemon" as daemon
actor "user" as user
group directory listing fails without authentication
user -> daemon : ls
daemon -> daemon : is_authenticated
daemon -->x user : error: no entry
end
group authenticate
provider -> daemon: authenticate(type, credentials)
daemon -> daemon: get_authenticator(type)
daemon -> daemon: check(credentials)
daemon --> provider: result
end
group directory listing succeeds after authentication
user -> daemon : ls
daemon -> daemon : is_authenticated
daemon -> provider : readdir
provider --> daemon : readdir_resp
daemon --> user : [., ..]
end
@enduml

BIN
doc/concept.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

30
doc/concept.uml Normal file
View File

@ -0,0 +1,30 @@
@startuml
participant "Filesystem Provider\n(e.g. Webbrowser)" as provider
participant "webfuse\ndaemon" as daemon
actor "user" as user
group startup
daemon -> daemon : fuse_mount
daemon -> daemon : start ws
end
...
group connect
provider -> daemon : connect
opt authentication
provider -> daemon: authenticate
daemon -> daemon: check credentials
daemon --> provider: okay
end
end
...
group directory listing
user -> daemon : ls
daemon -> provider : readdir
provider --> daemon : readdir_resp
daemon --> user : [., ..]
end
...
@enduml

View File

@ -7,9 +7,9 @@
#include <unistd.h>
#include <getopt.h>
#include <jansson.h>
#include <webfuse_adapter.h>
#include <userdb.h>
struct args
@ -50,24 +50,16 @@ static bool authenticate(struct wf_credentials * creds, void * user_data)
char const * password = wf_credentials_get(creds, "password");
if ((NULL != username) && (NULL != password))
{
json_t * passwd = json_load_file(args->passwd_path, 0, NULL);
if (NULL != passwd)
struct userdb * db = userdb_create("<pepper>");
result = userdb_load(db, args->passwd_path);
if (result)
{
json_t * user = json_object_get(passwd, username);
if (json_is_object(user))
{
json_t * password_holder = json_object_get(user, "password");
if (json_is_string(password_holder))
{
result = (0 == strcmp(password, json_string_value(password_holder)));
}
}
json_decref(passwd);
result = userdb_check(db, username, password);
userdb_dispose(db);
}
}
return result;
return result;
}
static int parse_arguments(int argc, char * argv[], struct args * args)

View File

@ -6,20 +6,51 @@ export class ConnectionView {
this.element = document.createElement("div");
const connectBox = document.createElement("div");
this.element.appendChild(connectBox);
const urlLabel = document.createElement("span");
urlLabel.textContent = "URL:";
this.element.appendChild(urlLabel);
connectBox.appendChild(urlLabel);
this.urlTextbox = document.createElement("input");
this.urlTextbox.type = "text";
this.urlTextbox.value = window.location.href.replace(/^http/, "ws");
this.element.appendChild(this.urlTextbox);
connectBox.appendChild(this.urlTextbox);
this.connectButton = document.createElement("input");
this.connectButton.type = "button";
this.connectButton.value = "connect";
this.connectButton.addEventListener("click", () => { this._onConnectButtonClicked(); });
this.element.appendChild(this.connectButton);
connectBox.appendChild(this.connectButton);
const authenticateBox = document.createElement("div");
this.element.appendChild(authenticateBox);
const usernameLabel = document.createElement("span");
usernameLabel.textContent = "user:";
authenticateBox.appendChild(usernameLabel);
this.usernameTextbox = document.createElement("input");
this.usernameTextbox.type = "text";
this.usernameTextbox.value = "bob";
authenticateBox.appendChild(this.usernameTextbox);
const passwordLabel = document.createElement("span");
passwordLabel.textContent = "user:";
authenticateBox.appendChild(passwordLabel);
this.passwordTextbox = document.createElement("input");
this.passwordTextbox.type = "password";
this.passwordTextbox.value = "secret";
authenticateBox.appendChild(this.passwordTextbox);
this.authenticateButton = document.createElement("input");
this.authenticateButton.type = "button";
this.authenticateButton.value = "authenticate";
this.authenticateButton.addEventListener("click", () => { this._onAuthenticateButtonClicked(); });
authenticateBox.appendChild(this.authenticateButton);
}
_onConnectButtonClicked() {
@ -32,6 +63,15 @@ export class ConnectionView {
}
}
_onAuthenticateButtonClicked() {
if (this._client.isConnected()) {
const username = this.usernameTextbox.value;
const password = this.passwordTextbox.value;
this._client.authenticate("username", { username, password });
}
}
_onConnectionOpened() {
this.connectButton.value = "disconnect";
}

View File

@ -24,6 +24,16 @@ export class Client {
};
}
authenticate(type, credentials) {
const request = {
"method": "authenticate",
"params": [type, credentials],
"id": 42
};
this._ws.send(JSON.stringify(request));
}
disconnect() {
if (this._ws) {
this._ws.close();

View File

@ -127,9 +127,9 @@ static char * compute_hash(
{
EVP_MD_CTX * context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, salt, strlen(salt));
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper));
EVP_DigestUpdate(context, password, strlen(password)); /* Flawfinder: ignore */
EVP_DigestUpdate(context, salt, strlen(salt)); /* Flawfinder: ignore */
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper)); /* Flawfinder: ignore */
EVP_DigestFinal_ex(context, hash, &hash_size);
EVP_MD_CTX_free(context);

View File

@ -268,7 +268,7 @@ static void fs_open(
}
else
{
wfp_respond_error(request, WF_BAD_NOACCESS);
wfp_respond_error(request, WF_BAD_ACCESS_DENIED);
}
}
else

View File

@ -10,7 +10,7 @@
#define WF_BAD_FORMAT 5
#define WF_BAD_NOENTRY 101
#define WF_BAD_NOACCESS 102
#define WF_BAD_ACCESS_DENIED 102
typedef int wf_status;

View File

@ -1,7 +1,7 @@
#include "webfuse/adapter/impl/filesystem.h"
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
@ -19,7 +19,7 @@ static struct fuse_lowlevel_ops const filesystem_operations =
bool wf_impl_filesystem_init(
struct wf_impl_filesystem * filesystem,
struct wf_impl_jsonrpc_server * rpc,
struct wf_impl_session_manager * session_manager,
char * mount_point)
{
bool result = false;
@ -29,7 +29,7 @@ bool wf_impl_filesystem_init(
filesystem->args.argv = argv;
filesystem->args.allocated = 0;
filesystem->user_data.rpc = rpc;
filesystem->user_data.session_manager = session_manager;
filesystem->user_data.timeout = 1.0;
memset(&filesystem->buffer, 0, sizeof(struct fuse_buf));

View File

@ -13,7 +13,7 @@ extern "C"
{
#endif
struct wf_impl_jsonrpc_server;
struct wf_impl_session_manager;
struct wf_impl_filesystem
{
@ -25,7 +25,7 @@ struct wf_impl_filesystem
extern bool wf_impl_filesystem_init(
struct wf_impl_filesystem * filesystem,
struct wf_impl_jsonrpc_server * rpc,
struct wf_impl_session_manager * session_manager,
char * mount_point);
extern void wf_impl_filesystem_cleanup(

View File

@ -1,10 +1,9 @@
#include "webfuse/adapter/impl/jsonrpc/method_intern.h"
#include "webfuse/adapter/impl/jsonrpc/method.h"
#include <stdlib.h>
#include <string.h>
struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
char const * name,
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data)
{
@ -12,7 +11,7 @@ struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
if (NULL != method)
{
method->next = NULL;
method->name = strdup(name);
method->name = strdup(method_name);
method->invoke = invoke;
method->user_data = user_data;
}

View File

@ -1,31 +1,40 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_METHOD_H
#define WF_ADAPTER_IMPL_JSONRPC_METHOD_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef bool wf_impl_jsonrpc_method_invoke_fn(
void * user_data,
struct json_t const * method_call);
struct wf_impl_jsonrpc_request;
typedef void wf_impl_jsonrpc_method_finished_fn(
void * user_data,
wf_status status,
struct json_t const * result);
typedef void wf_impl_jsonrpc_method_invoke_fn(
struct wf_impl_jsonrpc_request * request,
char const * method_name,
json_t * params,
void * user_data);
struct wf_impl_jsonrpc_method
{
struct wf_impl_jsonrpc_method * next;
char * name;
wf_impl_jsonrpc_method_invoke_fn * invoke;
void * user_data;
};
extern struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data);
extern void wf_impl_jsonrpc_method_dispose(
struct wf_impl_jsonrpc_method * method);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,31 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_METHOD_INTERN_H
#define WF_ADAPTER_IMPL_JSONRPC_METHOD_INTERN_H
#include "webfuse/adapter/impl/jsonrpc/method.h"
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_jsonrpc_method
{
struct wf_impl_jsonrpc_method * next;
char * name;
wf_impl_jsonrpc_method_invoke_fn * invoke;
void * user_data;
};
extern struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
char const * name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data);
extern void wf_impl_jsonrpc_method_dispose(
struct wf_impl_jsonrpc_method * method);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,181 @@
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include <string.h>
#include "webfuse/adapter/impl/jsonrpc/response.h"
#define WF_DEFAULT_TIMEOUT (10 * 1000)
static void wf_impl_jsonrpc_proxy_timeout(
struct wf_impl_timer * timer)
{
struct wf_impl_jsonrpc_proxy * proxy = timer->user_data;
if (proxy->request.is_pending)
{
wf_impl_jsonrpc_proxy_finished_fn * finished = proxy->request.finished;
void * user_data = proxy->request.user_data;
proxy->request.is_pending = false;
proxy->request.id = 0;
proxy->request.user_data = NULL;
proxy->request.finished = NULL;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, WF_BAD_TIMEOUT, NULL);
}
}
static json_t * wf_impl_jsonrpc_request_create(
char const * method,
int id,
char const * param_info,
va_list args)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string(method));
json_t * params = json_array();
for (char const * param_type = param_info; '\0' != *param_type; param_type++)
{
switch(*param_type)
{
case 's':
{
char const * const value = va_arg(args, char const *);
json_array_append_new(params, json_string(value));
}
break;
case 'i':
{
int const value = va_arg(args, int);
json_array_append_new(params, json_integer(value));
}
break;
default:
fprintf(stderr, "fatal: unknown param_type '%c'\n", *param_type);
exit(EXIT_FAILURE);
break;
}
}
json_object_set_new(request, "params", params);
if (0 != id)
{
json_object_set_new(request, "id", json_integer(id));
}
return request;
}
void wf_impl_jsonrpc_proxy_init(
struct wf_impl_jsonrpc_proxy * proxy,
struct wf_impl_timeout_manager * timeout_manager,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
proxy->send = send;
proxy->user_data = user_data;
proxy->request.is_pending = false;
wf_impl_timer_init(&proxy->request.timer, timeout_manager);
}
void wf_impl_jsonrpc_proxy_cleanup(
struct wf_impl_jsonrpc_proxy * proxy)
{
wf_impl_timer_cleanup(&proxy->request.timer);
if (proxy->request.is_pending)
{
proxy->request.finished(proxy->request.user_data, WF_BAD, NULL);
proxy->request.is_pending = false;
}
}
void wf_impl_jsonrpc_proxy_invoke(
struct wf_impl_jsonrpc_proxy * proxy,
wf_impl_jsonrpc_proxy_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
)
{
if (!proxy->request.is_pending)
{
proxy->request.is_pending = true;
proxy->request.finished = finished;
proxy->request.user_data = user_data;
proxy->request.id = 42;
wf_impl_timer_start(&proxy->request.timer, wf_impl_timepoint_in_msec(WF_DEFAULT_TIMEOUT),
&wf_impl_jsonrpc_proxy_timeout, proxy);
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, proxy->request.id, param_info, args);
va_end(args);
if (NULL != request)
{
if (!proxy->send(request, proxy->user_data))
{
proxy->request.is_pending = false;
proxy->request.finished = NULL;
proxy->request.user_data = NULL;
proxy->request.id = 0;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, WF_BAD, NULL);
}
json_decref(request);
}
}
else
{
finished(user_data, WF_BAD_BUSY, NULL);
}
}
extern void wf_impl_jsonrpc_proxy_notify(
struct wf_impl_jsonrpc_proxy * proxy,
char const * method_name,
char const * param_info,
...
)
{
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, 0, param_info, args);
va_end(args);
if (NULL != request)
{
proxy->send(request, proxy->user_data);
json_decref(request);
}
}
void wf_impl_jsonrpc_proxy_onresult(
struct wf_impl_jsonrpc_proxy * proxy,
json_t * message)
{
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message);
if ((proxy->request.is_pending) && (response.id == proxy->request.id))
{
wf_impl_jsonrpc_proxy_finished_fn * finished = proxy->request.finished;
void * user_data = proxy->request.user_data;
proxy->request.is_pending = false;
proxy->request.id = 0;
proxy->request.user_data = NULL;
proxy->request.finished = NULL;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, response.status, response.result);
}
wf_impl_jsonrpc_response_cleanup(&response);
}

View File

@ -0,0 +1,80 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_PROXY_H
#define WF_ADAPTER_IMPL_JSONRPC_PROXY_H
#ifndef __cplusplus
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#else
#include <cstdarg>
#include <cstddef>
using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
#include "webfuse/adapter/impl/time/timer.h"
#include "webfuse/core/status.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void wf_impl_jsonrpc_proxy_finished_fn(
void * user_data,
wf_status status,
struct json_t const * result);
struct wf_impl_jsonrpc_request
{
bool is_pending;
wf_impl_jsonrpc_proxy_finished_fn * finished;
void * user_data;
int id;
struct wf_impl_timer timer;
};
struct wf_impl_jsonrpc_proxy
{
struct wf_impl_jsonrpc_request request;
wf_impl_jsonrpc_send_fn * send;
void * user_data;
};
extern void wf_impl_jsonrpc_proxy_init(
struct wf_impl_jsonrpc_proxy * proxy,
struct wf_impl_timeout_manager * manager,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
extern void wf_impl_jsonrpc_proxy_cleanup(
struct wf_impl_jsonrpc_proxy * proxy);
extern void wf_impl_jsonrpc_proxy_invoke(
struct wf_impl_jsonrpc_proxy * proxy,
wf_impl_jsonrpc_proxy_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_proxy_notify(
struct wf_impl_jsonrpc_proxy * proxy,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_proxy_onresult(
struct wf_impl_jsonrpc_proxy * proxy,
json_t * message);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,44 +1,82 @@
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/core/status_intern.h"
#include <stdlib.h>
json_t * wf_impl_jsonrpc_request_create(
char const * method,
int id,
char const * param_info,
va_list args)
struct wf_impl_jsonrpc_request
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string(method));
json_t * params = json_array();
for (char const * param_type = param_info; '\0' != *param_type; param_type++)
{
switch(*param_type)
{
case 's':
{
char const * const value = va_arg(args, char const *);
json_array_append_new(params, json_string(value));
}
break;
case 'i':
{
int const value = va_arg(args, int);
json_array_append_new(params, json_integer(value));
}
break;
default:
fprintf(stderr, "fatal: unknown param_type '%c'\n", *param_type);
exit(EXIT_FAILURE);
break;
}
}
int id;
wf_impl_jsonrpc_send_fn * send;
void * user_data;
};
json_object_set_new(request, "params", params);
if (0 != id)
{
json_object_set_new(request, "id", json_integer(id));
}
return request;
bool wf_impl_jsonrpc_is_request(
json_t * message)
{
json_t * id = json_object_get(message, "id");
json_t * method = json_object_get(message, "method");
json_t * params = json_object_get(message, "params");
return (json_is_integer(id) && json_is_string(method) &&
(json_is_array(params) || json_is_object(params)));
}
struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create(
int id,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
struct wf_impl_jsonrpc_request * request = malloc(sizeof(struct wf_impl_jsonrpc_request));
if (NULL != request)
{
request->id = id;
request->send = send;
request->user_data = user_data;
}
return request;
}
void wf_impl_jsonrpc_request_dispose(
struct wf_impl_jsonrpc_request * request)
{
free(request);
}
void * wf_impl_jsonrpc_request_get_userdata(
struct wf_impl_jsonrpc_request * request)
{
return request->user_data;
}
void wf_impl_jsonrpc_respond(
struct wf_impl_jsonrpc_request * request,
json_t * result)
{
json_t * response = json_object();
json_object_set_new(response, "result", result);
json_object_set_new(response, "id", json_integer(request->id));
request->send(response, request->user_data);
json_decref(response);
wf_impl_jsonrpc_request_dispose(request);
}
void wf_impl_jsonrpc_respond_error(
struct wf_impl_jsonrpc_request * request,
wf_status status)
{
json_t * err = json_object();
json_object_set_new(err, "code", json_integer(status));
json_object_set_new(err, "message", json_string(wf_status_tostring(status)));
json_t * response = json_object();
json_object_set_new(response, "error", err);
json_object_set_new(response, "id", json_integer(request->id));
request->send(response, request->user_data);
json_decref(response);
wf_impl_jsonrpc_request_dispose(request);
}

View File

@ -12,17 +12,38 @@ using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern json_t * wf_impl_jsonrpc_request_create(
char const * method,
int id,
char const * param_info,
va_list args);
struct wf_impl_jsonrpc_request;
extern bool wf_impl_jsonrpc_is_request(
json_t * message);
extern struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create(
int id,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
extern void wf_impl_jsonrpc_request_dispose(
struct wf_impl_jsonrpc_request * request);
extern void * wf_impl_jsonrpc_request_get_userdata(
struct wf_impl_jsonrpc_request * request);
extern void wf_impl_jsonrpc_respond(
struct wf_impl_jsonrpc_request * request,
json_t * result);
extern void wf_impl_jsonrpc_respond_error(
struct wf_impl_jsonrpc_request * request,
wf_status status);
#ifdef __cplusplus
}

View File

@ -1,26 +1,29 @@
#include "webfuse/adapter/impl/jsonrpc/response.h"
extern bool wf_impl_jsonrpc_is_response(
json_t * message)
{
json_t * id = json_object_get(message, "id");
json_t * err = json_object_get(message, "error");
json_t * result = json_object_get(message, "result");
return (json_is_integer(id) &&
(json_is_object(err) || (NULL != result)));
}
void wf_impl_jsonrpc_response_init(
struct wf_impl_jsonrpc_response * result,
char const * buffer,
size_t length)
json_t * response)
{
result->status = WF_BAD;
result->id = -1;
result->result = NULL;
json_t * response = json_loadb(buffer, length, 0, NULL);
if (NULL == response)
{
result->status = WF_BAD_FORMAT;
return;
}
json_t * id_holder = json_object_get(response, "id");
if ((NULL == id_holder) || (!json_is_integer(id_holder)))
{
result->status = WF_BAD_FORMAT;
json_decref(response);
return;
}
@ -45,8 +48,6 @@ void wf_impl_jsonrpc_response_init(
}
}
}
json_decref(response);
}
void wf_impl_jsonrpc_response_cleanup(

View File

@ -2,6 +2,7 @@
#define WF_ADAPTER_IMPL_JSONRPC_RESPONSE_H
#ifndef __cplusplus
#include <stdbool.h>
#include <stddef.h>
#else
#include <cstddef>
@ -22,10 +23,12 @@ struct wf_impl_jsonrpc_response
json_t * result;
};
extern bool wf_impl_jsonrpc_is_response(
json_t * message);
extern void wf_impl_jsonrpc_response_init(
struct wf_impl_jsonrpc_response * response,
char const * buffer,
size_t buffer_length);
json_t * message);
extern void wf_impl_jsonrpc_response_cleanup(
struct wf_impl_jsonrpc_response * response);

View File

@ -0,0 +1,23 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_SEND_FN_H
#define WF_ADAPTER_IMPL_JSONRPC_SEND_FN_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef bool wf_impl_jsonrpc_send_fn(
json_t * request,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,186 +1,95 @@
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/method.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/core/util.h"
#include <string.h>
#include "webfuse/adapter/impl/jsonrpc/method_intern.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/adapter/impl/jsonrpc/response.h"
#define WF_DEFAULT_TIMEOUT (10 * 1000)
static struct wf_impl_jsonrpc_method const * wf_impl_jsonrpc_server_getmethod(
struct wf_impl_jsonrpc_server * server,
char const * name)
{
struct wf_impl_jsonrpc_method * method = server->methods;
while ((NULL != method) && (0 == strcmp(name, method->name)))
{
method = method->next;
}
return method;
}
static void wf_impl_jsonrpc_server_timeout(
struct wf_impl_timer * timer)
{
struct wf_impl_jsonrpc_server * server = timer->user_data;
if (server->request.is_pending)
{
wf_impl_jsonrpc_method_finished_fn * finished = server->request.finished;
void * user_data = server->request.user_data;
server->request.is_pending = false;
server->request.id = 0;
server->request.user_data = NULL;
server->request.finished = NULL;
wf_impl_timer_cancel(&server->request.timer);
finished(user_data, WF_BAD_TIMEOUT, NULL);
}
}
void wf_impl_jsonrpc_server_init(
struct wf_impl_jsonrpc_server * server,
struct wf_impl_timeout_manager * timeout_manager)
struct wf_impl_jsonrpc_server * server)
{
server->methods = NULL;
server->request.is_pending = false;
wf_impl_timer_init(&server->request.timer, timeout_manager);
}
void wf_impl_jsonrpc_server_cleanup(
struct wf_impl_jsonrpc_server * server)
{
wf_impl_timer_cleanup(&server->request.timer);
if (server->request.is_pending)
struct wf_impl_jsonrpc_method * current = server->methods;
while (NULL != current)
{
server->request.finished(server->request.user_data, WF_BAD, NULL);
server->request.is_pending = false;
}
struct wf_impl_jsonrpc_method * method = server->methods;
while (NULL != method)
{
struct wf_impl_jsonrpc_method * next = method->next;
method->next = NULL;
wf_impl_jsonrpc_method_dispose(method);
method = next;
struct wf_impl_jsonrpc_method * next = current->next;
wf_impl_jsonrpc_method_dispose(current);
current = next;
}
server->methods = NULL;
}
void wf_impl_jsonrpc_server_add(
struct wf_impl_jsonrpc_server * server,
char const * name,
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data)
{
struct wf_impl_jsonrpc_method * method = wf_impl_jsonrpc_method_create(name, invoke, user_data);
struct wf_impl_jsonrpc_method * method = wf_impl_jsonrpc_method_create(method_name, invoke, user_data);
method->next = server->methods;
server->methods = method;
}
void wf_impl_jsonrpc_server_invoke(
struct wf_impl_jsonrpc_server * server,
wf_impl_jsonrpc_method_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
)
static void wf_impl_jsonrpc_server_invalid_method_invoke(
struct wf_impl_jsonrpc_request * request,
char const * WF_UNUSED_PARAM(method_name),
json_t * WF_UNUSED_PARAM(params),
void * WF_UNUSED_PARAM(user_data))
{
if (!server->request.is_pending)
{
struct wf_impl_jsonrpc_method const * method = wf_impl_jsonrpc_server_getmethod(server, method_name);
if (NULL != method)
{
server->request.is_pending = true;
server->request.finished = finished;
server->request.user_data = user_data;
server->request.id = 42;
wf_impl_timer_start(&server->request.timer, wf_impl_timepoint_in_msec(WF_DEFAULT_TIMEOUT),
&wf_impl_jsonrpc_server_timeout, server);
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, server->request.id, param_info, args);
va_end(args);
if (NULL != request)
{
if (!method->invoke(method->user_data, request))
{
server->request.is_pending = false;
server->request.finished = NULL;
server->request.user_data = NULL;
server->request.id = 0;
wf_impl_timer_cancel(&server->request.timer);
finished(user_data, WF_BAD, NULL);
}
json_decref(request);
}
}
else
{
finished(user_data, WF_BAD_NOTIMPLEMENTED, NULL);
}
}
else
{
finished(user_data, WF_BAD_BUSY, NULL);
}
wf_impl_jsonrpc_respond_error(request, WF_BAD_NOTIMPLEMENTED);
}
extern void wf_impl_jsonrpc_server_notify(
struct wf_impl_jsonrpc_server * server,
char const * method_name,
char const * param_info,
...
)
static struct wf_impl_jsonrpc_method const wf_impl_jsonrpc_server_invalid_method =
{
struct wf_impl_jsonrpc_method const * method = wf_impl_jsonrpc_server_getmethod(server, method_name);
if (NULL != method)
{
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, 0, param_info, args);
va_end(args);
if (NULL != request)
{
method->invoke(method->user_data, request);
json_decref(request);
}
}
.next = NULL,
.name = "<invalid>",
.invoke = &wf_impl_jsonrpc_server_invalid_method_invoke,
.user_data = NULL
};
}
void wf_impl_jsonrpc_server_onresult(
static struct wf_impl_jsonrpc_method const * wf_impl_jsonrpc_server_get_method(
struct wf_impl_jsonrpc_server * server,
char const * message,
size_t length)
char const * method_name)
{
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message, length);
if ((server->request.is_pending) && (response.id == server->request.id))
struct wf_impl_jsonrpc_method const * current = server->methods;
while (NULL != current)
{
wf_impl_jsonrpc_method_finished_fn * finished = server->request.finished;
void * user_data = server->request.user_data;
if (0 == strcmp(method_name, current->name))
{
return current;
}
server->request.is_pending = false;
server->request.id = 0;
server->request.user_data = NULL;
server->request.finished = NULL;
wf_impl_timer_cancel(&server->request.timer);
finished(user_data, response.status, response.result);
current = current->next;
}
wf_impl_jsonrpc_response_cleanup(&response);
return &wf_impl_jsonrpc_server_invalid_method;
}
void wf_impl_jsonrpc_server_process(
struct wf_impl_jsonrpc_server * server,
json_t * request_data,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
json_t * method_holder = json_object_get(request_data, "method");
json_t * params = json_object_get(request_data, "params");
json_t * id_holder = json_object_get(request_data, "id");
if (json_is_string(method_holder) &&
(json_is_array(params) || (json_is_object(params))) &&
json_is_integer(id_holder))
{
char const * method_name = json_string_value(method_holder);
int id = json_integer_value(id_holder);
struct wf_impl_jsonrpc_request * request = wf_impl_jsonrpc_request_create(id, send, user_data);
struct wf_impl_jsonrpc_method const * method = wf_impl_jsonrpc_server_get_method(server, method_name);
method->invoke(request, method_name, params, method->user_data);
}
}

View File

@ -3,75 +3,46 @@
#ifndef __cplusplus
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#else
#include <cstdarg>
#include <cstddef>
using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#include "webfuse/adapter/impl/jsonrpc/method.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
#include "webfuse/adapter/impl/time/timer.h"
#ifdef __cplusplus
extern "C" {
#endif
struct wf_impl_jsonrpc_request
extern "C"
{
bool is_pending;
wf_impl_jsonrpc_method_finished_fn * finished;
void * user_data;
int id;
struct wf_impl_timer timer;
};
#endif
struct wf_impl_jsonrpc_server
{
struct wf_impl_jsonrpc_method * methods;
struct wf_impl_jsonrpc_request request;
};
extern void wf_impl_jsonrpc_server_init(
struct wf_impl_jsonrpc_server * server,
struct wf_impl_timeout_manager * manager);
struct wf_impl_jsonrpc_server * server);
extern void wf_impl_jsonrpc_server_cleanup(
struct wf_impl_jsonrpc_server * server);
extern void wf_impl_jsonrpc_server_add(
struct wf_impl_jsonrpc_server * server,
char const * name,
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data );
void * user_data);
extern void wf_impl_jsonrpc_server_invoke(
struct wf_impl_jsonrpc_server * server,
wf_impl_jsonrpc_method_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_server_notify(
struct wf_impl_jsonrpc_server * server,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_server_onresult(
extern void wf_impl_jsonrpc_server_process(
struct wf_impl_jsonrpc_server * server,
char const * message,
size_t length);
json_t * request,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,7 +4,7 @@
#include <errno.h>
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
void wf_impl_operation_close(
@ -13,9 +13,13 @@ void wf_impl_operation_close(
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, inode);
int handle = (int) (file_info->fh & INT_MAX);
wf_impl_jsonrpc_server_notify(rpc, "close", "iii", inode, handle, file_info->flags);
if (NULL != rpc)
{
int handle = (int) (file_info->fh & INT_MAX);
wf_impl_jsonrpc_proxy_notify(rpc, "close", "iii", inode, handle, file_info->flags);
}
fuse_reply_err(request, 0);
}

View File

@ -7,7 +7,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/util.h"
#include "webfuse/core/util.h"
@ -81,13 +81,20 @@ void wf_impl_operation_getattr (
{
struct fuse_ctx const * context = fuse_req_ctx(request);
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, inode);
struct wf_impl_operation_getattr_context * getattr_context = malloc(sizeof(struct wf_impl_operation_getattr_context));
getattr_context->request = request;
getattr_context->uid = context->uid;
getattr_context->gid = context->gid;
getattr_context->timeout = user_data->timeout;
if (NULL != rpc)
{
struct wf_impl_operation_getattr_context * getattr_context = malloc(sizeof(struct wf_impl_operation_getattr_context));
getattr_context->request = request;
getattr_context->uid = context->uid;
getattr_context->gid = context->gid;
getattr_context->timeout = user_data->timeout;
wf_impl_jsonrpc_server_invoke(rpc, &wf_impl_operation_getattr_finished, getattr_context, "getattr", "i", inode);
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_getattr_finished, getattr_context, "getattr", "i", inode);
}
else
{
fuse_reply_err(request, ENOENT);
}
}

View File

@ -10,7 +10,7 @@
#include <stdlib.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/util.h"
#include "webfuse/core/util.h"
@ -90,13 +90,20 @@ void wf_impl_operation_lookup (
{
struct fuse_ctx const * context = fuse_req_ctx(request);
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, parent);
struct wf_impl_operation_lookup_context * lookup_context = malloc(sizeof(struct wf_impl_operation_lookup_context));
lookup_context->request = request;
lookup_context->uid = context->uid;
lookup_context->gid = context->gid;
lookup_context->timeout = user_data->timeout;
if (NULL != rpc)
{
struct wf_impl_operation_lookup_context * lookup_context = malloc(sizeof(struct wf_impl_operation_lookup_context));
lookup_context->request = request;
lookup_context->uid = context->uid;
lookup_context->gid = context->gid;
lookup_context->timeout = user_data->timeout;
wf_impl_jsonrpc_server_invoke(rpc, &wf_impl_operation_lookup_finished, lookup_context, "lookup", "is", (int) (parent & INT_MAX), name);
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_lookup_finished, lookup_context, "lookup", "is", (int) (parent & INT_MAX), name);
}
else
{
fuse_reply_err(request, ENOENT);
}
}

View File

@ -4,7 +4,7 @@
#include <errno.h>
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
#include "webfuse/core/status.h"
@ -47,7 +47,14 @@ void wf_impl_operation_open(
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, inode);
wf_impl_jsonrpc_server_invoke(rpc, &wf_impl_operation_open_finished, request, "open", "ii", inode, file_info->flags);
if (NULL != rpc)
{
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_open_finished, request, "open", "ii", inode, file_info->flags);
}
else
{
fuse_reply_err(request, ENOENT);
}
}

View File

@ -6,7 +6,7 @@
#include <jansson.h>
#include <libwebsockets.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#define WF_MAX_READ_LENGTH 4096
@ -87,9 +87,16 @@ void wf_impl_operation_read(
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, inode);
int const length = (size <= WF_MAX_READ_LENGTH) ? (int) size : WF_MAX_READ_LENGTH;
int handle = (file_info->fh & INT_MAX);
wf_impl_jsonrpc_server_invoke(rpc, &wf_impl_operation_read_finished, request, "read", "iiii", inode, handle, (int) offset, length);
if (NULL != rpc)
{
int const length = (size <= WF_MAX_READ_LENGTH) ? (int) size : WF_MAX_READ_LENGTH;
int handle = (file_info->fh & INT_MAX);
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_read_finished, request, "read", "iiii", inode, handle, (int) offset, length);
}
else
{
fuse_reply_err(request, ENOENT);
}
}

View File

@ -8,7 +8,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
@ -137,11 +137,19 @@ void wf_impl_operation_readdir (
struct fuse_file_info * WF_UNUSED_PARAM(file_info))
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_server * rpc = user_data->rpc;
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data, inode);
if (NULL != rpc)
{
struct wf_impl_operation_readdir_context * readdir_context = malloc(sizeof(struct wf_impl_operation_readdir_context));
readdir_context->request = request;
readdir_context->size = size;
readdir_context->offset = offset;
wf_impl_jsonrpc_server_invoke(rpc, &wf_impl_operation_readdir_finished, readdir_context, "readdir", "i", inode);
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_readdir_finished, readdir_context, "readdir", "i", inode);
}
else
{
fuse_reply_err(request, ENOENT);
}
}

View File

@ -0,0 +1,20 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/session_manager.h"
#include "webfuse/adapter/impl/session.h"
#include <stddef.h>
struct wf_impl_jsonrpc_proxy * wf_impl_operations_context_get_proxy(
struct wf_impl_operations_context * context,
fuse_ino_t inode)
{
struct wf_impl_jsonrpc_proxy * proxy = NULL;
struct wf_impl_session_manager * session_manger = context->session_manager;
struct wf_impl_session * session = wf_impl_session_manager_get_by_inode(session_manger, inode);
if (NULL != session)
{
proxy = &session->rpc;
}
return proxy;
}

View File

@ -7,11 +7,12 @@
extern "C" {
#endif
struct wf_impl_jsonrpc_server;
struct wf_impl_session_manager;
struct wf_impl_jsonrpc_proxy;
struct wf_impl_operations_context
{
struct wf_impl_jsonrpc_server * rpc;
struct wf_impl_session_manager * session_manager;
double timeout;
};
@ -47,6 +48,10 @@ extern void wf_impl_operation_read(
fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
extern struct wf_impl_jsonrpc_proxy * wf_impl_operations_context_get_proxy(
struct wf_impl_operations_context * context,
fuse_ino_t inode);
#ifdef __cplusplus
}
#endif

View File

@ -7,6 +7,8 @@
#include "webfuse/core/util.h"
#include "webfuse/adapter/impl/filesystem.h"
#include "webfuse/adapter/impl/credentials.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
static int wf_impl_server_protocol_callback(
struct lws * wsi,
@ -38,7 +40,8 @@ static int wf_impl_server_protocol_callback(
&protocol->session_manager,
wsi,
&protocol->authenticators,
&protocol->rpc);
&protocol->timeout_manager,
&protocol->server);
if (NULL != session)
{
@ -70,20 +73,6 @@ static int wf_impl_server_protocol_callback(
return 0;
}
static bool wf_impl_server_protocol_invoke(
void * user_data,
json_t const * request)
{
struct wf_server_protocol * protocol = user_data;
struct wf_impl_session * session = &protocol->session_manager.session;
struct wf_message * message = wf_message_create(request);
bool const result = wf_impl_session_send(session, message);
return result;
}
struct wf_server_protocol * wf_impl_server_protocol_create(
char * mount_point)
{
@ -116,6 +105,41 @@ void wf_impl_server_protocol_init_lws(
lws_protocol->user = protocol;
}
static void wf_impl_server_protocol_authenticate(
struct wf_impl_jsonrpc_request * request,
char const * WF_UNUSED_PARAM(method_name),
json_t * params,
void * WF_UNUSED_PARAM(user_data))
{
bool result = false;
json_t * type_holder = json_array_get(params, 0);
json_t * creds_holder = json_array_get(params, 1);
if (json_is_string(type_holder) && json_is_object(creds_holder))
{
char const * type = json_string_value(type_holder);
struct wf_credentials creds;
wf_impl_credentials_init(&creds, type, creds_holder);
struct wf_impl_session * session = wf_impl_jsonrpc_request_get_userdata(request);
result = wf_impl_session_authenticate(session, &creds);
wf_impl_credentials_cleanup(&creds);
}
if (result)
{
json_t * result = json_object();
wf_impl_jsonrpc_respond(request, result);
}
else
{
wf_impl_jsonrpc_respond_error(request, WF_BAD_ACCESS_DENIED);
}
}
bool wf_impl_server_protocol_init(
struct wf_server_protocol * protocol,
char * mount_point)
@ -124,20 +148,15 @@ bool wf_impl_server_protocol_init(
wf_impl_session_manager_init(&protocol->session_manager);
wf_impl_authenticators_init(&protocol->authenticators);
wf_impl_jsonrpc_server_init(&protocol->rpc, &protocol->timeout_manager);
wf_impl_jsonrpc_server_add(&protocol->rpc, "lookup", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_add(&protocol->rpc, "getattr", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_add(&protocol->rpc, "readdir", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_add(&protocol->rpc, "open", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_add(&protocol->rpc, "close", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_add(&protocol->rpc, "read", &wf_impl_server_protocol_invoke, protocol);
wf_impl_jsonrpc_server_init(&protocol->server);
wf_impl_jsonrpc_server_add(&protocol->server, "authenticate", &wf_impl_server_protocol_authenticate, protocol);
bool const success = wf_impl_filesystem_init(&protocol->filesystem, &protocol->rpc, mount_point);
bool const success = wf_impl_filesystem_init(&protocol->filesystem, &protocol->session_manager, mount_point);
// cleanup on error
if (!success)
{
wf_impl_jsonrpc_server_cleanup(&protocol->rpc);
wf_impl_jsonrpc_server_cleanup(&protocol->server);
wf_impl_authenticators_cleanup(&protocol->authenticators);
wf_impl_timeout_manager_cleanup(&protocol->timeout_manager);
wf_impl_session_manager_cleanup(&protocol->session_manager);
@ -150,7 +169,7 @@ void wf_impl_server_protocol_cleanup(
struct wf_server_protocol * protocol)
{
wf_impl_filesystem_cleanup(&protocol->filesystem);
wf_impl_jsonrpc_server_cleanup(&protocol->rpc);
wf_impl_jsonrpc_server_cleanup(&protocol->server);
wf_impl_timeout_manager_cleanup(&protocol->timeout_manager);
wf_impl_authenticators_cleanup(&protocol->authenticators);
wf_impl_session_manager_cleanup(&protocol->session_manager);

View File

@ -2,10 +2,11 @@
#define WF_ADAPTER_IMPL_SERVER_PROTOCOL_H
#include "webfuse/adapter/impl/filesystem.h"
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
#include "webfuse/adapter/impl/authenticators.h"
#include "webfuse/adapter/impl/session_manager.h"
#include "webfuse/adapter/impl/jsonrpc/server.h"
#ifdef __cplusplus
extern "C"
@ -18,9 +19,9 @@ struct wf_server_protocol
{
struct wf_impl_timeout_manager timeout_manager;
struct wf_impl_filesystem filesystem;
struct wf_impl_jsonrpc_server rpc;
struct wf_impl_authenticators authenticators;
struct wf_impl_session_manager session_manager;
struct wf_impl_jsonrpc_server server;
};
extern bool wf_impl_server_protocol_init(

View File

@ -2,46 +2,21 @@
#include "webfuse/adapter/impl/authenticators.h"
#include "webfuse/core/message_queue.h"
#include "webfuse/core/message.h"
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/adapter/impl/jsonrpc/response.h"
#include <libwebsockets.h>
#include <stddef.h>
void wf_impl_session_init(
struct wf_impl_session * session,
struct lws * wsi,
struct wf_impl_authenticators * authenticators,
struct wf_impl_jsonrpc_server * rpc)
{
session->wsi = wsi;
session->is_authenticated = false;
session->authenticators = authenticators;
session->rpc = rpc;
wf_message_queue_init(&session->queue);
}
void wf_impl_session_cleanup(
struct wf_impl_session * session)
static bool wf_impl_session_send(
json_t * request,
void * user_data)
{
wf_message_queue_cleanup(&session->queue);
session->is_authenticated = false;
session->wsi = NULL;
session->authenticators = NULL;
session->rpc = NULL;
}
struct wf_impl_session * session = user_data;
struct wf_message * message = wf_message_create(request);
void wf_impl_session_authenticate(
struct wf_impl_session * session,
struct wf_credentials * creds)
{
session->is_authenticated = wf_impl_authenticators_authenticate(session->authenticators, creds);
}
bool wf_impl_session_send(
struct wf_impl_session * session,
struct wf_message * message)
{
bool result = (session->is_authenticated) && (NULL != session->wsi);
bool result = (session->is_authenticated || wf_impl_jsonrpc_is_response(request)) && (NULL != session->wsi);
if (result)
{
@ -58,6 +33,41 @@ bool wf_impl_session_send(
return result;
}
void wf_impl_session_init(
struct wf_impl_session * session,
struct lws * wsi,
struct wf_impl_authenticators * authenticators,
struct wf_impl_timeout_manager * timeout_manager,
struct wf_impl_jsonrpc_server * server)
{
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);
}
void wf_impl_session_cleanup(
struct wf_impl_session * session)
{
wf_impl_jsonrpc_proxy_cleanup(&session->rpc);
wf_message_queue_cleanup(&session->queue);
session->is_authenticated = false;
session->wsi = NULL;
session->authenticators = NULL;
session->server = NULL;
}
bool wf_impl_session_authenticate(
struct wf_impl_session * session,
struct wf_credentials * creds)
{
session->is_authenticated = wf_impl_authenticators_authenticate(session->authenticators, creds);
return session->is_authenticated;
}
void wf_impl_session_onwritable(
struct wf_impl_session * session)
{
@ -80,5 +90,19 @@ void wf_impl_session_receive(
char const * data,
size_t length)
{
wf_impl_jsonrpc_server_onresult(session->rpc, data, length);
json_t * message = json_loadb(data, length, 0, NULL);
if (NULL != message)
{
if (wf_impl_jsonrpc_is_response(message))
{
wf_impl_jsonrpc_proxy_onresult(&session->rpc, message);
}
else if (wf_impl_jsonrpc_is_request(message))
{
wf_impl_jsonrpc_server_process(session->server, message, &wf_impl_session_send, session);
}
json_decref(message);
}
}

View File

@ -10,6 +10,8 @@ using std::size_t;
#endif
#include "webfuse/core/message_queue.h"
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/server.h"
#ifdef __cplusplus
extern "C"
@ -20,7 +22,7 @@ struct lws;
struct wf_message;
struct wf_credentials;
struct wf_impl_authenticators;
struct wf_impl_jsonrpc_server;
struct wf_impl_timeout_manager;
struct wf_impl_session
{
@ -28,23 +30,21 @@ struct wf_impl_session
bool is_authenticated;
struct wf_message_queue queue;
struct wf_impl_authenticators * authenticators;
struct wf_impl_jsonrpc_server * rpc;
struct wf_impl_jsonrpc_server * server;
struct wf_impl_jsonrpc_proxy rpc;
};
extern void wf_impl_session_init(
struct wf_impl_session * session,
struct lws * wsi,
struct wf_impl_authenticators * authenticators,
struct wf_impl_jsonrpc_server * rpc);
struct wf_impl_timeout_manager * timeout_manager,
struct wf_impl_jsonrpc_server * server);
extern void wf_impl_session_authenticate(
extern bool wf_impl_session_authenticate(
struct wf_impl_session * session,
struct wf_credentials * creds);
extern bool wf_impl_session_send(
struct wf_impl_session * session,
struct wf_message * message);
extern void wf_impl_session_receive(
struct wf_impl_session * session,
char const * data,

View File

@ -1,10 +1,11 @@
#include "webfuse/adapter/impl/session_manager.h"
#include "webfuse/core/util.h"
#include <stddef.h>
void wf_impl_session_manager_init(
struct wf_impl_session_manager * manager)
{
wf_impl_session_init(&manager->session, NULL, NULL, NULL);
wf_impl_session_init(&manager->session, NULL, NULL, NULL, NULL);
}
void wf_impl_session_manager_cleanup(
@ -17,13 +18,14 @@ struct wf_impl_session * wf_impl_session_manager_add(
struct wf_impl_session_manager * manager,
struct lws * wsi,
struct wf_impl_authenticators * authenticators,
struct wf_impl_jsonrpc_server * rpc)
struct wf_impl_timeout_manager * timeout_manager,
struct wf_impl_jsonrpc_server * server)
{
struct wf_impl_session * session = NULL;
if (NULL == manager->session.wsi)
{
session = &manager->session;
wf_impl_session_init(&manager->session, wsi, authenticators, rpc);
wf_impl_session_init(&manager->session, wsi, authenticators, timeout_manager, server);
}
return session;
@ -42,6 +44,22 @@ struct wf_impl_session * wf_impl_session_manager_get(
return session;
}
struct wf_impl_session * wf_impl_session_manager_get_by_inode(
struct wf_impl_session_manager * manager,
fuse_ino_t WF_UNUSED_PARAM(inode))
{
// ToDo: use inode to determine session manager
struct wf_impl_session * session = NULL;
if (NULL != manager->session.wsi)
{
session = &manager->session;
}
return session;
}
void wf_impl_session_manager_remove(
struct wf_impl_session_manager * manager,
struct lws * wsi)

View File

@ -6,6 +6,7 @@
#endif
#include "webfuse/adapter/impl/session.h"
#include "webfuse/adapter/impl/fuse_wrapper.h"
#ifdef __cplusplus
extern "C"
@ -13,6 +14,8 @@ extern "C"
#endif
struct lws;
struct wf_impl_timeout_manager;
struct wf_impl_jsonrpc_server;
struct wf_impl_session_manager
{
@ -29,12 +32,17 @@ extern struct wf_impl_session * wf_impl_session_manager_add(
struct wf_impl_session_manager * manager,
struct lws * wsi,
struct wf_impl_authenticators * authenticators,
struct wf_impl_jsonrpc_server * rpc);
struct wf_impl_timeout_manager * timeout_manager,
struct wf_impl_jsonrpc_server * server);
extern struct wf_impl_session * wf_impl_session_manager_get(
struct wf_impl_session_manager * manager,
struct lws * wsi);
extern struct wf_impl_session * wf_impl_session_manager_get_by_inode(
struct wf_impl_session_manager * session_manger,
fuse_ino_t inode);
extern void wf_impl_session_manager_remove(
struct wf_impl_session_manager * manager,
struct lws * wsi);

View File

@ -12,7 +12,7 @@
case WF_BAD_BUSY: return -ENOENT;
case WF_BAD_FORMAT: return -ENOENT;
case WF_BAD_NOENTRY: return -ENOENT;
case WF_BAD_NOACCESS: return -EACCES;
case WF_BAD_ACCESS_DENIED: return -EACCES;
default: return -ENOENT;
}
}
@ -28,7 +28,7 @@ char const * wf_status_tostring(wf_status status)
case WF_BAD_BUSY: return "Bad (busy)";
case WF_BAD_FORMAT: return "Bad (format)";
case WF_BAD_NOENTRY: return "Bad (no entry)";
case WF_BAD_NOACCESS: return "Bad (no access)";
case WF_BAD_ACCESS_DENIED: return "Bad (access denied)";
default: return "Bad (unknown)";
}
}

View File

@ -8,25 +8,18 @@ static void response_parse_str(
std::string const & buffer,
struct wf_impl_jsonrpc_response * response)
{
wf_impl_jsonrpc_response_init(response, buffer.c_str(), buffer.size());
json_t * message = json_loadb(buffer.c_str(), buffer.size(), 0, nullptr);
if (nullptr != message)
{
wf_impl_jsonrpc_response_init(response, message);
json_decref(message);
}
}
TEST(response_parser, test)
{
struct wf_impl_jsonrpc_response response;
// invalid json
response_parse_str("", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(-1, response.id);
ASSERT_EQ(nullptr, response.result);
// invalid json
response_parse_str("invalid_json", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(-1, response.id);
ASSERT_EQ(nullptr, response.result);
// no object
response_parse_str("[]", &response);
ASSERT_NE(WF_GOOD, response.status);