added mio_foff_t.

adding sendfile support to the core
This commit is contained in:
hyung-hwan 2020-07-17 15:28:18 +00:00
parent 7adf19f01d
commit e439c29cb8
6 changed files with 115 additions and 28 deletions

View File

@ -59,10 +59,10 @@ struct file_state_t
mio_oow_t num_pending_writes_to_peer; mio_oow_t num_pending_writes_to_peer;
int peer; int peer;
mio_uintmax_t total_size; mio_foff_t total_size;
mio_uintmax_t start_offset; mio_foff_t start_offset;
mio_uintmax_t end_offset; mio_foff_t end_offset;
mio_uintmax_t cur_offset; mio_foff_t cur_offset;
mio_bch_t peer_buf[8192]; mio_bch_t peer_buf[8192];
mio_tmridx_t peer_tmridx; mio_tmridx_t peer_tmridx;
@ -433,7 +433,7 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu
{ {
mio_svc_htts_cli_t* cli = file_state->client; mio_svc_htts_cli_t* cli = file_state->client;
mio_bch_t dtbuf[64]; mio_bch_t dtbuf[64];
mio_uintmax_t content_length; mio_foff_t content_length;
mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf));
@ -449,8 +449,8 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu
(force_close? "close": "keep-alive"), (force_close? "close": "keep-alive"),
content_length) == (mio_oow_t)-1) return -1; content_length) == (mio_oow_t)-1) return -1;
if (status_code == 206 && mio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", file_state->start_offset, file_state->end_offset, file_state->total_size) == (mio_oow_t)-1) return -1; if (status_code == 206 && mio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", (mio_uintmax_t)file_state->start_offset, (mio_uintmax_t)file_state->end_offset, (mio_uintmax_t)file_state->total_size) == (mio_oow_t)-1) return -1;
if (mio_becs_fcat(cli->sbuf, "Content-Length: %ju\r\n\r\n", content_length) == (mio_oow_t)-1) return -1; if (mio_becs_fcat(cli->sbuf, "Content-Length: %ju\r\n\r\n", (mio_uintmax_t)content_length) == (mio_oow_t)-1) return -1;
return file_state_write_to_client(file_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)); return file_state_write_to_client(file_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf));
} }
@ -472,7 +472,7 @@ static int file_state_send_contents_to_client (file_state_t* file_state)
* mio_dev_sck_write(sck, data_required_for_sendfile_operation, 0, MIO_NULL);.... * mio_dev_sck_write(sck, data_required_for_sendfile_operation, 0, MIO_NULL);....
*/ */
mio_t* mio = file_state->htts->mio; mio_t* mio = file_state->htts->mio;
mio_uintmax_t lim; mio_foff_t lim;
ssize_t n; ssize_t n;
if (file_state->cur_offset > file_state->end_offset) if (file_state->cur_offset > file_state->end_offset)

View File

@ -214,7 +214,7 @@ int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range)
/* NOTE: this function does not support a range set /* NOTE: this function does not support a range set
* like bytes=1-20,30-50 */ * like bytes=1-20,30-50 */
mio_http_range_int_t from, to; mio_foff_t from, to;
int type = MIO_HTTP_RANGE_PROPER; int type = MIO_HTTP_RANGE_PROPER;
if (str[0] != 'b' || if (str[0] != 'b' ||

View File

@ -942,4 +942,33 @@ struct mio_cmgr_t
#define MIO_STATIC_ASSERT_EXPR(expr) ((void)MIO_SIZEOF(char[(expr)? 1: -1])) #define MIO_STATIC_ASSERT_EXPR(expr) ((void)MIO_SIZEOF(char[(expr)? 1: -1]))
/* =========================================================================
* FILE OFFSET TYPE
* =========================================================================*/
/**
* The #mio_foff_t type defines an integer that can represent a file offset.
* Depending on your system, it's defined to one of #mio_int64_t, #mio_int32_t,
* and #mio_int16_t.
*/
#if defined(MIO_HAVE_INT64_T) && (MIO_SIZEOF_OFF64_T==8)
typedef mio_int64_t mio_foff_t;
# define MIO_SIZEOF_FOFF_T MIO_SIZEOF_INT64_T
#elif defined(MIO_HAVE_INT64_T) && (MIO_SIZEOF_OFF_T==8)
typedef mio_int64_t mio_foff_t;
# define MIO_SIZEOF_FOFF_T MIO_SIZEOF_INT64_T
#elif defined(MIO_HAVE_INT32_T) && (MIO_SIZEOF_OFF_T==4)
typedef mio_int32_t mio_foff_t;
# define MIO_SIZEOF_FOFF_T MIO_SIZEOF_INT32_T
#elif defined(MIO_HAVE_INT16_T) && (MIO_SIZEOF_OFF_T==2)
typedef mio_int16_t mio_foff_t;
# define MIO_SIZEOF_FOFF_T MIO_SIZEOF_INT16_T
#elif defined(MIO_HAVE_INT8_T) && (MIO_SIZEOF_OFF_T==1)
typedef mio_int8_t mio_foff_t;
# define MIO_SIZEOF_FOFF_T MIO_SIZEOF_INT16_T
#else
typedef mio_int32_t mio_foff_t; /* this line is for doxygen */
# error Unsupported platform
#endif
#endif #endif

View File

@ -34,17 +34,6 @@
* This file provides basic data types and functions for the http protocol. * This file provides basic data types and functions for the http protocol.
*/ */
/**
* The #mio_http_range_int_t type defines an integer that can represent
* a range offset. Depening on the size of #mio_foff_t, it is defined to
* either #mio_foff_t or #mio_ulong_t.
*/
#if defined(MIO_SIZEOF_FOFF_T) && defined(MIO_SIZEOF_UINTMAX_T) && (MIO_SIZEOF_FOFF_T > MIO_SIZEOF_UINTMAX_T)
typedef mio_foff_t mio_http_range_int_t;
#else
typedef mio_uintmax_t mio_http_range_int_t;
#endif
enum mio_http_range_type_t enum mio_http_range_type_t
{ {
MIO_HTTP_RANGE_PROPER, MIO_HTTP_RANGE_PROPER,
@ -73,8 +62,8 @@ typedef enum mio_http_range_type_t mio_http_range_type_t;
struct mio_http_range_t struct mio_http_range_t
{ {
mio_http_range_type_t type; /**< type indicator */ mio_http_range_type_t type; /**< type indicator */
mio_http_range_int_t from; /**< starting offset */ mio_foff_t from; /**< starting offset */
mio_http_range_int_t to; /**< ending offset */ mio_foff_t to; /**< ending offset */
}; };
typedef struct mio_http_range_t mio_http_range_t; typedef struct mio_http_range_t mio_http_range_t;

View File

@ -1549,30 +1549,98 @@ enqueue_completed_write:
return __enqueue_completed_write(dev, len, wrctx, dstaddr); return __enqueue_completed_write(dev, len, wrctx, dstaddr);
} }
static int __dev_sendfile (mio_dev_t* dev, mio_syshnd_t in_fd, mio_uintmax_t offset, mio_iolen_t len, const mio_ntime_t* tmout, void* wrctx, const mio_devaddr_t* dstaddr) static int __dev_sendfile (mio_dev_t* dev, mio_syshnd_t in_fd, mio_foff_t foff, mio_iolen_t len, const mio_ntime_t* tmout, void* wrctx)
{ {
#if 1
mio_t* mio = dev->mio; mio_t* mio = dev->mio;
mio_foff_t uoff;
mio_iolen_t urem, ulen;
int x;
if (dev->dev_cap & MIO_DEV_CAP_OUT_CLOSED) if (dev->dev_cap & MIO_DEV_CAP_OUT_CLOSED)
{ {
mio_seterrbfmt (mio, MIO_ENOCAPA, "unable to write to closed device"); mio_seterrbfmt (mio, MIO_ENOCAPA, "unable to sendfile to closed device");
return -1; return -1;
} }
uoff = foff;
urem = len;
if (!MIO_WQ_IS_EMPTY(&dev->wq)) if (!MIO_WQ_IS_EMPTY(&dev->wq))
{ {
/* if the writing queue is not empty, enqueue this request immediately */ /* the writing queue is not empty.
* enqueue this request immediately */
goto enqueue_data; goto enqueue_data;
} }
return 1; if (dev->dev_cap & MIO_DEV_CAP_STREAM)
{
/* use the do..while() loop to be able to send a zero-length data */
do
{
ulen = urem;
x = dev->dev_mth->sendfile(dev, in_fd, foff, &ulen);
if (x <= -1) return -1;
else if (x == 0)
{
/* [NOTE]
* the write queue is empty at this moment. a zero-length
* request for a stream device can still get enqueued if the
* write callback returns 0 though i can't figure out if there
* is a compelling reason to do so
*/
goto enqueue_data; /* enqueue remaining data */
}
else
{
/* the write callback should return at most the number of requested
* bytes. but returning more is harmless as urem is of a signed type.
* for a zero-length request, it's necessary to return at least 1
* to indicate successful acknowlegement. otherwise, it gets enqueued
* as shown in the 'if' block right above. */
urem -= ulen;
uoff += ulen;
}
}
while (urem > 0);
if (len <= 0) /* original length */
{
/* a zero-length writing request is to close the writing end. this causes further write request to fail */
dev->dev_cap |= MIO_DEV_CAP_OUT_CLOSED;
}
/* if i trigger the write completion callback here, the performance
* may increase, but there can be annoying recursion issues if the
* callback requests another writing operation. it's imperative to
* delay the callback until this write function is finished.
* ---> if (dev->dev_evcb->on_write(dev, len, wrctx, dstaddr) <= -1) return -1; */
goto enqueue_completed_write;
}
else
{
mio_seterrbfmt (mio, MIO_ENOCAPA, "unable to sendfile over a non-stream device");
return -1;
}
return 1; /* written immediately and called on_write callback. but this line will never be reached */
enqueue_data: enqueue_data:
/*return __enqueue_pending_write(dev, len, urem, iov, iovcnt, index, tmout, wrctx, dstaddr);*/ #if 0
iov.iov_ptr = (void*)uptr;
iov.iov_len = urem;
return __enqueue_pending_write(dev, len, urem, &iov, 1, 0, tmout, wrctx, dstaddr);
#else
/* TODO: */
return -1;
#endif
enqueue_completed_write: enqueue_completed_write:
/*return __enqueue_completed_write(dev, len, wrctx, dstaddr);*/ return __enqueue_completed_write(dev, len, wrctx, dstaddr);
#else
return 0; return 0;
#endif
} }
int mio_dev_write (mio_dev_t* dev, const void* data, mio_iolen_t len, void* wrctx, const mio_devaddr_t* dstaddr) int mio_dev_write (mio_dev_t* dev, const void* data, mio_iolen_t len, void* wrctx, const mio_devaddr_t* dstaddr)

View File

@ -195,6 +195,7 @@ struct mio_dev_mth_t
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
int (*write) (mio_dev_t* dev, const void* data, mio_iolen_t* len, const mio_devaddr_t* dstaddr); int (*write) (mio_dev_t* dev, const void* data, mio_iolen_t* len, const mio_devaddr_t* dstaddr);
int (*writev) (mio_dev_t* dev, const mio_iovec_t* iov, mio_iolen_t* iovcnt, const mio_devaddr_t* dstaddr); int (*writev) (mio_dev_t* dev, const mio_iovec_t* iov, mio_iolen_t* iovcnt, const mio_devaddr_t* dstaddr);
int (*sendfile) (mio_dev_t* dev, mio_syshnd_t in_fd, mio_foff_t foff, mio_iolen_t* len);
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
int (*ioctl) (mio_dev_t* dev, int cmd, void* arg); int (*ioctl) (mio_dev_t* dev, int cmd, void* arg);