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