diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/asprintf.c | 47 | ||||
| -rw-r--r-- | src/core/basename.c | 22 | ||||
| -rw-r--r-- | src/core/download.c | 4 | ||||
| -rw-r--r-- | src/core/downloader.c | 15 | ||||
| -rw-r--r-- | src/core/hw.c | 27 | ||||
| -rw-r--r-- | src/core/open.c | 33 | ||||
| -rw-r--r-- | src/core/posix_io.c | 13 | ||||
| -rw-r--r-- | src/core/process.c | 26 | ||||
| -rw-r--r-- | src/core/refcnt.c | 8 | ||||
| -rw-r--r-- | src/core/uri.c | 241 | ||||
| -rw-r--r-- | src/core/vsprintf.c | 39 | ||||
| -rw-r--r-- | src/core/xfer.c | 113 |
12 files changed, 501 insertions, 87 deletions
diff --git a/src/core/asprintf.c b/src/core/asprintf.c new file mode 100644 index 000000000..94d7e7c43 --- /dev/null +++ b/src/core/asprintf.c @@ -0,0 +1,47 @@ +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +/** + * Write a formatted string to newly allocated memory. + * + * @v strp Pointer to hold allocated string + * @v fmt Format string + * @v args Arguments corresponding to the format string + * @ret len Length of formatted string + */ +int vasprintf ( char **strp, const char *fmt, va_list args ) { + size_t len; + va_list args_tmp; + + /* Calculate length needed for string */ + va_copy ( args_tmp, args ); + len = ( vsnprintf ( NULL, 0, fmt, args_tmp ) + 1 ); + va_end ( args_tmp ); + + /* Allocate and fill string */ + *strp = malloc ( len ); + if ( ! *strp ) + return -ENOMEM; + return vsnprintf ( *strp, len, fmt, args ); +} + +/** + * Write a formatted string to newly allocated memory. + * + * @v strp Pointer to hold allocated string + * @v fmt Format string + * @v ... Arguments corresponding to the format string + * @ret len Length of formatted string + */ +int asprintf ( char **strp, const char *fmt, ... ) { + va_list args; + int len; + + va_start ( args, fmt ); + len = vasprintf ( strp, fmt, args ); + va_end ( args ); + return len; +} diff --git a/src/core/basename.c b/src/core/basename.c index f50b71513..7340c0d55 100644 --- a/src/core/basename.c +++ b/src/core/basename.c @@ -38,3 +38,25 @@ char * basename ( char *path ) { basename = strrchr ( path, '/' ); return ( basename ? ( basename + 1 ) : path ); } + +/** + * Return directory name from path + * + * @v path Full path + * @ret dirname Directory name + * + * Note that this function may modify its argument. + */ +char * dirname ( char *path ) { + char *separator; + + separator = strrchr ( path, '/' ); + if ( separator == path ) { + return "/"; + } else if ( separator ) { + *separator = 0; + return path; + } else { + return "."; + } +} diff --git a/src/core/download.c b/src/core/download.c index 4522bf2c8..e3f77794f 100644 --- a/src/core/download.c +++ b/src/core/download.c @@ -121,7 +121,7 @@ int start_download ( const char *uri_string, struct async *parent, err: async_uninit ( &download->async ); ufree ( download->buffer.addr ); - free_uri ( download->uri ); + uri_put ( download->uri ); free ( download ); return rc; } @@ -150,7 +150,7 @@ static void download_sigchld ( struct async *async, /* Discard the buffer */ ufree ( download->buffer.addr ); } - free_uri ( download->uri ); + uri_put ( download->uri ); download->uri = NULL; /* Terminate ourselves */ diff --git a/src/core/downloader.c b/src/core/downloader.c index 2f28bc953..15ef962d3 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -115,19 +115,6 @@ static int downloader_ensure_size ( struct downloader *downloader, */ /** - * Handle start() event received via job control interface - * - * @v job Downloader job control interface - */ -static void downloader_job_start ( struct job_interface *job ) { - struct downloader *downloader = - container_of ( job, struct downloader, job ); - - /* Start data transfer */ - xfer_request_all ( &downloader->xfer ); -} - -/** * Handle kill() event received via job control interface * * @v job Downloader job control interface @@ -142,7 +129,7 @@ static void downloader_job_kill ( struct job_interface *job ) { /** Downloader job control interface operations */ static struct job_interface_operations downloader_job_operations = { - .start = downloader_job_start, + .start = ignore_job_start, .done = ignore_job_done, .kill = downloader_job_kill, .progress = ignore_job_progress, diff --git a/src/core/hw.c b/src/core/hw.c index 77b39ba1a..a3eb85007 100644 --- a/src/core/hw.c +++ b/src/core/hw.c @@ -3,6 +3,7 @@ #include <string.h> #include <errno.h> #include <gpxe/refcnt.h> +#include <gpxe/process.h> #include <gpxe/xfer.h> #include <gpxe/open.h> @@ -15,6 +16,7 @@ struct hw { struct refcnt refcnt; struct xfer_interface xfer; + struct process process; }; static const char hw_msg[] = "Hello world!\n"; @@ -22,6 +24,7 @@ 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 ); + process_del ( &hw->process ); } static void hw_xfer_close ( struct xfer_interface *xfer, int rc ) { @@ -30,26 +33,25 @@ static void hw_xfer_close ( struct xfer_interface *xfer, int rc ) { 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 ); - int rc; - - rc = xfer_deliver_raw ( xfer, hw_msg, sizeof ( hw_msg ) ); - hw_finished ( hw, rc ); - return 0; -} - static struct xfer_interface_operations hw_xfer_operations = { .close = hw_xfer_close, .vredirect = ignore_xfer_vredirect, - .request = hw_xfer_request, + .request = ignore_xfer_request, .seek = ignore_xfer_seek, .deliver_iob = xfer_deliver_as_raw, .deliver_raw = ignore_xfer_deliver_raw, }; +static void hw_step ( struct process *process ) { + struct hw *hw = container_of ( process, struct hw, process ); + int rc; + + if ( xfer_ready ( &hw->xfer ) == 0 ) { + rc = xfer_deliver_raw ( &hw->xfer, hw_msg, sizeof ( hw_msg ) ); + hw_finished ( hw, rc ); + } +} + static int hw_open ( struct xfer_interface *xfer, struct uri *uri __unused ) { struct hw *hw; @@ -59,6 +61,7 @@ static int hw_open ( struct xfer_interface *xfer, struct uri *uri __unused ) { return -ENOMEM; memset ( hw, 0, sizeof ( *hw ) ); xfer_init ( &hw->xfer, &hw_xfer_operations, &hw->refcnt ); + process_init ( &hw->process, hw_step, &hw->refcnt ); /* Attach parent interface, mortalise self, and return */ xfer_plug_plug ( &hw->xfer, xfer ); diff --git a/src/core/open.c b/src/core/open.c index 284d00a98..6c184e653 100644 --- a/src/core/open.c +++ b/src/core/open.c @@ -52,6 +52,7 @@ static struct socket_opener socket_openers_end[0] int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ) { struct uri *uri; struct uri_opener *opener; + int rc = -ENOTSUP; DBGC ( xfer, "XFER %p opening URI %s\n", xfer, uri_string ); @@ -61,44 +62,45 @@ int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ) { for ( opener = uri_openers ; opener < uri_openers_end ; opener++ ) { if ( strcmp ( uri->scheme, opener->scheme ) == 0 ) { - return opener->open ( xfer, uri ); + rc = opener->open ( xfer, uri ); + goto done; } } DBGC ( xfer, "XFER %p attempted to open unsupported URI scheme " "\"%s\"\n", xfer, uri->scheme ); - free_uri ( uri ); - return -ENOTSUP; + done: + uri_put ( uri ); + return rc; } /** * Open socket * * @v xfer Data transfer interface - * @v domain Communication domain (e.g. PF_INET) - * @v type Communication semantics (e.g. SOCK_STREAM) + * @v semantics Communication semantics (e.g. SOCK_STREAM) * @v peer Peer socket address * @v local Local socket address, or NULL * @ret rc Return status code */ -int xfer_open_socket ( struct xfer_interface *xfer, - int domain, int type, struct sockaddr *peer, - struct sockaddr *local ) { +int xfer_open_socket ( struct xfer_interface *xfer, int semantics, + struct sockaddr *peer, struct sockaddr *local ) { struct socket_opener *opener; DBGC ( xfer, "XFER %p opening (%s,%s) socket\n", xfer, - socket_domain_name ( domain ), socket_type_name ( type ) ); + socket_semantics_name ( semantics ), + socket_family_name ( peer->sa_family ) ); for ( opener = socket_openers; opener < socket_openers_end; opener++ ){ - if ( ( opener->domain == domain ) && - ( opener->type == type ) ) { + if ( ( opener->semantics == semantics ) && + ( opener->family == peer->sa_family ) ) { return opener->open ( xfer, peer, local ); } } DBGC ( xfer, "XFER %p attempted to open unsupported socket type " - "(%s,%s)\n", xfer, socket_domain_name ( domain ), - socket_type_name ( type ) ); + "(%s,%s)\n", xfer, socket_semantics_name ( semantics ), + socket_family_name ( peer->sa_family ) ); return -ENOTSUP; } @@ -117,12 +119,11 @@ int xfer_vopen ( struct xfer_interface *xfer, int type, va_list args ) { return xfer_open_uri ( xfer, uri_string ); } case LOCATION_SOCKET: { - int domain = va_arg ( args, int ); - int type = va_arg ( args, int ); + int semantics = va_arg ( args, int ); struct sockaddr *peer = va_arg ( args, struct sockaddr * ); struct sockaddr *local = va_arg ( args, struct sockaddr * ); - return xfer_open_socket ( xfer, domain, type, peer, local ); } + return xfer_open_socket ( xfer, semantics, peer, local ); } default: DBGC ( xfer, "XFER %p attempted to open unsupported location " "type %d\n", xfer, type ); diff --git a/src/core/posix_io.c b/src/core/posix_io.c index b98766f8d..3b5660e4f 100644 --- a/src/core/posix_io.c +++ b/src/core/posix_io.c @@ -78,6 +78,7 @@ static void posix_file_free ( struct refcnt *refcnt ) { struct io_buffer *tmp; list_for_each_entry_safe ( iobuf, tmp, &file->data, list ) { + list_del ( &iobuf->list ); free_iob ( iobuf ); } free ( file ); @@ -190,6 +191,7 @@ static int posix_find_free_fd ( void ) { if ( ! posix_fd_to_file ( fd ) ) return fd; } + DBG ( "POSIX could not find free file descriptor\n" ); return -ENFILE; } @@ -225,13 +227,11 @@ int open ( const char *uri_string ) { if ( ( rc = xfer_open_uri ( &file->xfer, uri_string ) ) != 0 ) goto err; - /* Request data */ - if ( ( rc = xfer_request_all ( &file->xfer ) ) != 0 ) - goto err; - /* Wait for open to succeed or fail */ while ( list_empty ( &file->data ) ) { step(); + if ( file->rc == 0 ) + break; if ( file->rc != -EINPROGRESS ) { rc = file->rc; goto err; @@ -240,6 +240,7 @@ int open ( const char *uri_string ) { /* Add to list of open files. List takes reference ownership. */ list_add ( &file->list, &posix_files ); + DBG ( "POSIX opened %s as file %d\n", uri_string, fd ); return fd; err: @@ -279,8 +280,10 @@ ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) { copy_to_user ( buffer, offset, iobuf->data, frag_len ); iob_pull ( iobuf, frag_len ); - if ( ! iob_len ( iobuf ) ) + if ( ! iob_len ( iobuf ) ) { + list_del ( &iobuf-> list ); free_iob ( iobuf ); + } file->pos += frag_len; len += frag_len; offset += frag_len; diff --git a/src/core/process.c b/src/core/process.c index c087f16d8..0583a398c 100644 --- a/src/core/process.c +++ b/src/core/process.c @@ -31,25 +31,43 @@ static LIST_HEAD ( run_queue ); /** - * Add process to run queue + * Add process to process list * * @v process Process */ -void schedule ( struct process *process ) { +void process_add ( struct process *process ) { + ref_get ( process->refcnt ); list_add_tail ( &process->list, &run_queue ); } /** + * Remove process from process list + * + * @v process Process + * + * It is safe to call process_del() multiple times; further calls will + * have no effect. + */ +void process_del ( struct process *process ) { + if ( ! list_empty ( &process->list ) ) { + list_del ( &process->list ); + INIT_LIST_HEAD ( &process->list ); + ref_put ( process->refcnt ); + } +} + +/** * Single-step a single process * - * This removes the first process from the run queue and executes a - * single step of that process. + * This executes a single step of the first process in the run queue, + * and moves the process to the end of the run queue. */ void step ( void ) { struct process *process; list_for_each_entry ( process, &run_queue, list ) { list_del ( &process->list ); + list_add_tail ( &process->list, &run_queue ); process->step ( process ); break; } diff --git a/src/core/refcnt.c b/src/core/refcnt.c index 227dac3f8..36b7ce22a 100644 --- a/src/core/refcnt.c +++ b/src/core/refcnt.c @@ -39,8 +39,8 @@ void ref_get ( struct refcnt *refcnt ) { refcnt->refcnt++; - DBGC ( refcnt, "REFCNT %p incremented to %d\n", - refcnt, refcnt->refcnt ); + DBGC2 ( refcnt, "REFCNT %p incremented to %d\n", + refcnt, refcnt->refcnt ); } /** @@ -59,8 +59,8 @@ void ref_put ( struct refcnt *refcnt ) { return; refcnt->refcnt--; - DBGC ( refcnt, "REFCNT %p decremented to %d\n", - refcnt, refcnt->refcnt ); + DBGC2 ( refcnt, "REFCNT %p decremented to %d\n", + refcnt, refcnt->refcnt ); if ( refcnt->refcnt >= 0 ) return; diff --git a/src/core/uri.c b/src/core/uri.c index cb1ac3bcb..a793c4577 100644 --- a/src/core/uri.c +++ b/src/core/uri.c @@ -25,9 +25,37 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <libgen.h> +#include <gpxe/vsprintf.h> #include <gpxe/uri.h> /** + * Dump URI for debugging + * + * @v uri URI + */ +static void dump_uri ( struct uri *uri ) { + if ( uri->scheme ) + DBG ( " scheme \"%s\"", uri->scheme ); + if ( uri->opaque ) + DBG ( " opaque \"%s\"", uri->opaque ); + if ( uri->user ) + DBG ( " user \"%s\"", uri->user ); + if ( uri->password ) + DBG ( " password \"%s\"", uri->password ); + if ( uri->host ) + DBG ( " host \"%s\"", uri->host ); + if ( uri->port ) + DBG ( " port \"%s\"", uri->port ); + if ( uri->path ) + DBG ( " path \"%s\"", uri->path ); + if ( uri->query ) + DBG ( " query \"%s\"", uri->query ); + if ( uri->fragment ) + DBG ( " fragment \"%s\"", uri->fragment ); +} + +/** * Parse URI * * @v uri_string URI as a string @@ -35,7 +63,7 @@ * * Splits a URI into its component parts. The return URI structure is * dynamically allocated and must eventually be freed by calling - * free_uri(). + * uri_put(). */ struct uri * parse_uri ( const char *uri_string ) { struct uri *uri; @@ -136,25 +164,8 @@ struct uri * parse_uri ( const char *uri_string ) { } done: - DBG ( "URI \"%s\" split into", raw ); - if ( uri->scheme ) - DBG ( " scheme \"%s\"", uri->scheme ); - if ( uri->opaque ) - DBG ( " opaque \"%s\"", uri->opaque ); - if ( uri->user ) - DBG ( " user \"%s\"", uri->user ); - if ( uri->password ) - DBG ( " password \"%s\"", uri->password ); - if ( uri->host ) - DBG ( " host \"%s\"", uri->host ); - if ( uri->port ) - DBG ( " port \"%s\"", uri->port ); - if ( uri->path ) - DBG ( " path \"%s\"", uri->path ); - if ( uri->query ) - DBG ( " query \"%s\"", uri->query ); - if ( uri->fragment ) - DBG ( " fragment \"%s\"", uri->fragment ); + DBG ( "URI \"%s\" split into", uri_string ); + dump_uri ( uri ); DBG ( "\n" ); return uri; @@ -170,3 +181,193 @@ struct uri * parse_uri ( const char *uri_string ) { unsigned int uri_port ( struct uri *uri, unsigned int default_port ) { return ( uri->port ? strtoul ( uri->port, NULL, 0 ) : default_port ); } + +/** + * Unparse URI + * + * @v buf Buffer to fill with URI string + * @v size Size of buffer + * @v uri URI to write into buffer + * @ret len Length of URI string + */ +int unparse_uri ( char *buf, size_t size, struct uri *uri ) { + int used = 0; + + DBG ( "URI unparsing" ); + dump_uri ( uri ); + DBG ( "\n" ); + + /* Special-case opaque URIs */ + if ( uri->opaque ) { + return ssnprintf ( ( buf + used ), ( size - used ), + "%s:%s", uri->scheme, uri->opaque ); + } + + /* scheme:// */ + if ( uri->scheme ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s://", uri->scheme ); + } + + /* [user[:password]@]host[:port] */ + if ( uri->host ) { + if ( uri->user ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s", uri->user ); + if ( uri->password ) { + used += ssnprintf ( ( buf + used ), + ( size - used ), + ":%s", uri->password ); + } + used += ssnprintf ( ( buf + used ), ( size - used ), + "@" ); + } + used += ssnprintf ( ( buf + used ), ( size - used ), "%s", + uri->host ); + if ( uri->port ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + ":%s", uri->port ); + } + } + + /* /path */ + if ( uri->path ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "%s", uri->path ); + } + + /* ?query */ + if ( uri->query ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "?%s", uri->query ); + } + + /* #fragment */ + if ( uri->fragment ) { + used += ssnprintf ( ( buf + used ), ( size - used ), + "#%s", uri->fragment ); + } + + return used; +} + +/** + * Duplicate URI + * + * @v uri URI + * @ret uri Duplicate URI + * + * Creates a modifiable copy of a URI. + */ +struct uri * uri_dup ( struct uri *uri ) { + size_t len = ( unparse_uri ( NULL, 0, uri ) + 1 ); + char buf[len]; + + unparse_uri ( buf, len, uri ); + return parse_uri ( buf ); +} + +/** + * Resolve base+relative path + * + * @v base_uri Base path + * @v relative_uri Relative path + * @ret resolved_uri Resolved path + * + * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative + * path (e.g. "initrd.gz") and produces a new path + * (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory + * portion of the base path will automatically be stripped; this + * matches the semantics used when resolving the path component of + * URIs. + */ +char * resolve_path ( const char *base_path, + const char *relative_path ) { + size_t base_len = ( strlen ( base_path ) + 1 ); + char base_path_copy[base_len]; + char *base_tmp = base_path_copy; + char *resolved; + + /* If relative path is absolute, just re-use it */ + if ( relative_path[0] == '/' ) + return strdup ( relative_path ); + + /* Create modifiable copy of path for dirname() */ + memcpy ( base_tmp, base_path, base_len ); + base_tmp = dirname ( base_tmp ); + + /* Process "./" and "../" elements */ + while ( *relative_path == '.' ) { + relative_path++; + if ( *relative_path == 0 ) { + /* Do nothing */ + } else if ( *relative_path == '/' ) { + relative_path++; + } else if ( *relative_path == '.' ) { + relative_path++; + if ( *relative_path == 0 ) { + base_tmp = dirname ( base_tmp ); + } else if ( *relative_path == '/' ) { + base_tmp = dirname ( base_tmp ); + relative_path++; + } else { + relative_path -= 2; + break; + } + } else { + relative_path--; + break; + } + } + + /* Create and return new path */ + if ( asprintf ( &resolved, "%s%s%s", base_tmp, + ( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ? + "" : "/" ), relative_path ) < 0 ) + return NULL; + + return resolved; +} + +/** + * Resolve base+relative URI + * + * @v base_uri Base URI + * @v relative_uri Relative URI + * @ret resolved_uri Resolved URI + * + * Takes a base URI (e.g. "http://etherboot.org/kernels/vmlinuz" and a + * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI + * (e.g. "http://etherboot.org/initrds/initrd.gz"). + */ +struct uri * resolve_uri ( struct uri *base_uri, + struct uri *relative_uri ) { + struct uri tmp_uri; + char *tmp_path = NULL; + struct uri *new_uri; + + /* If relative URI is absolute, just re-use it */ + if ( uri_is_absolute ( relative_uri ) ) + return uri_get ( relative_uri ); + + /* Mangle URI */ + memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) ); + if ( relative_uri->path ) { + tmp_path = resolve_path ( ( base_uri->path ? + base_uri->path : "/" ), + relative_uri->path ); + tmp_uri.path = tmp_path; + tmp_uri.query = relative_uri->query; + tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->query ) { + tmp_uri.query = relative_uri->query; + tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->fragment ) { + tmp_uri.fragment = relative_uri->fragment; + } + + /* Create demangled URI */ + new_uri = uri_dup ( &tmp_uri ); + free ( tmp_path ); + return new_uri; +} diff --git a/src/core/vsprintf.c b/src/core/vsprintf.c index e6f072e7b..4457fe4f4 100644 --- a/src/core/vsprintf.c +++ b/src/core/vsprintf.c @@ -339,6 +339,45 @@ int snprintf ( char *buf, size_t size, const char *fmt, ... ) { } /** + * Version of vsnprintf() that accepts a signed buffer size + * + * @v buf Buffer into which to write the string + * @v size Size of buffer + * @v fmt Format string + * @v args Arguments corresponding to the format string + * @ret len Length of formatted string + */ +int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) { + + /* Treat negative buffer size as zero buffer size */ + if ( ssize < 0 ) + ssize = 0; + + /* Hand off to vsnprintf */ + return vsnprintf ( buf, ssize, fmt, args ); +} + +/** + * Version of vsnprintf() that accepts a signed buffer size + * + * @v buf Buffer into which to write the string + * @v size Size of buffer + * @v fmt Format string + * @v ... Arguments corresponding to the format string + * @ret len Length of formatted string + */ +int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) { + va_list args; + int len; + + /* Hand off to vssnprintf */ + va_start ( args, fmt ); + len = vssnprintf ( buf, ssize, fmt, args ); + va_end ( args ); + return len; +} + +/** * Write character to console * * @v ctx Context diff --git a/src/core/xfer.c b/src/core/xfer.c index f2783f5bd..ea5fda3d6 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -17,6 +17,7 @@ */ #include <string.h> +#include <stdio.h> #include <errno.h> #include <gpxe/xfer.h> @@ -35,6 +36,8 @@ void xfer_close ( struct xfer_interface *xfer, int rc ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); + DBGC ( xfer, "XFER %p->%p close\n", xfer, dest ); + dest->op->close ( dest, rc ); xfer_unplug ( xfer ); xfer_put ( dest ); @@ -52,7 +55,14 @@ int xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); int rc; + DBGC ( xfer, "XFER %p->%p redirect\n", xfer, dest ); + rc = dest->op->vredirect ( dest, type, args ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p redirect: %s\n", xfer, dest, + strerror ( rc ) ); + } xfer_put ( dest ); return rc; } @@ -89,22 +99,20 @@ int xfer_request ( struct xfer_interface *xfer, off_t offset, int whence, struct xfer_interface *dest = xfer_get_dest ( xfer ); int rc; + DBGC ( xfer, "XFER %p->%p request %s+%ld %zd\n", xfer, dest, + whence_text ( whence ), offset, len ); + rc = dest->op->request ( dest, offset, whence, len ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p request: %s\n", xfer, dest, + strerror ( rc ) ); + } xfer_put ( dest ); return rc; } /** - * 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 @@ -116,12 +124,34 @@ int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); int rc; + DBGC ( xfer, "XFER %p->%p seek %s+%ld\n", xfer, dest, + whence_text ( whence ), offset ); + rc = dest->op->seek ( dest, offset, whence ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p seek: %s\n", xfer, dest, + strerror ( rc ) ); + } xfer_put ( dest ); return rc; } /** + * Test to see if interface is ready to accept data + * + * @v xfer Data transfer interface + * @ret rc Return status code + * + * This test is optional; the data transfer interface may wish that it + * does not yet wish to accept data, but cannot prevent attempts to + * deliver data to it. + */ +int xfer_ready ( struct xfer_interface *xfer ) { + return xfer_seek ( xfer, 0, SEEK_CUR ); +} + +/** * Allocate I/O buffer * * @v xfer Data transfer interface @@ -132,7 +162,13 @@ struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); struct io_buffer *iobuf; + DBGC ( xfer, "XFER %p->%p alloc_iob %zd\n", xfer, dest, len ); + iobuf = dest->op->alloc_iob ( dest, len ); + + if ( ! iobuf ) { + DBGC ( xfer, "XFER %p<-%p alloc_iob failed\n", xfer, dest ); + } xfer_put ( dest ); return iobuf; } @@ -148,7 +184,15 @@ int xfer_deliver_iob ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); int rc; + DBGC ( xfer, "XFER %p->%p deliver_iob %zd\n", xfer, dest, + iob_len ( iobuf ) ); + rc = dest->op->deliver_iob ( dest, iobuf ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p deliver_iob: %s\n", xfer, dest, + strerror ( rc ) ); + } xfer_put ( dest ); return rc; } @@ -165,11 +209,60 @@ int xfer_deliver_raw ( struct xfer_interface *xfer, struct xfer_interface *dest = xfer_get_dest ( xfer ); int rc; + DBGC ( xfer, "XFER %p->%p deliver_raw %p+%zd\n", xfer, dest, + data, len ); + rc = dest->op->deliver_raw ( dest, data, len ); + + if ( rc != 0 ) { + DBGC ( xfer, "XFER %p<-%p deliver_raw: %s\n", xfer, dest, + strerror ( rc ) ); + } xfer_put ( dest ); return rc; } +/** + * Deliver formatted string + * + * @v xfer Data transfer interface + * @v format Format string + * @v args Arguments corresponding to the format string + * @ret rc Return status code + */ +int xfer_vprintf ( struct xfer_interface *xfer, const char *format, + va_list args ) { + size_t len; + va_list args_tmp; + + va_copy ( args_tmp, args ); + len = vsnprintf ( NULL, 0, format, args ); + { + char buf[len + 1]; + vsnprintf ( buf, sizeof ( buf ), format, args_tmp ); + va_end ( args_tmp ); + return xfer_deliver_raw ( xfer, buf, len ); + } +} + +/** + * Deliver formatted string + * + * @v xfer Data transfer interface + * @v format Format string + * @v ... Arguments corresponding to the format string + * @ret rc Return status code + */ +int xfer_printf ( struct xfer_interface *xfer, const char *format, ... ) { + va_list args; + int rc; + + va_start ( args, format ); + rc = xfer_vprintf ( xfer, format, args ); + va_end ( args ); + return rc; +} + /**************************************************************************** * * Helper methods |
