Skip to content

Commit

Permalink
libunit-wasm: Add a luw_mem_splice_file() function
Browse files Browse the repository at this point in the history
This is inspired by the likes of splice(2) and sendfile(2) in that it
takes data from one place and puts it in another.

This function write(2)'s the request data straight from the shared
memory to a given file (referenced by its file descriptor).

This is an alternative to using luw_req_buf_copy() and avoids an extra
copying of the request data.

E.g

  /* In the request_handler */
  if (total_bytes_wrote == 0) {
          luw_init_ctx(&ctx, addr, 0);
          luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);

          fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
                    0666);
  }

  total_bytes_wrote += luw_mem_splice_file(addr, fd);
  if (total_bytes_wrote == luw_get_http_content_len(&ctx)) {
          close(fd);
          total_bytes_wrote = 0;
          luw_http_response_end();
  }

NOTE:

We include a typedef definition for ssize_t in unit-wasm.h, to avoid
having a dependency on the wasi-sysroot when generating the rust
bindings.

ssize_t is defined in sys/types.h which is provided by libc and not the
compiler.

Signed-off-by: Andrew Clayton <[email protected]>
  • Loading branch information
ac000 committed Sep 25, 2023
1 parent 1dd1b34 commit 43c8e44
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/c/include/unit/unit-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ typedef enum {
LUW_HTTP_GATEWAY_TIMEOUT = 504,
} luw_http_status_t;

#if !defined(__DEFINED_ssize_t)
/*
* Match the typedef from wasm32-wasi/include/bits/alltypes.h
* without requiring the wasi-sysroot for building the rust
* stuff.
*/
typedef long ssize_t;
#endif

struct luw_hdr_field {
u32 name_off;
u32 name_len;
Expand Down Expand Up @@ -239,6 +248,7 @@ extern int luw_mem_writep(luw_ctx_t *ctx, const char *fmt, ...);
extern size_t luw_mem_writep_data(luw_ctx_t *ctx, const u8 *src, size_t size);
extern void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src);
extern void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src);
extern ssize_t luw_mem_splice_file(const u8 *src, int fd);
extern size_t luw_mem_fill_buf_from_req(luw_ctx_t *ctx, size_t from);
extern void luw_mem_reset(luw_ctx_t *ctx);
extern void luw_http_set_response_status(luw_http_status_t status);
Expand Down
29 changes: 29 additions & 0 deletions src/c/libunit-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>

#include "unit/unit-wasm.h"

#define MIN(a, b) \
({ __typeof__(a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })

/*
* Some handlers are required some are optional.
*
Expand Down Expand Up @@ -315,6 +321,29 @@ void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src)
ctx->req->total_content_sent = req->total_content_sent;
}

/* Copy data from the request to a given file-descriptor. */
ssize_t luw_mem_splice_file(const u8 *src, int fd)
{
struct luw_req *req = (struct luw_req *)src;
size_t written = 0;
size_t bytes_splice = 1024 * 128; /* It's what cp(1) uses */

do {
ssize_t bytes_wrote;

bytes_splice = MIN(bytes_splice, req->content_sent - written);

bytes_wrote = write(fd, src + req->content_off + written,
bytes_splice);
if (bytes_wrote == -1)
return -1;

written += bytes_wrote;
} while (written < req->content_sent);

return written;
}

/*
* Convenience function to fill the response buffer with data from
* the request buffer.
Expand Down

0 comments on commit 43c8e44

Please sign in to comment.