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

added timeout handling

This commit is contained in:
Falk Werner 2019-02-09 19:02:53 +01:00
parent aec60d194e
commit 083ebbefe3
16 changed files with 534 additions and 5 deletions

View File

@ -44,6 +44,9 @@ add_library(fuse-wsfs
src/wsfs/server.c
src/wsfs/message.c
src/wsfs/message_queue.c
src/wsfs/time/timepoint.c
src/wsfs/time/timer.c
src/wsfs/time/timeout_manager.c
src/wsfs/operation/lookup.c
src/wsfs/operation/getattr.c
src/wsfs/operation/readdir.c
@ -81,6 +84,8 @@ pkg_check_modules(GTEST gtest_main)
add_executable(alltests
test-src/test_response_parser.cc
test-src/test_server.cc
test-src/test_timepoint.cc
test-src/test_timer.cc
)
target_link_libraries(alltests PUBLIC fuse-wsfs ${EXTRA_LIBS} ${GTEST_LIBRARIES})

View File

@ -5,6 +5,8 @@
#include "wsfs/jsonrpc/request.h"
#include "wsfs/jsonrpc/response.h"
#define WSFS_DEFAULT_TIMEOUT (10 * 1000)
static struct wsfs_jsonrpc_method const * wsfs_jsonrpc_server_getmethod(
struct wsfs_jsonrpc_server * server,
char const * name)
@ -18,16 +20,41 @@ static struct wsfs_jsonrpc_method const * wsfs_jsonrpc_server_getmethod(
return method;
}
static void wsfs_jsonrpc_server_timeout(
struct wsfs_timer * timer)
{
struct wsfs_jsonrpc_server * server = timer->user_data;
if (server->request.is_pending)
{
wsfs_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;
wsfs_timer_cancel(&server->request.timer);
finished(user_data, WSFS_BAD_TIMEOUT, NULL);
}
}
void wsfs_jsonrpc_server_init(
struct wsfs_jsonrpc_server * server)
struct wsfs_jsonrpc_server * server,
struct wsfs_timeout_manager * timeout_manager)
{
server->methods = NULL;
server->request.is_pending = false;
wsfs_timer_init(&server->request.timer, timeout_manager);
}
void wsfs_jsonrpc_server_cleanup(
struct wsfs_jsonrpc_server * server)
{
wsfs_timer_cleanup(&server->request.timer);
if (server->request.is_pending)
{
server->request.finished(server->request.user_data, WSFS_BAD, NULL);
@ -74,6 +101,8 @@ void wsfs_jsonrpc_server_invoke(
server->request.finished = finished;
server->request.user_data = user_data;
server->request.id = 42;
wsfs_timer_start(&server->request.timer, wsfs_timepoint_in_msec(WSFS_DEFAULT_TIMEOUT),
&wsfs_jsonrpc_server_timeout, server);
va_list args;
va_start(args, param_info);
@ -87,6 +116,7 @@ void wsfs_jsonrpc_server_invoke(
server->request.finished = NULL;
server->request.user_data = NULL;
server->request.id = 0;
wsfs_timer_cancel(&server->request.timer);
finished(user_data, WSFS_BAD, NULL);
}
@ -146,6 +176,7 @@ void wsfs_jsonrpc_server_onresult(
server->request.id = 0;
server->request.user_data = NULL;
server->request.finished = NULL;
wsfs_timer_cancel(&server->request.timer);
finished(user_data, response.status, response.result);
}

View File

@ -13,6 +13,9 @@ using std::size_t;
#include <jansson.h>
#include "wsfs/jsonrpc/method.h"
#include "wsfs/time/timeout_manager.h"
#include "wsfs/time/timer.h"
struct wsfs_jsonrpc_request
{
@ -20,6 +23,7 @@ struct wsfs_jsonrpc_request
wsfs_jsonrpc_method_finished_fn * finished;
void * user_data;
int id;
struct wsfs_timer timer;
};
struct wsfs_jsonrpc_server
@ -35,7 +39,8 @@ extern "C"
#endif
extern void wsfs_jsonrpc_server_init(
struct wsfs_jsonrpc_server * server);
struct wsfs_jsonrpc_server * server,
struct wsfs_timeout_manager * manager);
extern void wsfs_jsonrpc_server_cleanup(
struct wsfs_jsonrpc_server * server);

View File

@ -39,7 +39,7 @@ static void wsfs_operation_read_finished(void * user_data, wsfs_status status, j
fuse_req_t request = user_data;
char * buffer = NULL;
size_t length;
size_t length = 0;
if (NULL != data)
{
json_t * data_holder = json_object_get(data, "data");

View File

@ -17,6 +17,8 @@ static int wsfs_server_protocol_callback(
struct lws_protocols const * ws_protocol = lws_get_protocol(wsi);
struct wsfs_server_protocol * protocol = ws_protocol->user;
wsfs_timeout_manager_check(&protocol->timeout_manager);
switch (reason)
{
case LWS_CALLBACK_PROTOCOL_INIT:
@ -146,7 +148,9 @@ bool wsfs_server_protocol_init(
protocol->wsi = NULL;
wsfs_message_queue_init(&protocol->queue);
wsfs_jsonrpc_server_init(&protocol->rpc);
wsfs_timeout_manager_init(&protocol->timeout_manager);
wsfs_jsonrpc_server_init(&protocol->rpc, &protocol->timeout_manager);
wsfs_jsonrpc_server_add(&protocol->rpc, "lookup", &wsfs_server_protocol_invoke, protocol);
wsfs_jsonrpc_server_add(&protocol->rpc, "getattr", &wsfs_server_protocol_invoke, protocol);
wsfs_jsonrpc_server_add(&protocol->rpc, "readdir", &wsfs_server_protocol_invoke, protocol);
@ -154,7 +158,17 @@ bool wsfs_server_protocol_init(
wsfs_jsonrpc_server_add(&protocol->rpc, "close", &wsfs_server_protocol_invoke, protocol);
wsfs_jsonrpc_server_add(&protocol->rpc, "read", &wsfs_server_protocol_invoke, protocol);
return wsfs_filesystem_init(&protocol->filesystem, &protocol->rpc, mount_point);
bool const success = wsfs_filesystem_init(&protocol->filesystem, &protocol->rpc, mount_point);
// cleanup on error
if (!success)
{
wsfs_jsonrpc_server_cleanup(&protocol->rpc);
wsfs_timeout_manager_cleanup(&protocol->timeout_manager);
wsfs_message_queue_cleanup(&protocol->queue);
}
return success;
}
void wsfs_server_protocol_cleanup(
@ -162,6 +176,7 @@ void wsfs_server_protocol_cleanup(
{
wsfs_filesystem_cleanup(&protocol->filesystem);
wsfs_jsonrpc_server_cleanup(&protocol->rpc);
wsfs_timeout_manager_cleanup(&protocol->timeout_manager);
wsfs_message_queue_cleanup(&protocol->queue);
protocol->wsi = NULL;
}

View File

@ -5,9 +5,11 @@
#include "wsfs/filesystem.h"
#include "wsfs/message_queue.h"
#include "wsfs/jsonrpc/server.h"
#include "wsfs/time/timeout_manager.h"
struct wsfs_server_protocol
{
struct wsfs_timeout_manager timeout_manager;
struct wsfs_filesystem filesystem;
struct wsfs_jsonrpc_server rpc;
struct wsfs_message_queue queue;

View File

@ -0,0 +1,84 @@
#include "wsfs/time/timeout_manager_intern.h"
#include <stddef.h>
#include "wsfs/time/timer_intern.h"
#include "wsfs/time/timepoint.h"
void wsfs_timeout_manager_init(
struct wsfs_timeout_manager * manager)
{
manager->timers = NULL;
}
void wsfs_timeout_manager_cleanup(
struct wsfs_timeout_manager * manager)
{
struct wsfs_timer * timer = manager->timers;
while (NULL != timer)
{
struct wsfs_timer * next = timer->next;
wsfs_timer_trigger(timer);
timer = next;
}
manager->timers = NULL;
}
void wsfs_timeout_manager_check(
struct wsfs_timeout_manager * manager)
{
struct wsfs_timer * timer = manager->timers;
while (NULL != timer)
{
struct wsfs_timer * next = timer->next;
if (wsfs_timer_is_timeout(timer))
{
wsfs_timeout_manager_removetimer(manager, timer);
wsfs_timer_trigger(timer);
}
timer = next;
}
}
void wsfs_timeout_manager_addtimer(
struct wsfs_timeout_manager * manager,
struct wsfs_timer * timer)
{
if (NULL != manager->timers)
{
manager->timers->prev = timer;
}
timer->next = manager->timers;
timer->prev = NULL;
manager->timers = timer;
}
void wsfs_timeout_manager_removetimer(
struct wsfs_timeout_manager * manager,
struct wsfs_timer * timer)
{
struct wsfs_timer * prev = timer->prev;
struct wsfs_timer * next = timer->next;
if (NULL != prev)
{
prev->next = next;
}
if (NULL != next)
{
next->prev = prev;
}
if (manager->timers == timer)
{
manager->timers = next;
}
}

View File

@ -0,0 +1,29 @@
#ifndef _WSFS_TIME_TIMEOUT_MANAGER_H
#define _WSFS_TIME_TIMEOUT_MANAGER_H
struct wsfs_timer;
struct wsfs_timeout_manager
{
struct wsfs_timer * timers;
};
#ifdef __cplusplus
extern "C"
{
#endif
extern void wsfs_timeout_manager_init(
struct wsfs_timeout_manager * manager);
extern void wsfs_timeout_manager_cleanup(
struct wsfs_timeout_manager * manager);
extern void wsfs_timeout_manager_check(
struct wsfs_timeout_manager * manager);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,24 @@
#ifndef _WSFS_TIME_TIMEOUT_MANAGER_INTERN_H
#define _WSFS_TIME_TIMEOUT_MANAGER_INTERN_H
#include "wsfs/time/timeout_manager.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern void wsfs_timeout_manager_addtimer(
struct wsfs_timeout_manager * manager,
struct wsfs_timer * timer);
extern void wsfs_timeout_manager_removetimer(
struct wsfs_timeout_manager * manager,
struct wsfs_timer * timer);
#ifdef __cplusplus
}
#endif
#endif

31
src/wsfs/time/timepoint.c Normal file
View File

@ -0,0 +1,31 @@
#include "wsfs/time/timepoint.h"
#include <time.h>
#define WSFS_MSEC_PER_SEC ((wsfs_timepoint) 1000)
#define WSFS_NSEC_PER_MSEC ((wsfs_timepoint) 1000 * 1000)
wsfs_timepoint wsfs_timepoint_now(void)
{
struct timespec timepoint;
clock_gettime(CLOCK_MONOTONIC, &timepoint);
wsfs_timepoint const now = (timepoint.tv_sec * WSFS_MSEC_PER_SEC) + (timepoint.tv_nsec / WSFS_NSEC_PER_MSEC);
return now;
}
wsfs_timepoint wsfs_timepoint_in_msec(wsfs_timediff value)
{
wsfs_timepoint const now = wsfs_timepoint_now();
wsfs_timepoint result = now + ((wsfs_timepoint) value);
return result;
}
bool wsfs_timepoint_is_elapsed(wsfs_timepoint timepoint)
{
wsfs_timepoint const now = wsfs_timepoint_now();
wsfs_timediff const diff = (wsfs_timediff) (timepoint - now);
return (0 > diff);
}

31
src/wsfs/time/timepoint.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _WSFS_TIME_TIMEPOINT_H
#define _WSFS_TIME_TIMEPOINT_H
#ifndef __cplusplus
#include <stdbool.h>
#include <inttypes.h>
#else
#include <cinttypes>
#endif
typedef uint64_t wsfs_timepoint;
typedef int64_t wsfs_timediff;
#ifdef __cplusplus
extern "C"
{
#endif
extern wsfs_timepoint wsfs_timepoint_now(void);
extern wsfs_timepoint wsfs_timepoint_in_msec(
wsfs_timediff value);
extern bool wsfs_timepoint_is_elapsed(
wsfs_timepoint timepoint);
#ifdef __cplusplus
}
#endif
#endif

65
src/wsfs/time/timer.c Normal file
View File

@ -0,0 +1,65 @@
#include "wsfs/time/timer_intern.h"
#include "wsfs/time/timeout_manager_intern.h"
#include <stddef.h>
#include <string.h>
void wsfs_timer_init(
struct wsfs_timer * timer,
struct wsfs_timeout_manager * manager)
{
timer->manager = manager;
timer->timeout = 0;
timer->timeout_handler = NULL;
timer->user_data = NULL;
timer->prev = NULL;
timer->next = NULL;
}
void wsfs_timer_cleanup(
struct wsfs_timer * timer)
{
memset(timer, 0, sizeof(struct wsfs_timer));
}
void wsfs_timer_start(
struct wsfs_timer * timer,
wsfs_timepoint absolute_timeout,
wsfs_timer_timeout_fn * handler,
void * user_data)
{
timer->timeout = absolute_timeout;
timer->timeout_handler = handler;
timer->user_data = user_data;
wsfs_timeout_manager_addtimer(timer->manager, timer);
}
void wsfs_timer_cancel(
struct wsfs_timer * timer)
{
wsfs_timeout_manager_removetimer(timer->manager, timer);
timer->timeout = 0;
timer->timeout_handler = NULL;
timer->user_data = NULL;
}
bool wsfs_timer_is_timeout(
struct wsfs_timer * timer)
{
return wsfs_timepoint_is_elapsed(timer->timeout);
}
void wsfs_timer_trigger(
struct wsfs_timer * timer)
{
if (NULL != timer->timeout_handler)
{
timer->prev = NULL;
timer->next = NULL;
timer->timeout_handler(timer);
}
}

48
src/wsfs/time/timer.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef _WSFS_TIMER_H
#define _WSFS_TIMER_H
#include "wsfs/time/timepoint.h"
struct wsfs_timer;
struct wsfs_timeout_manager;
typedef void wsfs_timer_timeout_fn(struct wsfs_timer * timer);
struct wsfs_timer
{
struct wsfs_timeout_manager * manager;
wsfs_timepoint timeout;
wsfs_timer_timeout_fn * timeout_handler;
void * user_data;
struct wsfs_timer * next;
struct wsfs_timer * prev;
};
#ifdef __cplusplus
extern "C"
{
#endif
extern void wsfs_timer_init(
struct wsfs_timer * timer,
struct wsfs_timeout_manager * manager);
extern void wsfs_timer_cleanup(
struct wsfs_timer * timer);
extern void wsfs_timer_start(
struct wsfs_timer * timer,
wsfs_timepoint absolute_timeout,
wsfs_timer_timeout_fn * handler,
void * user_data);
extern void wsfs_timer_cancel(
struct wsfs_timer * timer);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,25 @@
#ifndef _WSFS_TIME_TIMER_INTERN_H
#define _WSFS_TIME_TIMER_INTERN_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include "wsfs/time/timer.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern bool wsfs_timer_is_timeout(
struct wsfs_timer * timer);
extern void wsfs_timer_trigger(
struct wsfs_timer * timer);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,34 @@
#include <gtest/gtest.h>
#include <unistd.h>
#include "wsfs/time/timepoint.h"
TEST(timepoint, now)
{
wsfs_timepoint start = wsfs_timepoint_now();
usleep(42 * 1000);
wsfs_timepoint end = wsfs_timepoint_now();
ASSERT_LT(start, end);
ASSERT_LT(end, start + 500);
}
TEST(timepoint, in_msec)
{
wsfs_timepoint now = wsfs_timepoint_now();
wsfs_timepoint later = wsfs_timepoint_in_msec(42);
ASSERT_LT(now, later);
ASSERT_LT(later, now + 500);
}
TEST(timepoint, elapsed)
{
wsfs_timepoint now;
now = wsfs_timepoint_now();
ASSERT_TRUE(wsfs_timepoint_is_elapsed(now - 1));
now = wsfs_timepoint_now();
ASSERT_FALSE(wsfs_timepoint_is_elapsed(now + 500));
}

100
test-src/test_timer.cc Normal file
View File

@ -0,0 +1,100 @@
#include <gtest/gtest.h>
#include <cstddef>
#include <unistd.h>
#include "wsfs/time/timer.h"
#include "wsfs/time/timeout_manager.h"
using std::size_t;
namespace
{
void on_timeout(struct wsfs_timer * timer)
{
bool * triggered = reinterpret_cast<bool*>(timer->user_data);
*triggered = true;
}
}
TEST(timer, init)
{
struct wsfs_timeout_manager manager;
struct wsfs_timer timer;
wsfs_timeout_manager_init(&manager);
wsfs_timer_init(&timer, &manager);
wsfs_timer_cleanup(&timer);
wsfs_timeout_manager_cleanup(&manager);
}
TEST(timer, trigger)
{
struct wsfs_timeout_manager manager;
struct wsfs_timer timer;
wsfs_timeout_manager_init(&manager);
wsfs_timer_init(&timer, &manager);
bool triggered = false;
wsfs_timer_start(&timer, wsfs_timepoint_in_msec(250), &on_timeout, reinterpret_cast<void*>(&triggered));
usleep(500 * 1000);
wsfs_timeout_manager_check(&manager);
ASSERT_TRUE(triggered);
wsfs_timer_cleanup(&timer);
wsfs_timeout_manager_cleanup(&manager);
}
TEST(timer, cancel)
{
struct wsfs_timeout_manager manager;
struct wsfs_timer timer;
wsfs_timeout_manager_init(&manager);
wsfs_timer_init(&timer, &manager);
bool triggered = false;
wsfs_timer_start(&timer, wsfs_timepoint_in_msec(250), &on_timeout, &triggered);
usleep(500 * 1000);
wsfs_timer_cancel(&timer);
wsfs_timeout_manager_check(&manager);
ASSERT_FALSE(triggered);
wsfs_timer_cleanup(&timer);
wsfs_timeout_manager_cleanup(&manager);
}
TEST(timer, multiple_timers)
{
static size_t const count = 5;
struct wsfs_timeout_manager manager;
struct wsfs_timer timer[count];
bool triggered[count];
wsfs_timeout_manager_init(&manager);
for(size_t i = 0; i < count; i++)
{
wsfs_timer_init(&timer[i], &manager);
triggered[i] = false;
wsfs_timer_start(&timer[i], wsfs_timepoint_in_msec(300 - (50 * i)), &on_timeout, &triggered[i]);
}
for(size_t i = 0; i < count; i++)
{
usleep(100 * 1000);
wsfs_timeout_manager_check(&manager);
}
for(size_t i = 0; i < count; i++)
{
ASSERT_TRUE(triggered[i]);
wsfs_timer_cleanup(&timer[i]);
}
wsfs_timeout_manager_cleanup(&manager);
}