added mio_foff_t.
adding sendfile support to the core
This commit is contained in:
		@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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' ||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user