Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdarg.h>
     22 #include <string.h>
     23 #include <errno.h>
     24 #include <gpxe/xfer.h>
     25 #include <gpxe/uri.h>
     26 #include <gpxe/socket.h>
     27 #include <gpxe/open.h>
     28 
     29 /** @file
     30  *
     31  * Data transfer interface opening
     32  *
     33  */
     34 
     35 /**
     36  * Open URI
     37  *
     38  * @v xfer		Data transfer interface
     39  * @v uri		URI
     40  * @ret rc		Return status code
     41  *
     42  * The URI will be regarded as being relative to the current working
     43  * URI (see churi()).
     44  */
     45 int xfer_open_uri ( struct xfer_interface *xfer, struct uri *uri ) {
     46 	struct uri_opener *opener;
     47 	struct uri *resolved_uri;
     48 	int rc = -ENOTSUP;
     49 
     50 	/* Resolve URI */
     51 	resolved_uri = resolve_uri ( cwuri, uri );
     52 	if ( ! resolved_uri )
     53 		return -ENOMEM;
     54 
     55 	/* Find opener which supports this URI scheme */
     56 	for_each_table_entry ( opener, URI_OPENERS ) {
     57 		if ( strcmp ( resolved_uri->scheme, opener->scheme ) == 0 ) {
     58 			DBGC ( xfer, "XFER %p opening %s URI\n",
     59 			       xfer, opener->scheme );
     60 			rc = opener->open ( xfer, resolved_uri );
     61 			goto done;
     62 		}
     63 	}
     64 	DBGC ( xfer, "XFER %p attempted to open unsupported URI scheme "
     65 	       "\"%s\"\n", xfer, resolved_uri->scheme );
     66 
     67  done:
     68 	uri_put ( resolved_uri );
     69 	return rc;
     70 }
     71 
     72 /**
     73  * Open URI string
     74  *
     75  * @v xfer		Data transfer interface
     76  * @v uri_string	URI string (e.g. "http://etherboot.org/kernel")
     77  * @ret rc		Return status code
     78  *
     79  * The URI will be regarded as being relative to the current working
     80  * URI (see churi()).
     81  */
     82 int xfer_open_uri_string ( struct xfer_interface *xfer,
     83 			   const char *uri_string ) {
     84 	struct uri *uri;
     85 	int rc;
     86 
     87 	DBGC ( xfer, "XFER %p opening URI %s\n", xfer, uri_string );
     88 
     89 	uri = parse_uri ( uri_string );
     90 	if ( ! uri )
     91 		return -ENOMEM;
     92 
     93 	rc = xfer_open_uri ( xfer, uri );
     94 
     95 	uri_put ( uri );
     96 	return rc;
     97 }
     98 
     99 /**
    100  * Open socket
    101  *
    102  * @v xfer		Data transfer interface
    103  * @v semantics		Communication semantics (e.g. SOCK_STREAM)
    104  * @v peer		Peer socket address
    105  * @v local		Local socket address, or NULL
    106  * @ret rc		Return status code
    107  */
    108 int xfer_open_socket ( struct xfer_interface *xfer, int semantics,
    109 		       struct sockaddr *peer, struct sockaddr *local ) {
    110 	struct socket_opener *opener;
    111 
    112 	DBGC ( xfer, "XFER %p opening (%s,%s) socket\n", xfer,
    113 	       socket_semantics_name ( semantics ),
    114 	       socket_family_name ( peer->sa_family ) );
    115 
    116 	for_each_table_entry ( opener, SOCKET_OPENERS ) {
    117 		if ( ( opener->semantics == semantics ) &&
    118 		     ( opener->family == peer->sa_family ) ) {
    119 			return opener->open ( xfer, peer, local );
    120 		}
    121 	}
    122 
    123 	DBGC ( xfer, "XFER %p attempted to open unsupported socket type "
    124 	       "(%s,%s)\n", xfer, socket_semantics_name ( semantics ),
    125 	       socket_family_name ( peer->sa_family ) );
    126 	return -ENOTSUP;
    127 }
    128 
    129 /**
    130  * Open location
    131  *
    132  * @v xfer		Data transfer interface
    133  * @v type		Location type
    134  * @v args		Remaining arguments depend upon location type
    135  * @ret rc		Return status code
    136  */
    137 int xfer_vopen ( struct xfer_interface *xfer, int type, va_list args ) {
    138 	switch ( type ) {
    139 	case LOCATION_URI_STRING: {
    140 		const char *uri_string = va_arg ( args, const char * );
    141 
    142 		return xfer_open_uri_string ( xfer, uri_string ); }
    143 	case LOCATION_URI: {
    144 		struct uri *uri = va_arg ( args, struct uri * );
    145 
    146 		return xfer_open_uri ( xfer, uri ); }
    147 	case LOCATION_SOCKET: {
    148 		int semantics = va_arg ( args, int );
    149 		struct sockaddr *peer = va_arg ( args, struct sockaddr * );
    150 		struct sockaddr *local = va_arg ( args, struct sockaddr * );
    151 
    152 		return xfer_open_socket ( xfer, semantics, peer, local ); }
    153 	default:
    154 		DBGC ( xfer, "XFER %p attempted to open unsupported location "
    155 		       "type %d\n", xfer, type );
    156 		return -ENOTSUP;
    157 	}
    158 }
    159 
    160 /**
    161  * Open location
    162  *
    163  * @v xfer		Data transfer interface
    164  * @v type		Location type
    165  * @v ...		Remaining arguments depend upon location type
    166  * @ret rc		Return status code
    167  */
    168 int xfer_open ( struct xfer_interface *xfer, int type, ... ) {
    169 	va_list args;
    170 	int rc;
    171 
    172 	va_start ( args, type );
    173 	rc = xfer_vopen ( xfer, type, args );
    174 	va_end ( args );
    175 	return rc;
    176 }
    177 
    178 /**
    179  * Reopen location
    180  *
    181  * @v xfer		Data transfer interface
    182  * @v type		Location type
    183  * @v args		Remaining arguments depend upon location type
    184  * @ret rc		Return status code
    185  *
    186  * This will close the existing connection and open a new connection
    187  * using xfer_vopen().  It is intended to be used as a .vredirect
    188  * method handler.
    189  */
    190 int xfer_vreopen ( struct xfer_interface *xfer, int type, va_list args ) {
    191 
    192 	/* Close existing connection */
    193 	xfer_close ( xfer, 0 );
    194 
    195 	/* Open new location */
    196 	return xfer_vopen ( xfer, type, args );
    197 }
    198