lws_plat_fd implement platform default handlers
This is a rewrite of the patch from Soapyman here https://github.com/warmcat/libwebsockets/pull/363 The main changes compared to Soapyman's original patch are - There's no new stuff in the info struct user code does any overrides it may want to do explicitly after lws_context_create returns - User overrides for file ops can call through (subclass) to the original platform implementation using lws_get_fops_plat() - A typedef is provided for plat-specific fd type - Public helpers are provided to allow user code to be platform-independent about file access, using the lws platform file operations underneath: static inline lws_filefd_type lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename, unsigned long *filelen, int flags) static inline int lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd) static inline unsigned long lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd, long offset_from_cur_pos) static inline int lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) static inline int lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) There's example documentation and implementation in the test server. Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
11260dac18
commit
4e442b7743
13 changed files with 483 additions and 179 deletions
|
@ -276,3 +276,43 @@ After attempting the connection and getting back a non-`NULL` `wsi` you should
|
|||
loop calling `lws_service()` until one of the above callbacks occurs.
|
||||
|
||||
As usual, see [test-client.c](test-server/test-client.c) for example code.
|
||||
|
||||
Lws platform-independent file access apis
|
||||
-----------------------------------------
|
||||
|
||||
lws now exposes his internal platform file abstraction in a way that can be
|
||||
both used by user code to make it platform-agnostic, and be overridden or
|
||||
subclassed by user code. This allows things like handling the URI "directory
|
||||
space" as a virtual filesystem that may or may not be backed by a regular
|
||||
filesystem. One example use is serving files from inside large compressed
|
||||
archive storage without having to unpack anything except the file being
|
||||
requested.
|
||||
|
||||
The test server shows how to use it, basically the platform-specific part of
|
||||
lws prepares a file operations structure that lives in the lws context.
|
||||
|
||||
The user code can get a pointer to the file operations struct
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
|
||||
`lws_get_fops`(struct lws_context *context);
|
||||
|
||||
and then can use it with helpers to also leverage these platform-independent
|
||||
file handling apis
|
||||
|
||||
static inline lws_filefd_type
|
||||
`lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename, unsigned long *filelen, int flags)
|
||||
|
||||
static inline int
|
||||
`lws_plat_file_close`(struct lws_plat_file_ops *fops, lws_filefd_type fd)
|
||||
|
||||
static inline unsigned long
|
||||
`lws_plat_file_seek_cur`(struct lws_plat_file_ops *fops, lws_filefd_type fd, long offset_from_cur_pos)
|
||||
|
||||
static inline int
|
||||
`lws_plat_file_read`(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
|
||||
static inline int
|
||||
`lws_plat_file_write`(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
|
||||
The user code can also override or subclass the file operations, to either
|
||||
wrap or replace them. An example is shown in test server.
|
||||
|
|
45
changelog
45
changelog
|
@ -1,6 +1,51 @@
|
|||
Changelog
|
||||
---------
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
lws now exposes his internal platform file abstraction in a way that can be
|
||||
both used by user code to make it platform-agnostic, and be overridden or
|
||||
subclassed by user code. This allows things like handling the URI "directory
|
||||
space" as a virtual filesystem that may or may not be backed by a regular
|
||||
filesystem. One example use is serving files from inside large compressed
|
||||
archive storage without having to unpack anything except the file being
|
||||
requested.
|
||||
|
||||
The test server shows how to use it, basically the platform-specific part of
|
||||
lws prepares a file operations structure that lives in the lws context.
|
||||
|
||||
The user code can get a pointer to the file operations struct
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
|
||||
lws_get_fops(struct lws_context *context);
|
||||
|
||||
and then can use it with helpers to also leverage these platform-independent
|
||||
file handling apis
|
||||
|
||||
static inline lws_filefd_type
|
||||
lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
|
||||
unsigned long *filelen, int flags)
|
||||
|
||||
static inline int
|
||||
lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd)
|
||||
|
||||
static inline unsigned long
|
||||
lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
long offset_from_cur_pos)
|
||||
|
||||
static inline int
|
||||
lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
|
||||
static inline int
|
||||
lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
|
||||
The user code can also override or subclass the file operations, to either
|
||||
wrap or replace them. An example is shown in test server.
|
||||
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ lws_close_and_free_session(struct lws_context *context,
|
|||
if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED &&
|
||||
wsi->u.http.fd != LWS_INVALID_FILE) {
|
||||
lwsl_debug("closing http file\n");
|
||||
compatible_file_close(wsi->u.http.fd);
|
||||
lws_plat_file_close(&context->fops, wsi->u.http.fd);
|
||||
wsi->u.http.fd = LWS_INVALID_FILE;
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0);
|
||||
|
@ -929,6 +929,11 @@ lws_union_transition(struct lws *wsi, enum connection_mode mode)
|
|||
wsi->mode = mode;
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct lws_plat_file_ops *
|
||||
lws_get_fops(struct lws_context *context)
|
||||
{
|
||||
return &context->fops;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_OLD_API_WRAPPERS
|
||||
|
||||
|
|
|
@ -177,9 +177,13 @@ extern "C" {
|
|||
#else
|
||||
#define LWS_EXTERN
|
||||
#endif
|
||||
|
||||
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
|
||||
|
||||
#else /* NOT WIN32 */
|
||||
#include <unistd.h>
|
||||
|
||||
#define LWS_INVALID_FILE -1
|
||||
|
||||
#ifndef MBED_OPERATORS
|
||||
#include <poll.h>
|
||||
|
@ -296,6 +300,9 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
|
|||
/* extra parameter introduced in 917f43ab821 */
|
||||
#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_LEN
|
||||
|
||||
/* File operations stuff exists */
|
||||
#define LWS_FEATURE_FOPS
|
||||
|
||||
/*
|
||||
* NOTE: These public enums are part of the abi. If you want to add one,
|
||||
* add it at where specified so existing users are unaffected.
|
||||
|
@ -1626,6 +1633,55 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
lws_hdr_copy(struct lws *wsi, char *dest, int len,
|
||||
enum lws_token_indexes h);
|
||||
|
||||
/* get the active file operations struct */
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
|
||||
lws_get_fops(struct lws_context *context);
|
||||
|
||||
/*
|
||||
* File Operations access helpers
|
||||
*
|
||||
* usually the first argument will be lws_get_fops(context)
|
||||
* If so, then it calls the platform handler or user overrides where present
|
||||
* (as defined in info->fops)
|
||||
*
|
||||
* The advantage from all this is user code can be portable for file operations
|
||||
* without having to deal with differences between platforms.
|
||||
*/
|
||||
|
||||
static inline lws_filefd_type
|
||||
lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
|
||||
unsigned long *filelen, int flags)
|
||||
{
|
||||
return fops->open(filename, filelen, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd)
|
||||
{
|
||||
return fops->close(fd);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
long offset_from_cur_pos)
|
||||
{
|
||||
return fops->seek_cur(fd, offset_from_cur_pos);
|
||||
}
|
||||
|
||||
static inline int
|
||||
lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
{
|
||||
return fops->read(fd, amount, buf, len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd,
|
||||
unsigned long *amount, unsigned char *buf, unsigned long len)
|
||||
{
|
||||
return fops->write(fd, amount, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: this is not normally needed as a user api. It's provided in case it is
|
||||
* useful when integrating with other app poll loop service code.
|
||||
|
|
|
@ -105,14 +105,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
|||
(void)info;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
|
@ -138,14 +130,6 @@ lws_plat_service_periodic(struct lws_context *context)
|
|||
(void)context;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_open_file(const char* filename, unsigned long* filelen)
|
||||
{
|
||||
(void)filename;
|
||||
(void)filelen;
|
||||
return LWS_INVALID_FILE;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
|
@ -172,4 +156,66 @@ delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
|
|||
(void)fd;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static lws_filefd_type
|
||||
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
|
||||
{
|
||||
(void)filename;
|
||||
(void)filelen;
|
||||
(void)flags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_close(lws_filefd_type fd)
|
||||
{
|
||||
(void)fd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
|
||||
{
|
||||
(void)fd;
|
||||
(void)offset;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char* buf, unsigned long* len)
|
||||
{
|
||||
(void)amount;
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)len;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char* buf, unsigned long len)
|
||||
{
|
||||
(void)amount;
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)len;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
context->fops.open = _lws_plat_file_open;
|
||||
context->fops.close = _lws_plat_file_close;
|
||||
context->fops.seek_cur = _lws_plat_file_seek_cur;
|
||||
context->fops.read = _lws_plat_file_read;
|
||||
context->fops.write = _lws_plat_file_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -271,43 +271,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
|||
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds);
|
||||
if (context->lws_lookup == NULL) {
|
||||
lwsl_err(
|
||||
"Unable to allocate lws_lookup array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
if (context->fd_random < 0) {
|
||||
lwsl_err("Unable to open random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, context->fd_random);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_libev_init_fd_table(context))
|
||||
/* libev handled it instead */
|
||||
return 0;
|
||||
|
||||
if (pipe(context->dummy_pipe_fds)) {
|
||||
lwsl_err("Unable to create pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use the read end of pipe as first item */
|
||||
context->fds[0].fd = context->dummy_pipe_fds[0];
|
||||
context->fds[0].events = LWS_POLLIN;
|
||||
context->fds[0].revents = 0;
|
||||
context->fds_count = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigpipe_handler(int x)
|
||||
{
|
||||
}
|
||||
|
@ -446,11 +409,17 @@ lws_plat_change_pollfd(struct lws_context *context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_open_file(const char* filename, unsigned long* filelen)
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
}
|
||||
|
||||
static lws_filefd_type
|
||||
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int ret = open(filename, O_RDONLY);
|
||||
int ret = open(filename, flags, 0664);
|
||||
|
||||
if (ret < 0)
|
||||
return LWS_INVALID_FILE;
|
||||
|
@ -463,8 +432,91 @@ lws_plat_open_file(const char* filename, unsigned long* filelen)
|
|||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
static int
|
||||
_lws_plat_file_close(lws_filefd_type fd)
|
||||
{
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
|
||||
{
|
||||
return lseek(fd, offset, SEEK_CUR);
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char *buf, unsigned long len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = read((int)fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char *buf, unsigned long len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = write((int)fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds);
|
||||
if (context->lws_lookup == NULL) {
|
||||
lwsl_err(
|
||||
"Unable to allocate lws_lookup array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
if (context->fd_random < 0) {
|
||||
lwsl_err("Unable to open random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, context->fd_random);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_libev_init_fd_table(context))
|
||||
/* libev handled it instead */
|
||||
return 0;
|
||||
|
||||
if (pipe(context->dummy_pipe_fds)) {
|
||||
lwsl_err("Unable to create pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use the read end of pipe as first item */
|
||||
context->fds[0].fd = context->dummy_pipe_fds[0];
|
||||
context->fds[0].events = LWS_POLLIN;
|
||||
context->fds[0].revents = 0;
|
||||
context->fds_count = 1;
|
||||
|
||||
context->fops.open = _lws_plat_file_open;
|
||||
context->fops.close = _lws_plat_file_close;
|
||||
context->fops.seek_cur = _lws_plat_file_seek_cur;
|
||||
context->fops.read = _lws_plat_file_read;
|
||||
context->fops.write = _lws_plat_file_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -256,35 +256,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
|||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
|
||||
context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct lws*) * context->max_fds);
|
||||
|
||||
if (!context->fd_hashtable[i].wsi) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
context->events = lws_malloc(sizeof(WSAEVENT) * (context->max_fds + 1));
|
||||
if (context->events == NULL) {
|
||||
lwsl_err("Unable to allocate events array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fds_count = 0;
|
||||
context->events[0] = WSACreateEvent();
|
||||
|
||||
context->fd_random = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
|
@ -393,23 +364,6 @@ lws_plat_change_pollfd(struct lws_context *context,
|
|||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE HANDLE
|
||||
lws_plat_open_file(const char* filename, unsigned long* filelen)
|
||||
{
|
||||
HANDLE ret;
|
||||
WCHAR buffer[MAX_PATH];
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer,
|
||||
sizeof(buffer) / sizeof(buffer[0]));
|
||||
ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (ret != LWS_INVALID_FILE)
|
||||
*filelen = GetFileSize(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
|
@ -455,3 +409,100 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|||
lws_free(buffer);
|
||||
return ok ? dst : NULL;
|
||||
}
|
||||
|
||||
static lws_filefd_type
|
||||
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
|
||||
{
|
||||
HANDLE ret;
|
||||
WCHAR buf[MAX_PATH];
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
|
||||
if (flags & O_RDONLY) {
|
||||
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
} else {
|
||||
lwsl_err("%s: open for write not implemented\n", __func__);
|
||||
*filelen = 0;
|
||||
return LWS_INVALID_FILE;
|
||||
}
|
||||
|
||||
if (ret != LWS_INVALID_FILE)
|
||||
*filelen = GetFileSize(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_close(lws_filefd_type fd)
|
||||
{
|
||||
CloseHandle((HANDLE)fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
|
||||
{
|
||||
return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char* buf, unsigned long len)
|
||||
{
|
||||
DWORD _amount;
|
||||
|
||||
if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
|
||||
*amount = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
*amount = (unsigned long)_amount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char* buf, unsigned long len)
|
||||
{
|
||||
lwsl_err("%s: not implemented on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
|
||||
context->fd_hashtable[i].wsi =
|
||||
lws_zalloc(sizeof(struct lws*) * context->max_fds);
|
||||
|
||||
if (!context->fd_hashtable[i].wsi)
|
||||
return -1;
|
||||
}
|
||||
|
||||
context->events = lws_malloc(sizeof(WSAEVENT) * (context->max_fds + 1));
|
||||
if (context->events == NULL) {
|
||||
lwsl_err("Unable to allocate events array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fds_count = 0;
|
||||
context->events[0] = WSACreateEvent();
|
||||
|
||||
context->fd_random = 0;
|
||||
|
||||
context->fops.open = _lws_plat_file_open;
|
||||
context->fops.close = _lws_plat_file_close;
|
||||
context->fops.seek_cur = _lws_plat_file_seek_cur;
|
||||
context->fops.read = _lws_plat_file_read;
|
||||
context->fops.write = _lws_plat_file_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
20
lib/output.c
20
lib/output.c
|
@ -509,8 +509,8 @@ send_raw:
|
|||
LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
|
||||
struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
int m;
|
||||
unsigned long amount;
|
||||
int n, m;
|
||||
|
||||
while (!lws_send_pipe_choked(wsi)) {
|
||||
|
||||
|
@ -518,7 +518,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
|
|||
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
|
||||
wsi->truncated_send_offset,
|
||||
wsi->truncated_send_len) < 0) {
|
||||
lwsl_info("closing from lws_serve_http_file_fragment\n");
|
||||
lwsl_info("%s: closing\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
|
@ -527,10 +527,12 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
|
|||
if (wsi->u.http.filepos == wsi->u.http.filelen)
|
||||
goto all_sent;
|
||||
|
||||
compatible_file_read(n, wsi->u.http.fd, context->service_buffer,
|
||||
sizeof(context->service_buffer));
|
||||
if (n < 0)
|
||||
if (lws_plat_file_read(&context->fops, wsi->u.http.fd, &amount,
|
||||
context->service_buffer,
|
||||
sizeof(context->service_buffer)) < 0)
|
||||
return -1; /* caller will close */
|
||||
|
||||
n = (int)amount;
|
||||
if (n) {
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
AWAITING_TIMEOUT);
|
||||
|
@ -543,7 +545,9 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
|
|||
|
||||
if (m != n)
|
||||
/* adjust for what was not sent */
|
||||
if (compatible_file_seek_cur(wsi->u.http.fd, m - n) < 0)
|
||||
if (lws_plat_file_seek_cur(&context->fops,
|
||||
wsi->u.http.fd,
|
||||
m - n) < 0)
|
||||
return -1;
|
||||
}
|
||||
all_sent:
|
||||
|
@ -552,7 +556,7 @@ all_sent:
|
|||
wsi->state = WSI_STATE_HTTP;
|
||||
|
||||
/* we might be in keepalive, so close it off here */
|
||||
compatible_file_close(wsi->u.http.fd);
|
||||
lws_plat_file_close(&context->fops, wsi->u.http.fd);
|
||||
wsi->u.http.fd = LWS_INVALID_FILE;
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
|
|
|
@ -62,16 +62,6 @@
|
|||
#define SOL_TCP IPPROTO_TCP
|
||||
|
||||
#define compatible_close(fd) closesocket(fd)
|
||||
#define compatible_file_close(fd) CloseHandle(fd)
|
||||
#define compatible_file_seek_cur(fd, offset) \
|
||||
SetFilePointer(fd, offset, NULL, FILE_CURRENT)
|
||||
#define compatible_file_read(amount, fd, buf, len) {\
|
||||
DWORD _amount; \
|
||||
if (!ReadFile(fd, buf, len, &_amount, NULL)) \
|
||||
amount = -1; \
|
||||
else \
|
||||
amount = _amount; \
|
||||
}
|
||||
#define lws_set_blocking_send(wsi) wsi->sock_send_blocking = TRUE
|
||||
#define lws_socket_is_valid(x) (!!x)
|
||||
#define LWS_SOCK_INVALID 0
|
||||
|
@ -91,7 +81,6 @@
|
|||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
|
||||
#else /* not windows --> */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
@ -144,15 +133,10 @@
|
|||
#define LWS_EINTR EINTR
|
||||
#define LWS_EISCONN EISCONN
|
||||
#define LWS_EWOULDBLOCK EWOULDBLOCK
|
||||
#define LWS_INVALID_FILE -1
|
||||
#define LWS_POLLHUP (POLLHUP|POLLERR)
|
||||
#define LWS_POLLIN (POLLIN)
|
||||
#define LWS_POLLOUT (POLLOUT)
|
||||
#define compatible_close(fd) close(fd)
|
||||
#define compatible_file_close(fd) close(fd)
|
||||
#define compatible_file_seek_cur(fd, offset) lseek(fd, offset, SEEK_CUR)
|
||||
#define compatible_file_read(amount, fd, buf, len) \
|
||||
amount = read(fd, buf, len);
|
||||
#define lws_set_blocking_send(wsi)
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
|
@ -546,8 +530,10 @@ struct lws_context {
|
|||
#ifndef LWS_NO_EXTENSIONS
|
||||
struct lws_extension *extensions;
|
||||
#endif
|
||||
struct lws_token_limits *token_limits;
|
||||
struct lws_token_limits *token_limits;
|
||||
void *user_space;
|
||||
|
||||
struct lws_plat_file_ops fops;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -644,11 +630,7 @@ struct allocated_headers {
|
|||
struct _lws_http_mode_related {
|
||||
/* MUST be first in struct */
|
||||
struct allocated_headers *ah; /* mirroring _lws_header_related */
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
HANDLE fd;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
lws_filefd_type fd;
|
||||
unsigned long filepos;
|
||||
unsigned long filelen;
|
||||
|
||||
|
@ -1142,12 +1124,6 @@ interface_to_sa(struct lws_context *context, const char *ifname,
|
|||
#endif
|
||||
LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
|
||||
|
||||
#ifdef _WIN32
|
||||
LWS_EXTERN HANDLE lws_plat_open_file(const char* filename, unsigned long* filelen);
|
||||
#else
|
||||
LWS_EXTERN int lws_plat_open_file(const char* filename, unsigned long* filelen);
|
||||
#endif
|
||||
|
||||
enum lws_ssl_capable_status {
|
||||
LWS_SSL_CAPABLE_ERROR = -1,
|
||||
LWS_SSL_CAPABLE_MORE_SERVICE = -2,
|
||||
|
|
|
@ -914,7 +914,8 @@ LWS_VISIBLE int lws_serve_http_file(struct lws_context *context,
|
|||
LWS_SEND_BUFFER_PRE_PADDING;
|
||||
int ret = 0;
|
||||
|
||||
wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
|
||||
wsi->u.http.fd = lws_plat_file_open(&context->fops, file,
|
||||
&wsi->u.http.filelen, O_RDONLY);
|
||||
|
||||
if (wsi->u.http.fd == LWS_INVALID_FILE) {
|
||||
lwsl_err("Unable to open '%s'\n", file);
|
||||
|
@ -948,8 +949,7 @@ LWS_VISIBLE int lws_serve_http_file(struct lws_context *context,
|
|||
if (lws_finalize_http_header(context, wsi, &p, end))
|
||||
return -1;
|
||||
|
||||
ret = lws_write(wsi, response,
|
||||
p - response, LWS_WRITE_HTTP_HEADERS);
|
||||
ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);
|
||||
if (ret != (p - response)) {
|
||||
lwsl_err("_write returned %d from %d\n", ret, (p - response));
|
||||
return -1;
|
||||
|
|
|
@ -117,7 +117,7 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
struct per_session_data__http *pss =
|
||||
(struct per_session_data__http *)user;
|
||||
static unsigned char buffer[4096];
|
||||
struct stat stat_buf;
|
||||
unsigned long amount, file_len;
|
||||
char leaf_path[1024];
|
||||
const char *mimetype;
|
||||
char *other_headers;
|
||||
|
@ -165,16 +165,12 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
|
||||
p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
|
||||
end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
|
||||
#ifdef _WIN32
|
||||
pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
|
||||
#else
|
||||
pss->fd = open(leaf_path, O_RDONLY);
|
||||
#endif
|
||||
|
||||
if (pss->fd < 0)
|
||||
return -1;
|
||||
pss->fd = lws_plat_file_open(lws_get_fops(context),
|
||||
leaf_path, &file_len,
|
||||
O_RDONLY);
|
||||
|
||||
if (fstat(pss->fd, &stat_buf) < 0)
|
||||
if (pss->fd == LWS_INVALID_FILE)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
|
@ -200,7 +196,8 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
10, &p, end))
|
||||
return 1;
|
||||
if (lws_add_http_header_content_length(context, wsi,
|
||||
stat_buf.st_size, &p, end))
|
||||
file_len, &p,
|
||||
end))
|
||||
return 1;
|
||||
if (lws_finalize_http_header(context, wsi, &p, end))
|
||||
return 1;
|
||||
|
@ -216,13 +213,13 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
* this is mandated by changes in HTTP2
|
||||
*/
|
||||
|
||||
n = lws_write(wsi,
|
||||
buffer + LWS_SEND_BUFFER_PRE_PADDING,
|
||||
p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
n = lws_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING,
|
||||
p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
|
||||
if (n < 0) {
|
||||
close(pss->fd);
|
||||
lws_plat_file_close(lws_get_fops(context),
|
||||
pss->fd);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
|
@ -328,11 +325,13 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
/* he couldn't handle that much */
|
||||
n = m;
|
||||
|
||||
n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING,
|
||||
n);
|
||||
n = lws_plat_file_read(lws_get_fops(context), pss->fd,
|
||||
&amount, buffer +
|
||||
LWS_SEND_BUFFER_PRE_PADDING, n);
|
||||
/* problem reading, close conn */
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
n = (int)amount;
|
||||
/* sent it all, close conn */
|
||||
if (n == 0)
|
||||
goto flush_bail;
|
||||
|
@ -354,7 +353,8 @@ int callback_http(struct lws_context *context, struct lws *wsi,
|
|||
*/
|
||||
if (m != n)
|
||||
/* partial write, adjust */
|
||||
if (lseek(pss->fd, m - n, SEEK_CUR) < 0)
|
||||
if (lws_plat_file_seek_cur(lws_get_fops(context),
|
||||
pss->fd, m - n) < 0)
|
||||
goto bail;
|
||||
|
||||
if (m) /* while still active, extend timeout */
|
||||
|
@ -377,11 +377,11 @@ flush_bail:
|
|||
lws_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
close(pss->fd);
|
||||
lws_plat_file_close(lws_get_fops(context), pss->fd);
|
||||
goto try_to_reuse;
|
||||
|
||||
bail:
|
||||
close(pss->fd);
|
||||
lws_plat_file_close(lws_get_fops(context), pss->fd);
|
||||
return -1;
|
||||
|
||||
/*
|
||||
|
|
|
@ -31,6 +31,7 @@ int count_pollfds;
|
|||
#endif
|
||||
volatile int force_exit = 0;
|
||||
struct lws_context *context;
|
||||
struct lws_plat_file_ops fops_plat;
|
||||
|
||||
/* http server gets files from this path */
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
|
@ -97,6 +98,25 @@ static struct lws_protocols protocols[] = {
|
|||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
||||
/* this shows how to override the lws file operations. You don't need
|
||||
* to do any of this unless you have a reason (eg, want to serve
|
||||
* compressed files without decompressing the whole archive)
|
||||
*/
|
||||
static lws_filefd_type
|
||||
test_server_fops_open(const char *filename, unsigned long *filelen, int flags)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* call through to original platform implementation */
|
||||
n = fops_plat.open(filename, filelen, flags);
|
||||
|
||||
lwsl_notice("%s: opening %s, ret %d, len %lu\n", __func__, filename,
|
||||
n, *filelen);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
|
@ -271,6 +291,15 @@ int main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* this shows how to override the lws file operations. You don't need
|
||||
* to do any of this unless you have a reason (eg, want to serve
|
||||
* compressed files without decompressing the whole archive)
|
||||
*/
|
||||
/* stash original platform fops */
|
||||
fops_plat = *(lws_get_fops(context));
|
||||
/* override the active fops */
|
||||
lws_get_fops(context)->open = test_server_fops_open;
|
||||
|
||||
n = 0;
|
||||
while (n >= 0 && !force_exit) {
|
||||
struct timeval tv;
|
||||
|
|
|
@ -43,7 +43,7 @@ extern void test_server_unlock(int care);
|
|||
#endif
|
||||
|
||||
struct per_session_data__http {
|
||||
int fd;
|
||||
lws_filefd_type fd;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -63,18 +63,18 @@ struct per_session_data__lws_mirror {
|
|||
int ringbuffer_tail;
|
||||
};
|
||||
|
||||
extern int callback_http(struct lws_context *context,
|
||||
struct lws *wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int callback_lws_mirror(struct lws_context *context,
|
||||
struct lws *wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int callback_dumb_increment(struct lws_context *context,
|
||||
struct lws *wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int
|
||||
callback_http(struct lws_context *context, struct lws *wsi,
|
||||
enum lws_callback_reasons reason, void *user, void *in,
|
||||
size_t len);
|
||||
extern int
|
||||
callback_lws_mirror(struct lws_context *context, struct lws *wsi,
|
||||
enum lws_callback_reasons reason, void *user, void *in,
|
||||
size_t len);
|
||||
extern int
|
||||
callback_dumb_increment(struct lws_context *context, struct lws *wsi,
|
||||
enum lws_callback_reasons reason, void *user, void *in,
|
||||
size_t len);
|
||||
|
||||
extern void
|
||||
dump_handshake_info(struct lws *wsi);
|
||||
|
|
Loading…
Add table
Reference in a new issue