1 /*
2 * Copyright (C) 2007 Michael Brown <mbrown@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 */
xfer_open_uri(struct xfer_interface * xfer,struct uri * uri)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 */
xfer_open_uri_string(struct xfer_interface * xfer,const char * uri_string)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 */
xfer_open_socket(struct xfer_interface * xfer,int semantics,struct sockaddr * peer,struct sockaddr * local)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 */
xfer_vopen(struct xfer_interface * xfer,int type,va_list args)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 */
xfer_open(struct xfer_interface * xfer,int type,...)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 */
xfer_vreopen(struct xfer_interface * xfer,int type,va_list args)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