From 360110338147844bfa4612ae2d6351f1d1054626 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 26 May 2007 15:00:56 +0000 Subject: Modify process semantics; rescheduling is now automatic. Add reference-counting to processes. Add timer_running() test. --- src/include/gpxe/process.h | 41 +++++++++++++++++++++++++++++++++++++---- src/include/gpxe/retry.h | 11 +++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) (limited to 'src/include') diff --git a/src/include/gpxe/process.h b/src/include/gpxe/process.h index 83ff83934..c0837fa4f 100644 --- a/src/include/gpxe/process.h +++ b/src/include/gpxe/process.h @@ -8,6 +8,7 @@ */ #include +#include /** A process */ struct process { @@ -19,14 +20,46 @@ struct process { * This method should execute a single step of the process. * Returning from this method is isomorphic to yielding the * CPU to another process. - * - * If the process wishes to be executed again, it must re-add - * itself to the run queue using schedule(). */ void ( * step ) ( struct process *process ); + /** Reference counter + * + * If this interface is not part of a reference-counted + * object, this field may be NULL. + */ + struct refcnt *refcnt; }; -extern void schedule ( struct process *process ); +extern void process_add ( struct process *process ); +extern void process_del ( struct process *process ); extern void step ( void ); +/** + * Initialise process without adding to process list + * + * @v process Process + * @v step Process' step() method + */ +static inline __attribute__ (( always_inline )) void +process_init_stopped ( struct process *process, + void ( * step ) ( struct process *process ), + struct refcnt *refcnt ) { + process->step = step; + process->refcnt = refcnt; +} + +/** + * Initialise process and add to process list + * + * @v process Process + * @v step Process' step() method + */ +static inline __attribute__ (( always_inline )) void +process_init ( struct process *process, + void ( * step ) ( struct process *process ), + struct refcnt *refcnt ) { + process_init_stopped ( process, step, refcnt ); + process_add ( process ); +} + #endif /* _GPXE_PROCESS_H */ diff --git a/src/include/gpxe/retry.h b/src/include/gpxe/retry.h index 57be432e2..e0c0248b1 100644 --- a/src/include/gpxe/retry.h +++ b/src/include/gpxe/retry.h @@ -37,4 +37,15 @@ struct retry_timer { extern void start_timer ( struct retry_timer *timer ); extern void stop_timer ( struct retry_timer *timer ); +/** + * Test to see if timer is currently running + * + * @v timer Retry timer + * @ret running Non-zero if timer is running + */ +static inline __attribute__ (( always_inline )) unsigned long +timer_running ( struct retry_timer *timer ) { + return ( timer->start ); +} + #endif /* _GPXE_RETRY_H */ -- cgit v1.2.3-55-g7522 From 10d0a1f8c759309ad0aa8f73c87ae7b45cbb5fe6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 26 May 2007 15:04:36 +0000 Subject: Modify data-xfer semantics: it is no longer necessary to call one of request(), seek() or deliver_xxx() in order to start the data flow. Autonomous generators must be genuinely autonomous (having their own process), or otherwise arrange to be called. TCP does this by starting the retry timer immediately. Add some debugging statements. --- src/core/downloader.c | 15 +---------- src/core/hw.c | 27 ++++++++++--------- src/core/posix_io.c | 8 +++--- src/core/xfer.c | 71 ++++++++++++++++++++++++++++++++++++++++++------- src/include/gpxe/xfer.h | 16 ++++++++++- 5 files changed, 96 insertions(+), 41 deletions(-) (limited to 'src/include') 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 @@ -114,19 +114,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 * @@ -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 #include #include +#include #include #include @@ -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/posix_io.c b/src/core/posix_io.c index 6cefbf7b9..3b5660e4f 100644 --- a/src/core/posix_io.c +++ b/src/core/posix_io.c @@ -191,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; } @@ -226,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; @@ -241,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: diff --git a/src/core/xfer.c b/src/core/xfer.c index f2783f5bd..54377c705 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -35,6 +35,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 +54,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,21 +98,19 @@ 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 * @@ -116,11 +123,33 @@ 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 * @@ -132,7 +161,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 +183,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,7 +208,15 @@ 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; } diff --git a/src/include/gpxe/xfer.h b/src/include/gpxe/xfer.h index 71b69dc51..e6c896c39 100644 --- a/src/include/gpxe/xfer.h +++ b/src/include/gpxe/xfer.h @@ -112,6 +112,20 @@ enum seek_whence { SEEK_CUR, }; +/** + * Describe seek basis + * + * @v whence Basis for new position + */ +static inline __attribute__ (( always_inline )) const char * +whence_text ( int whence ) { + switch ( whence ) { + case SEEK_SET: return "SET"; + case SEEK_CUR: return "CUR"; + default: return "INVALID"; + } +} + extern struct xfer_interface null_xfer; extern struct xfer_interface_operations null_xfer_ops; @@ -121,8 +135,8 @@ extern int xfer_vredirect ( struct xfer_interface *xfer, int type, extern int xfer_redirect ( struct xfer_interface *xfer, int type, ... ); 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 int xfer_ready ( struct xfer_interface *xfer ); extern struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ); extern int xfer_deliver_iob ( struct xfer_interface *xfer, -- cgit v1.2.3-55-g7522 From a1210e4fcab0e8dbf696444da13552f612701198 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 26 May 2007 20:41:23 +0000 Subject: Eliminate PF_INET; just use the AF_INET from the struct sockaddr instead. --- src/core/open.c | 24 ++++++++++------------ src/include/gpxe/open.h | 18 ++++++++++------- src/include/gpxe/socket.h | 51 +++++++++++++++++++---------------------------- 3 files changed, 43 insertions(+), 50 deletions(-) (limited to 'src/include') diff --git a/src/core/open.c b/src/core/open.c index 284d00a98..b61160eb2 100644 --- a/src/core/open.c +++ b/src/core/open.c @@ -75,30 +75,29 @@ int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ) { * 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 +116,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/include/gpxe/open.h b/src/include/gpxe/open.h index 229d2d78c..b16bbe88a 100644 --- a/src/include/gpxe/open.h +++ b/src/include/gpxe/open.h @@ -26,7 +26,9 @@ enum { * * Parameter list for open() is: * - * + * int semantics; + * struct sockaddr *peer; + * struct sockaddr *local; */ LOCATION_SOCKET, }; @@ -56,10 +58,10 @@ struct uri_opener { /** A socket opener */ struct socket_opener { - /** Communication domain (e.g. PF_INET) */ - int domain; /** Communication semantics (e.g. SOCK_STREAM) */ - int type; + int semantics; + /** Address family (e.g. AF_INET) */ + int family; /** Open socket * * @v xfer Data transfer interface @@ -76,9 +78,11 @@ struct socket_opener { extern int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ); -extern int xfer_open_socket ( struct xfer_interface *xfer, - int domain, int type, struct sockaddr *peer, - struct sockaddr *local ); +extern int xfer_open_named_socket ( struct xfer_interface *xfer, + int semantics, struct sockaddr *peer, + const char *name, struct sockaddr *local ); +extern int xfer_open_socket ( struct xfer_interface *xfer, int semantics, + struct sockaddr *peer, struct sockaddr *local ); extern int xfer_vopen ( struct xfer_interface *xfer, int type, va_list args ); extern int xfer_open ( struct xfer_interface *xfer, int type, ... ); diff --git a/src/include/gpxe/socket.h b/src/include/gpxe/socket.h index ea602537e..d47369aac 100644 --- a/src/include/gpxe/socket.h +++ b/src/include/gpxe/socket.h @@ -8,31 +8,7 @@ */ /** - * @defgroup commdomains Communication domains - * - * @{ - */ -#define PF_INET 1 /**< IPv4 Internet protocols */ -#define PF_INET6 2 /**< IPv6 Internet protocols */ -/** @} */ - -/** - * Name communication domain - * - * @v domain Communication domain (e.g. PF_INET) - * @ret name Name of communication domain - */ -static inline __attribute__ (( always_inline )) const char * -socket_domain_name ( int domain ) { - switch ( domain ) { - case PF_INET: return "PF_INET"; - case PF_INET6: return "PF_INET6"; - default: return "PF_UNKNOWN"; - } -} - -/** - * @defgroup commtypes Communication types + * @defgroup commtypes Communication semantics * * @{ */ @@ -41,14 +17,14 @@ socket_domain_name ( int domain ) { /** @} */ /** - * Name communication type + * Name communication semantics * - * @v type Communication type (e.g. SOCK_STREAM) - * @ret name Name of communication type + * @v semantics Communication semantics (e.g. SOCK_STREAM) + * @ret name Name of communication semantics */ static inline __attribute__ (( always_inline )) const char * -socket_type_name ( int type ) { - switch ( type ) { +socket_semantics_name ( int semantics ) { + switch ( semantics ) { case SOCK_STREAM: return "SOCK_STREAM"; case SOCK_DGRAM: return "SOCK_DGRAM"; default: return "SOCK_UNKNOWN"; @@ -64,6 +40,21 @@ socket_type_name ( int type ) { #define AF_INET6 2 /**< IPv6 Internet addresses */ /** @} */ +/** + * Name address family + * + * @v family Address family (e.g. AF_INET) + * @ret name Name of address family + */ +static inline __attribute__ (( always_inline )) const char * +socket_family_name ( int family ) { + switch ( family ) { + case AF_INET: return "AF_INET"; + case AF_INET6: return "AF_INET6"; + default: return "AF_UNKNOWN"; + } +} + /** A socket address family */ typedef uint16_t sa_family_t; -- cgit v1.2.3-55-g7522 From 656485c1f1487775ccb0c223c4f5809f8daa7fcc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 28 May 2007 17:35:15 +0000 Subject: Make URI structures reference-counted. --- src/core/download.c | 4 ++-- src/core/open.c | 9 ++++++--- src/core/uri.c | 2 +- src/include/gpxe/open.h | 3 --- src/include/gpxe/uri.h | 23 ++++++++++++++++++----- 5 files changed, 27 insertions(+), 14 deletions(-) (limited to 'src/include') 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/open.c b/src/core/open.c index b61160eb2..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,14 +62,16 @@ 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; } /** diff --git a/src/core/uri.c b/src/core/uri.c index cb1ac3bcb..6ebc63734 100644 --- a/src/core/uri.c +++ b/src/core/uri.c @@ -35,7 +35,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; diff --git a/src/include/gpxe/open.h b/src/include/gpxe/open.h index b16bbe88a..5e368486b 100644 --- a/src/include/gpxe/open.h +++ b/src/include/gpxe/open.h @@ -46,9 +46,6 @@ struct uri_opener { * @v xfer Data transfer interface * @v uri URI * @ret rc Return status code - * - * This method takes ownership of the URI structure, and is - * responsible for eventually calling free_uri(). */ int ( * open ) ( struct xfer_interface *xfer, struct uri *uri ); }; diff --git a/src/include/gpxe/uri.h b/src/include/gpxe/uri.h index b8c7e098a..6fddcc33b 100644 --- a/src/include/gpxe/uri.h +++ b/src/include/gpxe/uri.h @@ -8,6 +8,7 @@ */ #include +#include /** A Uniform Resource Identifier * @@ -37,6 +38,8 @@ * query = "what=is", fragment = "this" */ struct uri { + /** Reference count */ + struct refcnt refcnt; /** Scheme */ const char *scheme; /** Opaque part */ @@ -100,15 +103,25 @@ static inline int uri_has_relative_path ( struct uri *uri ) { } /** - * Free URI structure + * Increment URI reference count * * @v uri URI + * @ret uri URI + */ +static inline __attribute__ (( always_inline )) struct uri * +uri_get ( struct uri *uri ) { + ref_get ( &uri->refcnt ); + return uri; +} + +/** + * Decrement URI reference count * - * Frees all the dynamically-allocated storage used by the URI - * structure. + * @v uri URI */ -static inline void free_uri ( struct uri *uri ) { - free ( uri ); +static inline __attribute__ (( always_inline )) void +uri_put ( struct uri *uri ) { + ref_put ( &uri->refcnt ); } extern struct uri * parse_uri ( const char *uri_string ); -- cgit v1.2.3-55-g7522 From a6a18ae9af43f870c82836ec0c9b486db6e58b15 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 28 May 2007 20:09:44 +0000 Subject: Add xfer_[v]printf() functions. --- src/core/xfer.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/include/gpxe/xfer.h | 4 ++++ 2 files changed, 45 insertions(+) (limited to 'src/include') diff --git a/src/core/xfer.c b/src/core/xfer.c index 54377c705..2250687e4 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -221,6 +222,46 @@ int xfer_deliver_raw ( struct xfer_interface *xfer, 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 ); + 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 diff --git a/src/include/gpxe/xfer.h b/src/include/gpxe/xfer.h index e6c896c39..f946ab1c1 100644 --- a/src/include/gpxe/xfer.h +++ b/src/include/gpxe/xfer.h @@ -143,6 +143,10 @@ 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 int xfer_vprintf ( struct xfer_interface *xfer, + const char *format, va_list args ); +extern int xfer_printf ( struct xfer_interface *xfer, + const char *format, ... ); extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc ); extern int ignore_xfer_vredirect ( struct xfer_interface *xfer, -- cgit v1.2.3-55-g7522 From 335b99a39d468c7671f584bee362856cf5c2ed99 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 31 May 2007 13:26:50 +0000 Subject: Move [v]ssnprintf() from iscsi.c into vsprintf.c; we need them elsewhere as well. --- src/core/vsprintf.c | 39 +++++++++++++++++++++++++++++++++++++++ src/include/gpxe/vsprintf.h | 4 ++++ src/net/tcp/iscsi.c | 27 +-------------------------- 3 files changed, 44 insertions(+), 26 deletions(-) (limited to 'src/include') 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 @@ -338,6 +338,45 @@ int snprintf ( char *buf, size_t size, const char *fmt, ... ) { return i; } +/** + * 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 * diff --git a/src/include/gpxe/vsprintf.h b/src/include/gpxe/vsprintf.h index ac87c5a8b..9360f29b7 100644 --- a/src/include/gpxe/vsprintf.h +++ b/src/include/gpxe/vsprintf.h @@ -64,4 +64,8 @@ struct printf_context { extern size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ); +extern int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, + va_list args ); +extern int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ); + #endif /* _GPXE_VSPRINTF_H */ diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index 56567976f..f95286d09 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -348,32 +349,6 @@ static void iscsi_tx_data_out ( struct iscsi_session *iscsi, * */ -/** - * Version of snprintf() 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 - * - * This is a utility function for iscsi_build_login_request_strings(). - */ -static int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) { - va_list args; - int len; - - /* Treat negative buffer size as zero buffer size */ - if ( ssize < 0 ) - ssize = 0; - - /* Hand off to vsnprintf */ - va_start ( args, fmt ); - len = vsnprintf ( buf, ssize, fmt, args ); - va_end ( args ); - return len; -} - /** * Build iSCSI login request strings * -- cgit v1.2.3-55-g7522 From 816c8f3b894e2cedf28e568329b6c69e45aa161e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Jun 2007 01:50:03 +0000 Subject: Added [v]asprintf() --- src/core/asprintf.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/include/stdio.h | 5 +++++ 2 files changed, 52 insertions(+) create mode 100644 src/core/asprintf.c (limited to 'src/include') 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 +#include +#include +#include +#include + +/** + * 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/include/stdio.h b/src/include/stdio.h index 169cfd9e3..82077e20f 100644 --- a/src/include/stdio.h +++ b/src/include/stdio.h @@ -10,10 +10,15 @@ printf ( const char *fmt, ... ); extern int __attribute__ (( format ( printf, 3, 4 ) )) snprintf ( char *buf, size_t size, const char *fmt, ... ); +extern int __attribute__ (( format ( printf, 2, 3 ) )) +asprintf ( char **strp, const char *fmt, ... ); + extern int vprintf ( const char *fmt, va_list args ); extern int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ); +extern int vasprintf ( char **strp, const char *fmt, va_list args ); + /** * Write a formatted string to a buffer * -- cgit v1.2.3-55-g7522 From 182e3ed61d8db574c2bf7a091ce2221746259cbd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Jun 2007 01:51:10 +0000 Subject: Added dirname() --- src/core/basename.c | 22 ++++++++++++++++++++++ src/include/libgen.h | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/include') 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/include/libgen.h b/src/include/libgen.h index 8fa552a92..56a2f760b 100644 --- a/src/include/libgen.h +++ b/src/include/libgen.h @@ -1,6 +1,7 @@ #ifndef _LIBGEN_H #define _LIBGEN_H -char * basename ( char *path ); +extern char * basename ( char *path ); +extern char * dirname ( char *path ); #endif /* _LIBGEN_H */ -- cgit v1.2.3-55-g7522 From a6f0a098da98a4274b202300f62c5c4b871b3e92 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Jun 2007 02:01:02 +0000 Subject: Add facility for resolving base+relative URIs (and paths). --- src/core/uri.c | 239 +++++++++++++++++++++++++++++++++++++++++++++---- src/include/gpxe/uri.h | 8 +- 2 files changed, 227 insertions(+), 20 deletions(-) (limited to 'src/include') diff --git a/src/core/uri.c b/src/core/uri.c index 6ebc63734..a793c4577 100644 --- a/src/core/uri.c +++ b/src/core/uri.c @@ -25,8 +25,36 @@ #include #include #include +#include +#include #include +/** + * 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 * @@ -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/include/gpxe/uri.h b/src/include/gpxe/uri.h index 6fddcc33b..f61623824 100644 --- a/src/include/gpxe/uri.h +++ b/src/include/gpxe/uri.h @@ -125,6 +125,12 @@ uri_put ( struct uri *uri ) { } extern struct uri * parse_uri ( const char *uri_string ); -unsigned int uri_port ( struct uri *uri, unsigned int default_port ); +extern unsigned int uri_port ( struct uri *uri, unsigned int default_port ); +extern int unparse_uri ( char *buf, size_t size, struct uri *uri ); +extern struct uri * uri_dup ( struct uri *uri ); +extern char * resolve_path ( const char *base_path, + const char *relative_path ); +extern struct uri * resolve_uri ( struct uri *base_uri, + struct uri *relative_uri ); #endif /* _GPXE_URI_H */ -- cgit v1.2.3-55-g7522