Merge branch 'master' into mcb-tcp-xfer
authorMichael Brown <mcb30@etherboot.org>
Fri, 8 Jun 2007 15:33:24 +0000 (16:33 +0100)
committerMichael Brown <mcb30@etherboot.org>
Fri, 8 Jun 2007 15:33:24 +0000 (16:33 +0100)
27 files changed:
src/core/asprintf.c [new file with mode: 0644]
src/core/basename.c
src/core/download.c
src/core/downloader.c
src/core/hw.c
src/core/open.c
src/core/posix_io.c
src/core/process.c
src/core/refcnt.c
src/core/uri.c
src/core/vsprintf.c
src/core/xfer.c
src/crypto/axtls/asn1.c [deleted file]
src/hci/strerror.c
src/include/gpxe/open.h
src/include/gpxe/process.h
src/include/gpxe/retry.h
src/include/gpxe/socket.h
src/include/gpxe/uri.h
src/include/gpxe/vsprintf.h
src/include/gpxe/xfer.h
src/include/libgen.h
src/include/stdio.h
src/net/netdevice.c
src/net/retry.c
src/net/tcp/iscsi.c
src/tests/uri_test.c [new file with mode: 0644]

diff --git a/src/core/asprintf.c b/src/core/asprintf.c
new file mode 100644 (file)
index 0000000..94d7e7c
--- /dev/null
@@ -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;
+}
index f50b715..7340c0d 100644 (file)
@@ -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 ".";
+       }
+}
index 4522bf2..e3f7779 100644 (file)
@@ -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 */
index 2f28bc9..15ef962 100644 (file)
@@ -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,
index 77b39ba..a3eb850 100644 (file)
@@ -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 );
index 284d00a..6c184e6 100644 (file)
@@ -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 );
index b98766f..3b5660e 100644 (file)
@@ -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;
index c087f16..0583a39 100644 (file)
 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;
        }
index 227dac3..36b7ce2 100644 (file)
@@ -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;
index cb1ac3b..a793c45 100644 (file)
 #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
  *
@@ -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;
+}
index e6f072e..4457fe4 100644 (file)
@@ -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
  *
index f2783f5..ea5fda3 100644 (file)
@@ -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,21 +99,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 +124,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 +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
diff --git a/src/crypto/axtls/asn1.c b/src/crypto/axtls/asn1.c
deleted file mode 100644 (file)
index 74411c7..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- *  Copyright(C) 2006 Cameron Rich
- *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2.1 of the License, or
- *  (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @file asn1.c
- * 
- * Some primitive asn methods for extraction rsa modulus information. It also
- * is used for retrieving information from X.509 certificates.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "crypto.h"
-
-#define SIG_OID_PREFIX_SIZE     8
-
-#define SIG_TYPE_MD2            0x02
-#define SIG_TYPE_MD5            0x04
-#define SIG_TYPE_SHA1           0x05
-
-/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
-static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = 
-{
-    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
-};
-
-/* CN, O, OU */
-static const uint8_t g_dn_types[] = { 3, 10, 11 };
-
-static int get_asn1_length(const uint8_t *buf, int *offset)
-{
-    int len, i;
-
-    if (!(buf[*offset] & 0x80)) /* short form */
-    {
-        len = buf[(*offset)++];
-    }
-    else    /* long form */
-    {
-        int length_bytes = buf[(*offset)++]&0x7f;
-        len = 0;
-        for (i = 0; i < length_bytes; i++)
-        {
-            len <<= 8;
-            len += buf[(*offset)++];
-        }
-    }
-
-    return len;
-}
-
-/**
- * Skip the ASN1.1 object type and its length. Get ready to read the object's
- * data.
- */
-int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
-{
-    if (buf[*offset] != obj_type)
-        return X509_NOT_OK;
-    (*offset)++;
-    return get_asn1_length(buf, offset);
-}
-
-/**
- * Skip over an ASN.1 object type completely. Get ready to read the next
- * object.
- */
-int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
-{
-    int len;
-
-    if (buf[*offset] != obj_type)
-        return X509_NOT_OK;
-    (*offset)++;
-    len = get_asn1_length(buf, offset);
-    *offset += len;
-    return 0;
-}
-
-/**
- * Read an integer value for ASN.1 data
- * Note: This function allocates memory which must be freed by the user.
- */
-int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
-{
-    int len;
-
-    if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
-        goto end_int_array;
-
-    *object = (uint8_t *)malloc(len);
-    memcpy(*object, &buf[*offset], len);
-    *offset += len;
-
-end_int_array:
-    return len;
-}
-
-#if 0
-
-/**
- * Get all the RSA private key specifics from an ASN.1 encoded file 
- */
-int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
-{
-    int offset = 7;
-    uint8_t *modulus, *priv_exp, *pub_exp;
-    int mod_len, priv_len, pub_len;
-#ifdef CONFIG_BIGINT_CRT
-    uint8_t *p, *q, *dP, *dQ, *qInv;
-    int p_len, q_len, dP_len, dQ_len, qInv_len;
-#endif
-
-    /* not in der format */
-    if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
-    {
-#ifdef CONFIG_SSL_FULL_MODE
-        printf("Error: This is not a valid ASN.1 file\n");
-#endif
-        return X509_INVALID_PRIV_KEY;
-    }
-
-    /* initialise the RNG */
-    RNG_initialize(buf, len);
-
-    mod_len = asn1_get_int(buf, &offset, &modulus);
-    pub_len = asn1_get_int(buf, &offset, &pub_exp);
-    priv_len = asn1_get_int(buf, &offset, &priv_exp);
-
-    if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
-        return X509_INVALID_PRIV_KEY;
-
-#ifdef CONFIG_BIGINT_CRT
-    p_len = asn1_get_int(buf, &offset, &p);
-    q_len = asn1_get_int(buf, &offset, &q);
-    dP_len = asn1_get_int(buf, &offset, &dP);
-    dQ_len = asn1_get_int(buf, &offset, &dQ);
-    qInv_len = asn1_get_int(buf, &offset, &qInv);
-
-    if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
-        return X509_INVALID_PRIV_KEY;
-
-    RSA_priv_key_new(rsa_ctx, 
-            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
-            p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
-
-    free(p);
-    free(q);
-    free(dP);
-    free(dQ);
-    free(qInv);
-#else
-    RSA_priv_key_new(rsa_ctx, 
-            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
-#endif
-
-    free(modulus);
-    free(priv_exp);
-    free(pub_exp);
-    return X509_OK;
-}
-
-/**
- * Get the time of a certificate. Ignore hours/minutes/seconds.
- */
-static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
-{
-    int ret = X509_NOT_OK, len, t_offset;
-    struct tm tm;
-
-    if (buf[(*offset)++] != ASN1_UTC_TIME)
-        goto end_utc_time;
-    len = get_asn1_length(buf, offset);
-    t_offset = *offset;
-
-    memset(&tm, 0, sizeof(struct tm));
-    tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
-
-    if (tm.tm_year <= 50)    /* 1951-2050 thing */
-    {
-        tm.tm_year += 100;
-    }
-
-    tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
-    tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
-    *t = mktime(&tm);
-    *offset += len;
-    ret = X509_OK;
-
-end_utc_time:
-    return ret;
-}
-
-/**
- * Get the version type of a certificate (which we don't actually care about)
- */
-static int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
-    int ret = X509_NOT_OK;
-
-    (*offset) += 2;        /* get past explicit tag */
-    if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
-        goto end_version;
-
-    ret = X509_OK;
-end_version:
-    return ret;
-}
-
-/**
- * Retrieve the notbefore and notafter certificate times.
- */
-static int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
-    return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
-              asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
-              asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
-}
-
-/**
- * Get the components of a distinguished name 
- */
-static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
-{
-    int dn_type = 0;
-    int len;
-
-    if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
-        goto end_oid;
-
-    /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name 
-       components we are interested in. */
-    if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
-        dn_type = buf[(*offset)++];
-    else
-    {
-        *offset += len;     /* skip over it */
-    }
-
-end_oid:
-    return dn_type;
-}
-
-/**
- * Obtain an ASN.1 printable string type.
- */
-static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
-{
-    int len = X509_NOT_OK;
-
-    /* some certs have this awful crud in them for some reason */
-    if (buf[*offset] != ASN1_PRINTABLE_STR && 
-            buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR)
-        goto end_pnt_str;
-
-    (*offset)++;
-    len = get_asn1_length(buf, offset);
-    *str = (char *)malloc(len+1);       /* allow for null */
-    memcpy(*str, &buf[*offset], len);
-    (*str)[len] = 0;                    /* null terminate */
-    *offset += len;
-end_pnt_str:
-    return len;
-}
-
-/**
- * Get the subject name (or the issuer) of a certificate.
- */
-static int asn1_name(const uint8_t *cert, int *offset, char *dn[])
-{
-    int ret = X509_NOT_OK;
-    int dn_type;
-    char *tmp = NULL;
-
-    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
-        goto end_name;
-
-    while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
-    {
-        int i, found = 0;
-
-        if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
-               (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
-            goto end_name;
-
-        if (asn1_get_printable_str(cert, offset, &tmp) < 0)
-        {
-            free(tmp);
-            goto end_name;
-        }
-
-        /* find the distinguished named type */
-        for (i = 0; i < X509_NUM_DN_TYPES; i++)
-        {
-            if (dn_type == g_dn_types[i])
-            {
-                if (dn[i] == NULL)
-                {
-                    dn[i] = tmp;
-                    found = 1;
-                    break;
-                }
-            }
-        }
-
-        if (found == 0) /* not found so get rid of it */
-        {
-            free(tmp);
-        }
-    }
-
-    ret = X509_OK;
-end_name:
-    return ret;
-}
-
-/**
- * Read the modulus and public exponent of a certificate.
- */
-static int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
-    int ret = X509_NOT_OK, mod_len, pub_len;
-    uint8_t *modulus, *pub_exp;
-
-    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
-            asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
-            asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
-        goto end_pub_key;
-
-    (*offset)++;
-
-    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
-        goto end_pub_key;
-
-    mod_len = asn1_get_int(cert, offset, &modulus);
-    pub_len = asn1_get_int(cert, offset, &pub_exp);
-
-    RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
-
-    free(modulus);
-    free(pub_exp);
-    ret = X509_OK;
-
-end_pub_key:
-    return ret;
-}
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * Read the signature of the certificate.
- */
-static int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
-    int ret = X509_NOT_OK;
-
-    if (cert[(*offset)++] != ASN1_BIT_STRING)
-        goto end_sig;
-
-    x509_ctx->sig_len = get_asn1_length(cert, offset);
-    x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
-    memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
-    *offset += x509_ctx->sig_len;
-    ret = X509_OK;
-
-end_sig:
-    return ret;
-}
-
-/*
- * Compare 2 distinguished name components for equality 
- * @return 0 if a match
- */
-static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
-{
-    int ret = 1;
-
-    if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match;
-
-    ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0;
-
-err_no_match:
-    return ret;
-}
-
-/**
- * Clean up all of the CA certificates.
- */
-void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
-{
-    int i = 0;
-
-    while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
-    {
-        x509_free(ca_cert_ctx->cert[i]);
-        ca_cert_ctx->cert[i++] = NULL;
-    }
-
-    free(ca_cert_ctx);
-}
-
-/*
- * Compare 2 distinguished names for equality 
- * @return 0 if a match
- */
-static int asn1_compare_dn(char * const dn1[], char * const dn2[])
-{
-    int i;
-
-    for (i = 0; i < X509_NUM_DN_TYPES; i++)
-    {
-        if (asn1_compare_dn_comp(dn1[i], dn2[i]))
-        {
-            return 1;
-        }
-    }
-
-    return 0;       /* all good */
-}
-
-/**
- * Retrieve the signature from a certificate.
- */
-const uint8_t *x509_get_signature(const uint8_t *asn1_sig, int *len)
-{
-    int offset = 0;
-    const uint8_t *ptr = NULL;
-
-    if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || 
-            asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
-        goto end_get_sig;
-
-    if (asn1_sig[offset++] != ASN1_OCTET_STRING)
-        goto end_get_sig;
-    *len = get_asn1_length(asn1_sig, &offset);
-    ptr = &asn1_sig[offset];          /* all ok */
-
-end_get_sig:
-    return ptr;
-}
-
-#endif
-
-/**
- * Read the signature type of the certificate. We only support RSA-MD5 and
- * RSA-SHA1 signature types.
- */
-static int asn1_signature_type(const uint8_t *cert, 
-                                int *offset, X509_CTX *x509_ctx)
-{
-    int ret = X509_NOT_OK, len;
-
-    if (cert[(*offset)++] != ASN1_OID)
-        goto end_check_sig;
-
-    len = get_asn1_length(cert, offset);
-
-    if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
-        goto end_check_sig;     /* unrecognised cert type */
-
-    x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
-
-    *offset += len;
-    if (asn1_skip_obj(cert, offset, ASN1_NULL))
-        goto end_check_sig;
-    ret = X509_OK;
-
-end_check_sig:
-    return ret;
-}
-
-/**
- * Construct a new x509 object.
- * @return 0 if ok. < 0 if there was a problem.
- */
-int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
-{
-    int begin_tbs, end_tbs;
-    int ret = X509_NOT_OK, offset = 0, cert_size = 0;
-    X509_CTX *x509_ctx;
-    BI_CTX *bi_ctx;
-
-    *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
-    x509_ctx = *ctx;
-
-    /* get the certificate size */
-    asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); 
-
-    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
-        goto end_cert;
-
-    begin_tbs = offset;         /* start of the tbs */
-    end_tbs = begin_tbs;        /* work out the end of the tbs */
-    asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
-
-    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
-        goto end_cert;
-
-    if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */
-    {
-        if (asn1_version(cert, &offset, x509_ctx))
-            goto end_cert;
-    }
-
-    if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ 
-            asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
-        goto end_cert;
-
-    /* make sure the signature is ok */
-    if (asn1_signature_type(cert, &offset, x509_ctx))
-    {
-        ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
-        goto end_cert;
-    }
-
-    if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || 
-            asn1_validity(cert, &offset, x509_ctx) ||
-            asn1_name(cert, &offset, x509_ctx->cert_dn) ||
-            asn1_public_key(cert, &offset, x509_ctx))
-        goto end_cert;
-
-    bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
-    /* use the appropriate signature algorithm (either SHA1 or MD5) */
-    if (x509_ctx->sig_type == SIG_TYPE_MD5)
-    {
-        MD5_CTX md5_ctx;
-        uint8_t md5_dgst[MD5_SIZE];
-        MD5Init(&md5_ctx);
-        MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
-        MD5Final(&md5_ctx, md5_dgst);
-        x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
-    }
-    else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
-    {
-        SHA1_CTX sha_ctx;
-        uint8_t sha_dgst[SHA1_SIZE];
-        SHA1Init(&sha_ctx);
-        SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
-        SHA1Final(&sha_ctx, sha_dgst);
-        x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
-    }
-
-    offset = end_tbs;   /* skip the v3 data */
-    if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || 
-            asn1_signature(cert, &offset, x509_ctx))
-        goto end_cert;
-#endif
-
-    if (len)
-    {
-        *len = cert_size;
-    }
-
-    ret = X509_OK;
-end_cert:
-
-#ifdef CONFIG_SSL_FULL_MODE
-    if (ret)
-    {
-        printf("Error: Invalid X509 ASN.1 file\n");
-    }
-#endif
-
-    return ret;
-}
-
-/**
- * Free an X.509 object's resources.
- */
-void x509_free(X509_CTX *x509_ctx)
-{
-    X509_CTX *next;
-    int i;
-
-    if (x509_ctx == NULL)       /* if already null, then don't bother */
-        return;
-
-    for (i = 0; i < X509_NUM_DN_TYPES; i++)
-    {
-        free(x509_ctx->ca_cert_dn[i]);
-        free(x509_ctx->cert_dn[i]);
-    }
-
-    free(x509_ctx->signature);
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION 
-    if (x509_ctx->digest)
-    {
-        bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
-    }
-#endif
-
-    RSA_free(x509_ctx->rsa_ctx);
-
-    next = x509_ctx->next;
-    free(x509_ctx);
-    x509_free(next);        /* clear the chain */
-}
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * Do some basic checks on the certificate chain.
- *
- * Certificate verification consists of a number of checks:
- * - A root certificate exists in the certificate store.
- * - The date of the certificate is after the start date.
- * - The date of the certificate is before the finish date.
- * - The certificate chain is valid.
- * - That the certificate(s) are not self-signed.
- * - The signature of the certificate is valid.
- */
-int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) 
-{
-    int ret = X509_OK, i = 0;
-    bigint *cert_sig;
-    X509_CTX *next_cert = NULL;
-    BI_CTX *ctx;
-    bigint *mod, *expn;
-    struct timeval tv;
-    int match_ca_cert = 0;
-
-    if (cert == NULL || ca_cert_ctx == NULL)
-    {
-        ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
-        goto end_verify;
-    }
-
-    /* last cert in the chain - look for a trusted cert */
-    if (cert->next == NULL)
-    {
-        while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
-        {
-            if (asn1_compare_dn(cert->ca_cert_dn,
-                                        ca_cert_ctx->cert[i]->cert_dn) == 0)
-            {
-                match_ca_cert = 1;
-                break;
-            }
-
-            i++;
-        }
-
-        if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
-        {
-            next_cert = ca_cert_ctx->cert[i];
-        }
-        else    /* trusted cert not found */
-        {
-            ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       
-            goto end_verify;
-        }
-    }
-    else
-    {
-        next_cert = cert->next;
-    }
-
-    gettimeofday(&tv, NULL);
-
-    /* check the not before date */
-    if (tv.tv_sec < cert->not_before)
-    {
-        ret = X509_VFY_ERROR_NOT_YET_VALID;
-        goto end_verify;
-    }
-
-    /* check the not after date */
-    if (tv.tv_sec > cert->not_after)
-    {
-        ret = X509_VFY_ERROR_EXPIRED;
-        goto end_verify;
-    }
-
-    /* check the chain integrity */
-    if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn))
-    {
-        ret = X509_VFY_ERROR_INVALID_CHAIN;
-        goto end_verify;
-    }
-
-    /* check for self-signing */
-    if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
-    {
-        ret = X509_VFY_ERROR_SELF_SIGNED;
-        goto end_verify;
-    }
-
-    /* check the signature */
-    ctx = cert->rsa_ctx->bi_ctx;
-    mod = next_cert->rsa_ctx->m;
-    expn = next_cert->rsa_ctx->e;
-    cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len, 
-            bi_clone(ctx, mod), bi_clone(ctx, expn));
-
-    if (cert_sig)
-    {
-        ret = cert->digest ?    /* check the signature */
-            bi_compare(cert_sig, cert->digest) :
-            X509_VFY_ERROR_UNSUPPORTED_DIGEST;
-        bi_free(ctx, cert_sig);
-
-        if (ret)
-            goto end_verify;
-    }
-    else
-    {
-        ret = X509_VFY_ERROR_BAD_SIGNATURE;
-        goto end_verify;
-    }
-
-    /* go down the certificate chain using recursion. */
-    if (ret == 0 && cert->next)
-    {
-        ret = x509_verify(ca_cert_ctx, next_cert);
-    }
-
-end_verify:
-    return ret;
-}
-#endif
-
-#if defined (CONFIG_SSL_FULL_MODE)
-/**
- * Used for diagnostics.
- */
-void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) 
-{
-    if (cert == NULL)
-        return;
-
-    printf("----------------   CERT DEBUG   ----------------\n");
-    printf("* CA Cert Distinguished Name\n");
-    if (cert->ca_cert_dn[X509_COMMON_NAME])
-    {
-        printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]);
-    }
-
-    if (cert->ca_cert_dn[X509_ORGANIZATION])
-    {
-        printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]);
-    }
-
-    if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE])
-    {
-        printf("Organizational Unit (OU): %s\n", 
-                cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]);
-    }
-
-    printf("* Cert Distinguished Name\n");
-    if (cert->cert_dn[X509_COMMON_NAME])
-    {
-        printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]);
-    }
-
-    if (cert->cert_dn[X509_ORGANIZATION])
-    {
-        printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]);
-    }
-
-    if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE])
-    {
-        printf("Organizational Unit (OU): %s\n", 
-                cert->cert_dn[X509_ORGANIZATIONAL_TYPE]);
-    }
-
-    printf("Not Before:\t\t%s", ctime(&cert->not_before));
-    printf("Not After:\t\t%s", ctime(&cert->not_after));
-    printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8);
-    printf("Sig Type:\t\t");
-    switch (cert->sig_type)
-    {
-        case SIG_TYPE_MD5:
-            printf("MD5\n");
-            break;
-        case SIG_TYPE_SHA1:
-            printf("SHA1\n");
-            break;
-        case SIG_TYPE_MD2:
-            printf("MD2\n");
-            break;
-        default:
-            printf("Unrecognized: %d\n", cert->sig_type);
-            break;
-    }
-
-    printf("Verify:\t\t\t");
-
-    if (ca_cert_ctx)
-    {
-        x509_display_error(x509_verify(ca_cert_ctx, cert));
-    }
-
-    printf("\n");
-#if 0
-    print_blob("Signature", cert->signature, cert->sig_len);
-    bi_print("Modulus", cert->rsa_ctx->m);
-    bi_print("Pub Exp", cert->rsa_ctx->e);
-#endif
-
-    if (ca_cert_ctx)
-    {
-        x509_print(ca_cert_ctx, cert->next);
-    }
-}
-
-void x509_display_error(int error)
-{
-    switch (error)
-    {
-        case X509_NOT_OK:
-            printf("X509 not ok");
-            break;
-
-        case X509_VFY_ERROR_NO_TRUSTED_CERT:
-            printf("No trusted cert is available");
-            break;
-
-        case X509_VFY_ERROR_BAD_SIGNATURE:
-            printf("Bad signature");
-            break;
-
-        case X509_VFY_ERROR_NOT_YET_VALID:
-            printf("Cert is not yet valid");
-            break;
-
-        case X509_VFY_ERROR_EXPIRED:
-            printf("Cert has expired");
-            break;
-
-        case X509_VFY_ERROR_SELF_SIGNED:
-            printf("Cert is self-signed");
-            break;
-
-        case X509_VFY_ERROR_INVALID_CHAIN:
-            printf("Chain is invalid (check order of certs)");
-            break;
-
-        case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
-            printf("Unsupported digest");
-            break;
-
-        case X509_INVALID_PRIV_KEY:
-            printf("Invalid private key");
-            break;
-    }
-}
-#endif      /* CONFIG_SSL_FULL_MODE */
-
-#endif
index 045e635..7609f03 100644 (file)
@@ -120,4 +120,5 @@ struct errortab common_errors[] __errortab = {
        { ENOENT, "File not found" },
        { ENETUNREACH, "Network unreachable" },
        { ETIMEDOUT, "Connection timed out" },
+       { EPIPE, "Broken pipe" },
 };
index 229d2d7..5e36848 100644 (file)
@@ -26,7 +26,9 @@ enum {
         *
         * Parameter list for open() is:
         *
-        * 
+        * int semantics;
+        * struct sockaddr *peer;
+        * struct sockaddr *local;
         */
        LOCATION_SOCKET,
 };
@@ -44,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 );
 };
@@ -56,10 +55,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 +75,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, ... );
 
index 83ff839..c0837fa 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <gpxe/list.h>
+#include <gpxe/refcnt.h>
 
 /** 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 */
index 57be432..e0c0248 100644 (file)
@@ -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 */
index ea60253..d47369a 100644 (file)
@@ -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;
 
index b8c7e09..f616238 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <stdlib.h>
+#include <gpxe/refcnt.h>
 
 /** 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,18 +103,34 @@ 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 );
-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 */
index ac87c5a..9360f29 100644 (file)
@@ -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 */
index 71b69dc..f946ab1 100644 (file)
@@ -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,14 +135,18 @@ 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,
                              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,
index 8fa552a..56a2f76 100644 (file)
@@ -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 */
index 169cfd9..82077e2 100644 (file)
@@ -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
  *
index c1ad5f6..ddcb296 100644 (file)
@@ -388,7 +388,7 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
  * This polls all interfaces for received packets, and processes
  * packets from the RX queue.
  */
-static void net_step ( struct process *process ) {
+static void net_step ( struct process *process __unused ) {
        struct net_device *netdev;
        struct io_buffer *iobuf;
 
@@ -410,9 +410,6 @@ static void net_step ( struct process *process ) {
                        netdev->ll_protocol->rx ( iobuf, netdev );
                }
        }
-
-       /* Re-schedule ourself */
-       schedule ( process );
 }
 
 /** Networking stack process */
@@ -422,7 +419,7 @@ static struct process net_process = {
 
 /** Initialise the networking stack process */
 static void init_net ( void ) {
-       schedule ( &net_process );
+       process_add ( &net_process );
 }
 
 INIT_FN ( INIT_PROCESS, init_net, NULL, NULL );
index cd683f5..f8c34b8 100644 (file)
@@ -64,7 +64,7 @@ static LIST_HEAD ( timers );
  * be stopped and the timer's callback function will be called.
  */
 void start_timer ( struct retry_timer *timer ) {
-       if ( ! timer->start )
+       if ( ! timer_running ( timer ) )
                list_add ( &timer->list, &timers );
        timer->start = currticks();
        if ( timer->timeout < MIN_TIMEOUT )
@@ -86,7 +86,7 @@ void stop_timer ( struct retry_timer *timer ) {
        unsigned long runtime;
 
        /* If timer was already stopped, do nothing */
-       if ( ! timer->start )
+       if ( ! timer_running ( timer ) )
                return;
 
        list_del ( &timer->list );
@@ -153,7 +153,7 @@ static void timer_expired ( struct retry_timer *timer ) {
  *
  * @v process          Retry timer process
  */
-static void retry_step ( struct process *process ) {
+static void retry_step ( struct process *process __unused ) {
        struct retry_timer *timer;
        struct retry_timer *tmp;
        unsigned long now = currticks();
@@ -164,8 +164,6 @@ static void retry_step ( struct process *process ) {
                if ( used >= timer->timeout )
                        timer_expired ( timer );
        }
-
-       schedule ( process );
 }
 
 /** Retry timer process */
@@ -175,7 +173,7 @@ static struct process retry_process = {
 
 /** Initialise the retry timer module */
 static void init_retry ( void ) {
-       schedule ( &retry_process );
+       process_add ( &retry_process );
 }
 
 INIT_FN ( INIT_PROCESS, init_retry, NULL, NULL );
index 5656797..f95286d 100644 (file)
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <assert.h>
 #include <byteswap.h>
+#include <gpxe/vsprintf.h>
 #include <gpxe/scsi.h>
 #include <gpxe/process.h>
 #include <gpxe/uaccess.h>
@@ -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
  *
diff --git a/src/tests/uri_test.c b/src/tests/uri_test.c
new file mode 100644 (file)
index 0000000..2548760
--- /dev/null
@@ -0,0 +1,145 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <gpxe/uri.h>
+
+#define URI_MAX_LEN 1024
+
+struct uri_test {
+       const char *base_uri_string;
+       const char *relative_uri_string;
+       const char *resolved_uri_string;
+};
+
+static struct uri_test uri_tests[] = {
+       { "http://www.fensystems.co.uk", "",
+         "http://www.fensystems.co.uk/" },
+       { "http://etherboot.org/wiki/page1", "page2",
+         "http://etherboot.org/wiki/page2" },
+       { "http://etherboot.org/wiki/page1", "../page3",
+         "http://etherboot.org/page3" },
+       { "tftp://192.168.0.1/", "/tftpboot/vmlinuz",
+         "tftp://192.168.0.1/tftpboot/vmlinuz" },
+#if 0
+       "http://www.etherboot.org/wiki",
+       "mailto:bob@nowhere.com",
+       "ftp://joe:secret@insecure.org:8081/hidden/path/to?what=is#this",
+#endif
+};
+
+static int test_parse_unparse ( const char *uri_string ) {
+       char buf[URI_MAX_LEN];
+       size_t len;
+       struct uri *uri = NULL;
+       int rc;
+
+       /* Parse and unparse URI */
+       uri = parse_uri ( uri_string );
+       if ( ! uri ) {
+               rc = -ENOMEM;
+               goto done;
+       }
+       len = unparse_uri ( buf, sizeof ( buf ), uri );
+
+       /* Compare result */
+       if ( strcmp ( buf, uri_string ) != 0 ) {
+               printf ( "Unparse of \"%s\" produced \"%s\"\n",
+                        uri_string, buf );
+               rc = -EINVAL;
+               goto done;
+       }
+
+       rc = 0;
+
+ done:
+       uri_put ( uri );
+       if ( rc ) {
+               printf ( "URI parse-unparse of \"%s\" failed: %s\n",
+                        uri_string, strerror ( rc ) );
+       }
+       return rc;
+}
+
+static int test_resolve ( const char *base_uri_string,
+                         const char *relative_uri_string,
+                         const char *resolved_uri_string ) {
+       struct uri *base_uri = NULL;
+       struct uri *relative_uri = NULL;
+       struct uri *resolved_uri = NULL;
+       char buf[URI_MAX_LEN];
+       size_t len;
+       int rc;
+
+       /* Parse URIs */
+       base_uri = parse_uri ( base_uri_string );
+       if ( ! base_uri ) {
+               rc = -ENOMEM;
+               goto done;
+       }
+       relative_uri = parse_uri ( relative_uri_string );
+       if ( ! relative_uri ) {
+               rc = -ENOMEM;
+               goto done;
+       }
+
+       /* Resolve URI */
+       resolved_uri = resolve_uri ( base_uri, relative_uri );
+       if ( ! resolved_uri ) {
+               rc = -ENOMEM;
+               goto done;
+       }
+
+       /* Compare result */
+       len = unparse_uri ( buf, sizeof ( buf ), resolved_uri );
+       if ( strcmp ( buf, resolved_uri_string ) != 0 ) {
+               printf ( "Resolution of \"%s\"+\"%s\" produced \"%s\"\n",
+                        base_uri_string, relative_uri_string, buf );
+               rc = -EINVAL;
+               goto done;
+       }
+
+       rc = 0;
+
+ done:
+       uri_put ( base_uri );
+       uri_put ( relative_uri );
+       uri_put ( resolved_uri );
+       if ( rc ) {
+               printf ( "URI resolution of \"%s\"+\"%s\" failed: %s\n",
+                        base_uri_string, relative_uri_string,
+                        strerror ( rc ) );
+       }
+       return rc;
+}
+
+int uri_test ( void ) {
+       unsigned int i;
+       struct uri_test *uri_test;
+       int rc;
+       int overall_rc = 0;
+
+       for ( i = 0 ; i < ( sizeof ( uri_tests ) /
+                           sizeof ( uri_tests[0] ) ) ; i++ ) {
+               uri_test = &uri_tests[i];
+               rc = test_parse_unparse ( uri_test->base_uri_string );
+               if ( rc != 0 )
+                       overall_rc = rc;
+               rc = test_parse_unparse ( uri_test->relative_uri_string );
+               if ( rc != 0 )
+                       overall_rc = rc;
+               rc = test_parse_unparse ( uri_test->resolved_uri_string );
+               if ( rc != 0 )
+                       overall_rc = rc;
+               rc = test_resolve ( uri_test->base_uri_string,
+                                   uri_test->relative_uri_string,
+                                   uri_test->resolved_uri_string );
+               if ( rc != 0 )
+                       overall_rc = rc;
+       }
+
+       if ( overall_rc )
+               printf ( "URI tests failed: %s\n", strerror ( overall_rc ) );
+       return overall_rc;
+}