diff --git a/src/core/open.c b/src/core/open.c new file mode 100644 index 00000000..ffcb4e29 --- /dev/null +++ b/src/core/open.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Data transfer interface opening + * + */ + +/** Registered URI openers */ +static struct uri_opener uri_openers[0] + __table_start ( struct uri_opener, uri_openers ); +static struct uri_opener uri_openers_end[0] + __table_end ( struct uri_opener, uri_openers ); + +/** Registered socket openers */ +static struct socket_opener socket_openers[0] + __table_start ( struct socket_opener, socket_openers ); +static struct socket_opener socket_openers_end[0] + __table_end ( struct socket_opener, socket_openers ); + +/** + * Open URI + * + * @v xfer Data-transfer interface + * @v uri_string URI string (e.g. "http://etherboot.org/kernel") + * @ret rc Return status code + */ +int open_uri ( struct xfer_interface *xfer, const char *uri_string ) { + struct uri *uri; + struct uri_opener *opener; + + DBGC ( xfer, "XFER %p opening URI %s\n", xfer, uri_string ); + + uri = parse_uri ( uri_string ); + if ( ! uri ) + return -ENOMEM; + + for ( opener = uri_openers ; opener < uri_openers_end ; opener++ ) { + if ( strcmp ( uri->scheme, opener->scheme ) == 0 ) { + return opener->open ( xfer, uri ); + } + } + + DBGC ( xfer, "XFER %p attempted to open unsupported URI scheme " + "\"%s\"\n", xfer, uri->scheme ); + free_uri ( uri ); + return -ENOTSUP; +} + +/** + * Open socket + * + * @v xfer Data-transfer interface + * @v domain Communication domain (e.g. PF_INET) + * @v type Communication semantics (e.g. SOCK_STREAM) + */ +int open_socket ( struct xfer_interface *xfer, + int domain, int type, struct sockaddr *sa ) { + struct socket_opener *opener; + + DBGC ( xfer, "XFER %p opening (%s,%s) socket\n", xfer, + socket_domain_name ( domain ), socket_type_name ( type ) ); + + for ( opener = socket_openers; opener < socket_openers_end; opener++ ){ + if ( ( opener->domain == domain ) && + ( opener->type == type ) ) { + return opener->open ( xfer, sa ); + } + } + + DBGC ( xfer, "XFER %p attempted to open unsupported socket type " + "(%s,%s)\n", xfer, socket_domain_name ( domain ), + socket_type_name ( type ) ); + return -ENOTSUP; +} + +/** + * Open location + * + * @v xfer Data-transfer interface + * @v type Location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ +int vopen ( struct xfer_interface *xfer, int type, va_list args ) { + switch ( type ) { + case LOCATION_URI: { + const char *uri_string = va_arg ( args, const char * ); + + return open_uri ( xfer, uri_string ); } + case LOCATION_SOCKET: { + int domain = va_arg ( args, int ); + int type = va_arg ( args, int ); + struct sockaddr *sa = va_arg ( args, struct sockaddr * ); + + return open_socket ( xfer, domain, type, sa ); } + default: + DBGC ( xfer, "XFER %p attempted to open unsupported location " + "type %d\n", xfer, type ); + return -ENOTSUP; + } +} + +/** + * Open location + * + * @v xfer Data-transfer interface + * @v type Location type + * @v ... Remaining arguments depend upon location type + * @ret rc Return status code + */ +int open ( struct xfer_interface *xfer, int type, ... ) { + va_list args; + int rc; + + va_start ( args, type ); + rc = vopen ( xfer, type, args ); + va_end ( args ); + return rc; +} diff --git a/src/core/xfer.c b/src/core/xfer.c index bf56d060..c3993799 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -26,6 +26,38 @@ * */ +/** + * Send redirection event + * + * @v xfer Data-transfer interface + * @v type New location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ +int vredirect ( struct xfer_interface *xfer, int type, va_list args ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->vredirect ( dest, type, args ); +} + +/** + * Send redirection event + * + * @v xfer Data-transfer interface + * @v type New location type + * @v ... Remaining arguments depend upon location type + * @ret rc Return status code + */ +int redirect ( struct xfer_interface *xfer, int type, ... ) { + va_list args; + int rc; + + va_start ( args, type ); + rc = vredirect ( xfer, type, args ); + va_end ( args ); + return rc; +} + /** * Deliver datagram * @@ -36,14 +68,35 @@ int deliver ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { struct xfer_interface *dest = xfer_dest ( xfer ); - return dest->op->deliver ( dest, xfer, iobuf ); + return dest->op->deliver ( dest, iobuf ); } /** * Deliver datagram as raw data * * @v xfer Data-transfer interface - * @v src Source interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ +int deliver_raw ( struct xfer_interface *xfer, const void *data, size_t len ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->deliver_raw ( dest, data, len ); +} + +/**************************************************************************** + * + * Helper methods + * + * These functions are designed to be used as methods in the + * xfer_interface_operations table. + * + */ + +/** + * Deliver datagram as raw data + * + * @v xfer Data-transfer interface * @v iobuf Datagram I/O buffer * @ret rc Return status code * @@ -51,12 +104,10 @@ int deliver ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { * data transfer interfaces that prefer to handle raw data. */ int deliver_as_raw ( struct xfer_interface *xfer, - struct xfer_interface *src, struct io_buffer *iobuf ) { int rc; - rc = xfer->op->deliver_raw ( xfer, src, iobuf->data, - iob_len ( iobuf ) ); + rc = xfer->op->deliver_raw ( xfer, iobuf->data, iob_len ( iobuf ) ); free_iob ( iobuf ); return rc; } @@ -65,7 +116,6 @@ int deliver_as_raw ( struct xfer_interface *xfer, * Deliver datagram as I/O buffer * * @v xfer Data-transfer interface - * @v src Source interface * @v data Data buffer * @v len Length of data buffer * @ret rc Return status code @@ -74,32 +124,34 @@ int deliver_as_raw ( struct xfer_interface *xfer, * for data transfer interfaces that prefer to handle I/O buffers. */ int deliver_as_iobuf ( struct xfer_interface *xfer, - struct xfer_interface *src, const void *data, size_t len ) { struct io_buffer *iobuf; -#warning "Do we need interface-specific I/O buffer allocation?" iobuf = alloc_iob ( len ); if ( ! iobuf ) return -ENOMEM; memcpy ( iob_put ( iobuf, len ), data, len ); - return xfer->op->deliver ( xfer, src, iobuf ); + return xfer->op->deliver ( xfer, iobuf ); } +/**************************************************************************** + * + * Null data transfer interface + * + */ + /** * Null deliver datagram as raw data * * @v xfer Data-transfer interface - * @v src Source interface * @v data Data buffer * @v len Length of data buffer * @ret rc Return status code */ static int null_deliver_raw ( struct xfer_interface *xfer, - struct xfer_interface *src, const void *data __unused, size_t len ) { - DBGC ( src, "XFER %p->%p %zd bytes delivered %s\n", src, xfer, len, + DBGC ( xfer, "XFER %p %zd bytes delivered %s\n", xfer, len, ( ( xfer == &null_xfer ) ? "before connection" : "after termination" ) ); return -EPIPE; diff --git a/src/include/gpxe/open.h b/src/include/gpxe/open.h new file mode 100644 index 00000000..8839dc28 --- /dev/null +++ b/src/include/gpxe/open.h @@ -0,0 +1,81 @@ +#ifndef _GPXE_OPEN_H +#define _GPXE_OPEN_H + +/** @file + * + * Data transfer interface opening + * + */ + +#include + +struct xfer_interface; +struct uri; +struct sockaddr; + +/** Location types */ +enum { + /** Location is a URI string + * + * Parameter list for open() is: + * + * const char *uri_string; + */ + LOCATION_URI = 1, + /** Location is a socket + * + * Parameter list for open() is: + * + * + */ + LOCATION_SOCKET, +}; + +/** A URI opener */ +struct uri_opener { + /** URI protocol name + * + * This is the "scheme" portion of the URI, e.g. "http" or + * "file". + */ + const char *scheme; + /** Open URI + * + * @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 ); +}; + +/** Register a URI opener */ +#define __uri_opener __table ( struct uri_opener, uri_openers, 01 ) + +/** A socket opener */ +struct socket_opener { + /** Communication domain (e.g. PF_INET) */ + int domain; + /** Communication semantics (e.g. SOCK_STREAM) */ + int type; + /** Open socket + * + * @v xfer Data-transfer interface + * @v sa Socket address + * @ret rc Return status code + */ + int ( * open ) ( struct xfer_interface *xfer, struct sockaddr *sa ); +}; + +/** Register a socket opener */ +#define __socket_opener __table ( struct socket_opener, socket_openers, 01 ) + +extern int open_uri ( struct xfer_interface *xfer, const char *uri_string ); +extern int open_socket ( struct xfer_interface *xfer, + int domain, int type, struct sockaddr *sa ); +extern int vopen ( struct xfer_interface *xfer, int type, va_list args ); +extern int open ( struct xfer_interface *xfer, int type, ... ); + +#endif /* _GPXE_OPEN_H */ diff --git a/src/include/gpxe/xfer.h b/src/include/gpxe/xfer.h index 7a10b860..0b8bf4ce 100644 --- a/src/include/gpxe/xfer.h +++ b/src/include/gpxe/xfer.h @@ -8,6 +8,7 @@ */ #include +#include #include #include @@ -15,10 +16,38 @@ struct xfer_interface; /** Data transfer interface operations */ struct xfer_interface_operations { + + /* Missing features: + * + * notification of non-close status - e.g. connected/opened, ... + * + * seek + * + * prompt for data delivery + * + * I/O buffer preparation + * + */ + + + /** Close interface + * + * @v xfer Data-transfer interface + * @v rc Reason for close + */ + void ( * close ) ( struct xfer_interface *xfer, int rc ); + /** Redirect to new location + * + * @v xfer Data-transfer interface + * @v type New location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ + int ( * vredirect ) ( struct xfer_interface *xfer, int type, + va_list args ); /** Deliver datagram * * @v xfer Data-transfer interface - * @v src Source interface * @v iobuf Datagram I/O buffer * @ret rc Return status code * @@ -27,12 +56,10 @@ struct xfer_interface_operations { * deliver_as_raw(). */ int ( * deliver ) ( struct xfer_interface *xfer, - struct xfer_interface *src, struct io_buffer *iobuf ); /** Deliver datagram as raw data * * @v xfer Data-transfer interface - * @v src Source interface * @v data Data buffer * @v len Length of data buffer * @ret rc Return status code @@ -42,7 +69,6 @@ struct xfer_interface_operations { * deliver_as_iobuf(). */ int ( * deliver_raw ) ( struct xfer_interface *xfer, - struct xfer_interface *src, const void *data, size_t len ); }; @@ -57,11 +83,15 @@ struct xfer_interface { extern struct xfer_interface null_xfer; extern struct xfer_interface_operations null_xfer_ops; +extern int vredirect ( struct xfer_interface *xfer, int type, va_list args ); +extern int redirect ( struct xfer_interface *xfer, int type, ... ); +extern int deliver ( struct xfer_interface *xfer, struct io_buffer *iobuf ); +extern int deliver_raw ( struct xfer_interface *xfer, + const void *data, size_t len ); + extern int deliver_as_raw ( struct xfer_interface *xfer, - struct xfer_interface *src, struct io_buffer *iobuf ); extern int deliver_as_iobuf ( struct xfer_interface *xfer, - struct xfer_interface *src, const void *data, size_t len ); /**