From e439c29cb8b5559180553d89e19bf84e30801037 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 17 Jul 2020 15:28:18 +0000 Subject: [PATCH] added mio_foff_t. adding sendfile support to the core --- mio/lib/http-fil.c | 16 +++++----- mio/lib/http.c | 2 +- mio/lib/mio-cmn.h | 29 +++++++++++++++++ mio/lib/mio-http.h | 15 ++------- mio/lib/mio.c | 80 ++++++++++++++++++++++++++++++++++++++++++---- mio/lib/mio.h | 1 + 6 files changed, 115 insertions(+), 28 deletions(-) diff --git a/mio/lib/http-fil.c b/mio/lib/http-fil.c index 8a582b1..bec1aa7 100644 --- a/mio/lib/http-fil.c +++ b/mio/lib/http-fil.c @@ -59,10 +59,10 @@ struct file_state_t mio_oow_t num_pending_writes_to_peer; int peer; - mio_uintmax_t total_size; - mio_uintmax_t start_offset; - mio_uintmax_t end_offset; - mio_uintmax_t cur_offset; + mio_foff_t total_size; + mio_foff_t start_offset; + mio_foff_t end_offset; + mio_foff_t cur_offset; mio_bch_t peer_buf[8192]; 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_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)); @@ -449,8 +449,8 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu (force_close? "close": "keep-alive"), 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 (mio_becs_fcat(cli->sbuf, "Content-Length: %ju\r\n\r\n", 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", (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", (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)); } @@ -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_t* mio = file_state->htts->mio; - mio_uintmax_t lim; + mio_foff_t lim; ssize_t n; if (file_state->cur_offset > file_state->end_offset) diff --git a/mio/lib/http.c b/mio/lib/http.c index db1d960..438c4b3 100644 --- a/mio/lib/http.c +++ b/mio/lib/http.c @@ -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 * like bytes=1-20,30-50 */ - mio_http_range_int_t from, to; + mio_foff_t from, to; int type = MIO_HTTP_RANGE_PROPER; if (str[0] != 'b' || diff --git a/mio/lib/mio-cmn.h b/mio/lib/mio-cmn.h index 9cd2d00..7f8c3ea 100644 --- a/mio/lib/mio-cmn.h +++ b/mio/lib/mio-cmn.h @@ -942,4 +942,33 @@ struct mio_cmgr_t #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 diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index e151565..33d7b18 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -34,17 +34,6 @@ * 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 { 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 { mio_http_range_type_t type; /**< type indicator */ - mio_http_range_int_t from; /**< starting offset */ - mio_http_range_int_t to; /**< ending offset */ + mio_foff_t from; /**< starting offset */ + mio_foff_t to; /**< ending offset */ }; typedef struct mio_http_range_t mio_http_range_t; diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 32fbe43..ba46258 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -1549,30 +1549,98 @@ enqueue_completed_write: 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_foff_t uoff; + mio_iolen_t urem, ulen; + int x; 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; } + uoff = foff; + urem = len; + 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; } - 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: - /*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: - /*return __enqueue_completed_write(dev, len, wrctx, dstaddr);*/ + return __enqueue_completed_write(dev, len, wrctx, dstaddr); +#else 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) diff --git a/mio/lib/mio.h b/mio/lib/mio.h index 244f36b..27b37a2 100644 --- a/mio/lib/mio.h +++ b/mio/lib/mio.h @@ -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 (*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);