From 5471bfbbbe9f49f7be7f2ca92b8c99a02c435458 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 May 2007 15:23:09 +0000 Subject: [PATCH] Data-transfer interface should now be functionally complete. --- src/core/downloader.c | 33 +++++++---- src/core/hw.c | 68 ++++++++++++++++++++++ src/core/xfer.c | 124 +++++++++++++++++++++++++++++----------- src/include/gpxe/xfer.h | 93 +++++++++++++++++++----------- 4 files changed, 244 insertions(+), 74 deletions(-) create mode 100644 src/core/hw.c diff --git a/src/core/downloader.c b/src/core/downloader.c index f539bb68..2e466cbf 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -115,7 +115,7 @@ static void downloader_job_start ( struct job_interface *job ) { container_of ( job, struct downloader, job ); /* Start data transfer */ - xfer_start ( &downloader->xfer ); + xfer_request_all ( &downloader->xfer ); } /** @@ -152,17 +152,30 @@ static struct job_interface_operations downloader_job_operations = { * @v pos New position * @ret rc Return status code */ -static int downloader_xfer_seek ( struct xfer_interface *xfer, size_t pos ) { +static int downloader_xfer_seek ( struct xfer_interface *xfer, off_t offset, + int whence ) { struct downloader *downloader = container_of ( xfer, struct downloader, xfer ); + off_t new_pos; int rc; - /* Ensure that we have enough buffer space for this buffer position */ - if ( ( rc = downloader_ensure_size ( downloader, pos ) ) != 0 ) - return rc; + /* Calculate new buffer position */ + switch ( whence ) { + case SEEK_SET: + new_pos = offset; + break; + case SEEK_CUR: + new_pos = ( downloader->pos + offset ); + break; + default: + assert ( 0 ); + return -EINVAL; + } - /* Update current buffer position */ - downloader->pos = pos; + /* Ensure that we have enough buffer space for this buffer position */ + if ( ( rc = downloader_ensure_size ( downloader, new_pos ) ) != 0 ) + return rc; + downloader->pos = new_pos; return 0; } @@ -216,11 +229,11 @@ static void downloader_xfer_close ( struct xfer_interface *xfer, int rc ) { /** Downloader data transfer interface operations */ static struct xfer_interface_operations downloader_xfer_operations = { - .start = ignore_xfer_start, .close = downloader_xfer_close, - .vredirect = default_xfer_vredirect, + .vredirect = vopen, + .request = ignore_xfer_request, .seek = downloader_xfer_seek, - .deliver = xfer_deliver_as_raw, + .deliver_iob = xfer_deliver_as_raw, .deliver_raw = downloader_xfer_deliver_raw, }; diff --git a/src/core/hw.c b/src/core/hw.c new file mode 100644 index 00000000..80cac99c --- /dev/null +++ b/src/core/hw.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * "Hello World" data source + * + */ + +struct hw { + struct refcnt refcnt; + struct xfer_interface xfer; +}; + +static const char hw_msg[] = "Hello world!\n"; + +static void hw_finished ( struct hw *hw, int rc ) { + xfer_nullify ( &hw->xfer ); + xfer_close ( &hw->xfer, rc ); + ref_put ( &hw->refcnt ); +} + +static void hw_xfer_close ( struct xfer_interface *xfer, int rc ) { + struct hw *hw = container_of ( xfer, struct hw, xfer ); + + hw_finished ( hw, rc ); +} + +static int hw_xfer_request ( struct xfer_interface *xfer, off_t start __unused, + int whence __unused, size_t len __unused ) { + struct hw *hw = container_of ( xfer, struct hw, xfer ); + + xfer_deliver_raw ( xfer, hw_msg, sizeof ( hw_msg ) ); + hw_finished ( hw, 0 ); + return 0; +} + +static struct xfer_interface_operations hw_xfer_operations = { + .close = hw_xfer_close, + .vredirect = ignore_xfer_vredirect, + .request = hw_xfer_request, + .seek = ignore_xfer_seek, + .deliver_iob = xfer_deliver_as_raw, + .deliver_raw = ignore_xfer_deliver_raw, +}; + +static int hw_open ( struct xfer_interface *xfer, struct uri *uri __unused ) { + struct hw *hw; + + hw = malloc ( sizeof ( *hw ) ); + if ( ! hw ) + return -ENOMEM; + memset ( hw, 0, sizeof ( *hw ) ); + xfer_init ( &hw->xfer, &hw_xfer_operations, &hw->refcnt ); + + xfer_plug_plug ( &hw->xfer, xfer ); + return 0; +} + +struct uri_opener hw_uri_opener __uri_opener = { + .scheme = "hw", + .open = hw_open, +}; diff --git a/src/core/xfer.c b/src/core/xfer.c index 8a5d03d8..bfbf1ced 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -39,19 +39,6 @@ void xfer_close ( struct xfer_interface *xfer, int rc ) { xfer_unplug ( xfer ); } -/** - * Seek to position - * - * @v xfer Data transfer interface - * @v pos New position - * @ret rc Return status code - */ -int xfer_seek ( struct xfer_interface *xfer, size_t pos ) { - struct xfer_interface *dest = xfer_dest ( xfer ); - - return dest->op->seek ( dest, pos ); -} - /** * Send redirection event * @@ -84,6 +71,59 @@ int xfer_redirect ( struct xfer_interface *xfer, int type, ... ) { return rc; } +/** + * Request data + * + * @v xfer Data transfer interface + * @v offset Offset to new position + * @v whence Basis for new position + * @v len Length of requested data + * @ret rc Return status code + */ +int xfer_request ( struct xfer_interface *xfer, off_t offset, int whence, + size_t len ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->request ( dest, offset, whence, len ); +} + +/** + * Request all data + * + * @v xfer Data transfer interface + * @ret rc Return status code + */ +int xfer_request_all ( struct xfer_interface *xfer ) { + return xfer_request ( xfer, 0, SEEK_SET, ~( ( size_t ) 0 ) ); +} + +/** + * Seek to position + * + * @v xfer Data transfer interface + * @v offset Offset to new position + * @v whence Basis for new position + * @ret rc Return status code + */ +int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->seek ( dest, offset, whence ); +} + +/** + * Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->alloc_iob ( dest, len ); +} + /** * Deliver datagram * @@ -91,10 +131,10 @@ int xfer_redirect ( struct xfer_interface *xfer, int type, ... ) { * @v iobuf Datagram I/O buffer * @ret rc Return status code */ -int xfer_deliver ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { +int xfer_deliver_iob ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { struct xfer_interface *dest = xfer_dest ( xfer ); - return dest->op->deliver ( dest, iobuf ); + return dest->op->deliver_iob ( dest, iobuf ); } /** @@ -120,15 +160,6 @@ int xfer_deliver_raw ( struct xfer_interface *xfer, * */ -/** - * Ignore start() event - * - * @v xfer Data transfer interface - */ -void ignore_xfer_start ( struct xfer_interface *xfer __unused ) { - /* Nothing to do */ -} - /** * Ignore close() event * @@ -153,18 +184,46 @@ int ignore_xfer_vredirect ( struct xfer_interface *xfer __unused, return 0; } +/** + * Ignore request() event + * + * @v xfer Data transfer interface + * @v offset Offset to new position + * @v whence Basis for new position + * @v len Length of requested data + * @ret rc Return status code + */ +int ignore_xfer_request ( struct xfer_interface *xfer __unused, + off_t offset __unused, int whence __unused, + size_t len __unused ) { + return 0; +} + /** * Ignore seek() event * * @v xfer Data transfer interface - * @v pos New position + * @v offset Offset to new position + * @v whence Basis for new position * @ret rc Return status code */ int ignore_xfer_seek ( struct xfer_interface *xfer __unused, - size_t pos __unused ) { + off_t offset __unused, int whence __unused ) { return 0; } +/** + * Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +struct io_buffer * +default_xfer_alloc_iob ( struct xfer_interface *xfer __unused, size_t len ) { + return alloc_iob ( len ); +} + /** * Deliver datagram as raw data * @@ -195,16 +254,16 @@ int xfer_deliver_as_raw ( struct xfer_interface *xfer, * This function is intended to be used as the deliver_raw() method * for data transfer interfaces that prefer to handle I/O buffers. */ -int xfer_deliver_as_iobuf ( struct xfer_interface *xfer, - const void *data, size_t len ) { +int xfer_deliver_as_iob ( struct xfer_interface *xfer, + const void *data, size_t len ) { struct io_buffer *iobuf; - iobuf = alloc_iob ( len ); + iobuf = xfer->op->alloc_iob ( xfer, len ); if ( ! iobuf ) return -ENOMEM; memcpy ( iob_put ( iobuf, len ), data, len ); - return xfer->op->deliver ( xfer, iobuf ); + return xfer->op->deliver_iob ( xfer, iobuf ); } /** @@ -225,11 +284,12 @@ int ignore_xfer_deliver_raw ( struct xfer_interface *xfer, /** Null data transfer interface operations */ struct xfer_interface_operations null_xfer_ops = { - .start = ignore_xfer_start, .close = ignore_xfer_close, .vredirect = ignore_xfer_vredirect, + .request = ignore_xfer_request, .seek = ignore_xfer_seek, - .deliver = xfer_deliver_as_raw, + .alloc_iob = default_xfer_alloc_iob, + .deliver_iob = xfer_deliver_as_raw, .deliver_raw = ignore_xfer_deliver_raw, }; diff --git a/src/include/gpxe/xfer.h b/src/include/gpxe/xfer.h index 61f5d86c..4fb3a519 100644 --- a/src/include/gpxe/xfer.h +++ b/src/include/gpxe/xfer.h @@ -16,22 +16,6 @@ struct xfer_interface; /** Data transfer interface operations */ struct xfer_interface_operations { - - /* Missing features: - * - * notification of non-close status - e.g. connected/opened, ... - * - * prompt for data delivery - * - * I/O buffer preparation - * - */ - - /** Start data transfer - * - * @v xfer Data transfer interface - */ - void ( * start ) ( struct xfer_interface *xfer ); /** Close interface * * @v xfer Data transfer interface @@ -47,14 +31,39 @@ struct xfer_interface_operations { */ int ( * vredirect ) ( struct xfer_interface *xfer, int type, va_list args ); + /** Request data + * + * @v xfer Data transfer interface + * @v offset Offset to new position + * @v whence Basis for new position + * @v len Length of requested data + * @ret rc Return status code + */ + int ( * request ) ( struct xfer_interface *xfer, off_t offset, + int whence, size_t len ); /** Seek to position * * @v xfer Data transfer interface - * @v pos New position + * @v offset Offset to new position + * @v whence Basis for new position * @ret rc Return status code + * + * @c whence must be one of @c SEEK_SET or @c SEEK_CUR. A + * successful return indicates that the interface is ready to + * immediately accept datagrams; return -EAGAIN if this is not + * the case. */ - int ( * seek ) ( struct xfer_interface *xfer, size_t pos ); - /** Deliver datagram + int ( * seek ) ( struct xfer_interface *xfer, off_t offset, + int whence ); + /** Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ + struct io_buffer * ( * alloc_iob ) ( struct xfer_interface *xfer, + size_t len ); + /** Deliver datagram as I/O buffer * * @v xfer Data transfer interface * @v iobuf Datagram I/O buffer @@ -63,9 +72,13 @@ struct xfer_interface_operations { * A data transfer interface that wishes to support only raw * data delivery should set this method to * xfer_deliver_as_raw(). + * + * Interfaces may not temporarily refuse to accept data by + * returning -EAGAIN; such a response may be treated as a + * fatal error. */ - int ( * deliver ) ( struct xfer_interface *xfer, - struct io_buffer *iobuf ); + int ( * deliver_iob ) ( struct xfer_interface *xfer, + struct io_buffer *iobuf ); /** Deliver datagram as raw data * * @v xfer Data transfer interface @@ -75,7 +88,11 @@ struct xfer_interface_operations { * * A data transfer interface that wishes to support only I/O * buffer delivery should set this method to - * xfer_deliver_as_iobuf(). + * xfer_deliver_as_iob(). + * + * Interfaces may not temporarily refuse to accept data by + * returning -EAGAIN; such a response may be treated as a + * fatal error. */ int ( * deliver_raw ) ( struct xfer_interface *xfer, const void *data, size_t len ); @@ -89,31 +106,43 @@ struct xfer_interface { struct xfer_interface_operations *op; }; +/** Basis positions for seek() events */ +enum seek_whence { + SEEK_SET = 0, + SEEK_CUR, +}; + extern struct xfer_interface null_xfer; extern struct xfer_interface_operations null_xfer_ops; -extern void xfer_start ( struct xfer_interface *xfer ); extern void xfer_close ( struct xfer_interface *xfer, int rc ); -extern int xfer_seek ( struct xfer_interface *xfer, size_t pos ); extern int xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ); extern int xfer_redirect ( struct xfer_interface *xfer, int type, ... ); -extern int xfer_deliver ( struct xfer_interface *xfer, - struct io_buffer *iobuf ); +extern int xfer_request ( struct xfer_interface *xfer, off_t offset, + int whence, size_t len ); +extern int xfer_request_all ( struct xfer_interface *xfer ); +extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ); +extern struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, + size_t len ); +extern int xfer_deliver_iob ( struct xfer_interface *xfer, + struct io_buffer *iobuf ); extern int xfer_deliver_raw ( struct xfer_interface *xfer, const void *data, size_t len ); -extern void ignore_xfer_start ( struct xfer_interface *xfer ); extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc ); extern int ignore_xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ); -extern int default_xfer_vredirect ( struct xfer_interface *xfer, - int type, va_list args ); -extern int ignore_xfer_seek ( struct xfer_interface *xfer, size_t pos ); +extern int ignore_xfer_request ( struct xfer_interface *xfer, off_t offset, + int whence, size_t len ); +extern int ignore_xfer_seek ( struct xfer_interface *xfer, off_t offset, + int whence ); +extern struct io_buffer * default_xfer_alloc_iob ( struct xfer_interface *xfer, + size_t len ); extern int xfer_deliver_as_raw ( struct xfer_interface *xfer, struct io_buffer *iobuf ); -extern int xfer_deliver_as_iobuf ( struct xfer_interface *xfer, - const void *data, size_t len ); +extern int xfer_deliver_as_iob ( struct xfer_interface *xfer, + const void *data, size_t len ); extern int ignore_xfer_deliver_raw ( struct xfer_interface *xfer, const void *data __unused, size_t len );