iPXE
open.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdarg.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <ipxe/xfer.h>
00030 #include <ipxe/uri.h>
00031 #include <ipxe/socket.h>
00032 #include <ipxe/open.h>
00033 
00034 /** @file
00035  *
00036  * Data transfer interface opening
00037  *
00038  */
00039 
00040 /**
00041  * Find opener for URI scheme
00042  *
00043  * @v scheme            URI scheme
00044  * @ret opener          Opener, or NULL
00045  */
00046 struct uri_opener * xfer_uri_opener ( const char *scheme ) {
00047         struct uri_opener *opener;
00048 
00049         for_each_table_entry ( opener, URI_OPENERS ) {
00050                 if ( strcmp ( scheme, opener->scheme ) == 0 )
00051                         return opener;
00052         }
00053         return NULL;
00054 }
00055 
00056 /**
00057  * Open URI
00058  *
00059  * @v intf              Data transfer interface
00060  * @v uri               URI
00061  * @ret rc              Return status code
00062  *
00063  * The URI will be regarded as being relative to the current working
00064  * URI (see churi()).
00065  */
00066 int xfer_open_uri ( struct interface *intf, struct uri *uri ) {
00067         struct uri_opener *opener;
00068         struct uri *resolved_uri;
00069         int rc;
00070 
00071         /* Resolve URI */
00072         resolved_uri = resolve_uri ( cwuri, uri );
00073         if ( ! resolved_uri ) {
00074                 rc = -ENOMEM;
00075                 goto err_resolve_uri;
00076         }
00077 
00078         /* Find opener which supports this URI scheme */
00079         opener = xfer_uri_opener ( resolved_uri->scheme );
00080         if ( ! opener ) {
00081                 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
00082                        "unsupported URI scheme \"%s\"\n",
00083                        INTF_DBG ( intf ), resolved_uri->scheme );
00084                 rc = -ENOTSUP;
00085                 goto err_opener;
00086         }
00087 
00088         /* Call opener */
00089         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening %s URI\n",
00090                INTF_DBG ( intf ), resolved_uri->scheme );
00091         if ( ( rc = opener->open ( intf, resolved_uri ) ) != 0 ) {
00092                 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " could not open: "
00093                        "%s\n", INTF_DBG ( intf ), strerror ( rc ) );
00094                 goto err_open;
00095         }
00096 
00097  err_open:
00098  err_opener:
00099         uri_put ( resolved_uri );
00100  err_resolve_uri:
00101         return rc;
00102 }
00103 
00104 /**
00105  * Open URI string
00106  *
00107  * @v intf              Data transfer interface
00108  * @v uri_string        URI string (e.g. "http://ipxe.org/kernel")
00109  * @ret rc              Return status code
00110  *
00111  * The URI will be regarded as being relative to the current working
00112  * URI (see churi()).
00113  */
00114 int xfer_open_uri_string ( struct interface *intf,
00115                            const char *uri_string ) {
00116         struct uri *uri;
00117         int rc;
00118 
00119         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening URI %s\n",
00120                INTF_DBG ( intf ), uri_string );
00121 
00122         uri = parse_uri ( uri_string );
00123         if ( ! uri )
00124                 return -ENOMEM;
00125 
00126         rc = xfer_open_uri ( intf, uri );
00127 
00128         uri_put ( uri );
00129         return rc;
00130 }
00131 
00132 /**
00133  * Open socket
00134  *
00135  * @v intf              Data transfer interface
00136  * @v semantics         Communication semantics (e.g. SOCK_STREAM)
00137  * @v peer              Peer socket address
00138  * @v local             Local socket address, or NULL
00139  * @ret rc              Return status code
00140  */
00141 int xfer_open_socket ( struct interface *intf, int semantics,
00142                        struct sockaddr *peer, struct sockaddr *local ) {
00143         struct socket_opener *opener;
00144 
00145         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening (%s,%s) socket\n",
00146                INTF_DBG ( intf ), socket_semantics_name ( semantics ),
00147                socket_family_name ( peer->sa_family ) );
00148 
00149         for_each_table_entry ( opener, SOCKET_OPENERS ) {
00150                 if ( ( opener->semantics == semantics ) &&
00151                      ( opener->family == peer->sa_family ) ) {
00152                         return opener->open ( intf, peer, local );
00153                 }
00154         }
00155 
00156         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
00157                "unsupported socket type (%s,%s)\n",
00158                INTF_DBG ( intf ), socket_semantics_name ( semantics ),
00159                socket_family_name ( peer->sa_family ) );
00160         return -ENOTSUP;
00161 }
00162 
00163 /**
00164  * Open location
00165  *
00166  * @v intf              Data transfer interface
00167  * @v type              Location type
00168  * @v args              Remaining arguments depend upon location type
00169  * @ret rc              Return status code
00170  */
00171 int xfer_vopen ( struct interface *intf, int type, va_list args ) {
00172         switch ( type ) {
00173         case LOCATION_URI_STRING: {
00174                 const char *uri_string = va_arg ( args, const char * );
00175 
00176                 return xfer_open_uri_string ( intf, uri_string ); }
00177         case LOCATION_URI: {
00178                 struct uri *uri = va_arg ( args, struct uri * );
00179 
00180                 return xfer_open_uri ( intf, uri ); }
00181         case LOCATION_SOCKET: {
00182                 int semantics = va_arg ( args, int );
00183                 struct sockaddr *peer = va_arg ( args, struct sockaddr * );
00184                 struct sockaddr *local = va_arg ( args, struct sockaddr * );
00185 
00186                 return xfer_open_socket ( intf, semantics, peer, local ); }
00187         default:
00188                 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to "
00189                        "open unsupported location type %d\n",
00190                        INTF_DBG ( intf ), type );
00191                 return -ENOTSUP;
00192         }
00193 }
00194 
00195 /**
00196  * Open location
00197  *
00198  * @v intf              Data transfer interface
00199  * @v type              Location type
00200  * @v ...               Remaining arguments depend upon location type
00201  * @ret rc              Return status code
00202  */
00203 int xfer_open ( struct interface *intf, int type, ... ) {
00204         va_list args;
00205         int rc;
00206 
00207         va_start ( args, type );
00208         rc = xfer_vopen ( intf, type, args );
00209         va_end ( args );
00210         return rc;
00211 }
00212 
00213 /**
00214  * Reopen location
00215  *
00216  * @v intf              Data transfer interface
00217  * @v type              Location type
00218  * @v args              Remaining arguments depend upon location type
00219  * @ret rc              Return status code
00220  *
00221  * This will close the existing connection and open a new connection
00222  * using xfer_vopen().  It is intended to be used as a .vredirect
00223  * method handler.
00224  */
00225 int xfer_vreopen ( struct interface *intf, int type, va_list args ) {
00226 
00227         /* Close existing connection */
00228         intf_restart ( intf, 0 );
00229 
00230         /* Open new location */
00231         return xfer_vopen ( intf, type, args );
00232 }