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.
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
----------------
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);
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
#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>
/* 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.
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.
}
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)
{
return 0;
(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)
{
(void)fd;
return 1;
-}
\ No newline at end of file
+}
+
+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;
+}
}
-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)
{
}
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;
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;
}
}
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)
{
WORD wVersionRequested;
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)
{
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;
+}
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)) {
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;
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);
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:
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)
#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
#define vsnprintf _vsnprintf
#endif
-#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
#else /* not windows --> */
#include <fcntl.h>
#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
#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 {
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;
#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,
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);
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;
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;
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;
/*
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;
* 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;
}
/*
/* 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;
*/
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 */
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;
/*
#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"
{ 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;
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;
#endif
struct per_session_data__http {
- int fd;
+ lws_filefd_type fd;
};
/*
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);