From 4e442b774306134db3bae13cbed88623290ee69c Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 10 Dec 2015 07:58:58 +0800 Subject: [PATCH] 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 --- README.coding.md | 40 ++++++++++++ changelog | 45 +++++++++++++ lib/libwebsockets.c | 7 +- lib/libwebsockets.h | 56 ++++++++++++++++ lib/lws-plat-mbed3.c | 80 ++++++++++++++++++----- lib/lws-plat-unix.c | 138 ++++++++++++++++++++++++++------------- lib/lws-plat-win.c | 143 ++++++++++++++++++++++++++++------------- lib/output.c | 20 +++--- lib/private-libwebsockets.h | 32 ++------- lib/server.c | 6 +- test-server/test-server-http.c | 40 ++++++------ test-server/test-server.c | 29 +++++++++ test-server/test-server.h | 26 ++++---- 13 files changed, 483 insertions(+), 179 deletions(-) diff --git a/README.coding.md b/README.coding.md index 28be02c..c2a5f3b 100644 --- a/README.coding.md +++ b/README.coding.md @@ -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. diff --git a/changelog b/changelog index 583f8dd..3fc66e1 100644 --- a/changelog +++ b/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 ---------------- diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 16b5027..1cb6684 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -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 diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 3ef4f18..f930485 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -177,9 +177,13 @@ extern "C" { #else #define LWS_EXTERN #endif + +#define LWS_INVALID_FILE INVALID_HANDLE_VALUE #else /* NOT WIN32 */ #include + +#define LWS_INVALID_FILE -1 #ifndef MBED_OPERATORS #include @@ -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. diff --git a/lib/lws-plat-mbed3.c b/lib/lws-plat-mbed3.c index 372cbbb..1fa7db8 100644 --- a/lib/lws-plat-mbed3.c +++ b/lib/lws-plat-mbed3.c @@ -106,14 +106,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) -{ - return 0; -} - - -LWS_VISIBLE int lws_plat_context_early_init(void) { return 0; @@ -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; -} \ 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; +} diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index 7673765..a6898d8 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -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; } diff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c index 43b7c6a..f7afd99 100644 --- a/lib/lws-plat-win.c +++ b/lib/lws-plat-win.c @@ -257,35 +257,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) { WORD wVersionRequested; @@ -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; +} diff --git a/lib/output.c b/lib/output.c index 9985e79..58d86ea 100644 --- a/lib/output.c +++ b/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) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 99e34ba..e406b2f 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -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 @@ -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, diff --git a/lib/server.c b/lib/server.c index 2473cb5..0844435 100644 --- a/lib/server.c +++ b/lib/server.c @@ -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; diff --git a/test-server/test-server-http.c b/test-server/test-server-http.c index 7456d01..4e05b52 100644 --- a/test-server/test-server-http.c +++ b/test-server/test-server-http.c @@ -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; /* diff --git a/test-server/test-server.c b/test-server/test-server.c index 2ffe062..5620e4e 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -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; diff --git a/test-server/test-server.h b/test-server/test-server.h index 3ebf6f7..457f6aa 100644 --- a/test-server/test-server.h +++ b/test-server/test-server.h @@ -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); -- 2.7.4