iPXE
httpconn.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/**
28 * @file
29 *
30 * Hyper Text Transfer Protocol (HTTP) connection management
31 *
32 */
33
34#include <stdlib.h>
35#include <string.h>
36#include <strings.h>
37#include <errno.h>
38#include <byteswap.h>
39#include <ipxe/tcpip.h>
40#include <ipxe/uri.h>
41#include <ipxe/timer.h>
42#include <ipxe/xfer.h>
43#include <ipxe/open.h>
44#include <ipxe/pool.h>
45#include <ipxe/http.h>
46
47/** HTTP pooled connection expiry time */
48#define HTTP_CONN_EXPIRY ( 10 * TICKS_PER_SEC )
49
50/** HTTP connection pool */
51static LIST_HEAD ( http_connection_pool );
52
53/**
54 * Identify HTTP scheme
55 *
56 * @v uri URI
57 * @ret scheme HTTP scheme, or NULL
58 */
59static struct http_scheme * http_scheme ( struct uri *uri ) {
60 struct http_scheme *scheme;
61
62 /* Sanity check */
63 if ( ! uri->scheme )
64 return NULL;
65
66 /* Identify scheme */
68 if ( strcasecmp ( uri->scheme, scheme->name ) == 0 )
69 return scheme;
70 }
71
72 return NULL;
73}
74
75/**
76 * Free HTTP connection
77 *
78 * @v refcnt Reference count
79 */
80static void http_conn_free ( struct refcnt *refcnt ) {
81 struct http_connection *conn =
83
84 /* Free connection */
85 uri_put ( conn->uri );
86 free ( conn );
87}
88
89/**
90 * Close HTTP connection
91 *
92 * @v conn HTTP connection
93 * @v rc Reason for close
94 */
95static void http_conn_close ( struct http_connection *conn, int rc ) {
96
97 /* Remove from connection pool, if applicable */
98 pool_del ( &conn->pool );
99
100 /* Shut down interfaces */
101 intf_shutdown ( &conn->socket, rc );
102 intf_shutdown ( &conn->xfer, rc );
103 if ( rc == 0 ) {
104 DBGC2 ( conn, "HTTPCONN %p closed %s://%s\n",
105 conn, conn->scheme->name, conn->uri->host );
106 } else {
107 DBGC ( conn, "HTTPCONN %p closed %s://%s: %s\n",
108 conn, conn->scheme->name, conn->uri->host,
109 strerror ( rc ) );
110 }
111}
112
113/**
114 * Disconnect idle HTTP connection
115 *
116 * @v pool Pooled connection
117 */
118static void http_conn_expired ( struct pooled_connection *pool ) {
119 struct http_connection *conn =
121
122 /* Close connection */
123 http_conn_close ( conn, 0 /* Not an error to close idle connection */ );
124}
125
126/**
127 * Receive data from transport layer interface
128 *
129 * @v http HTTP connection
130 * @v iobuf I/O buffer
131 * @v meta Transfer metadata
132 * @ret rc Return status code
133 */
135 struct io_buffer *iobuf,
136 struct xfer_metadata *meta ) {
137
138 /* Mark connection as alive */
139 pool_alive ( &conn->pool );
140
141 /* Pass on to data transfer interface */
142 return xfer_deliver ( &conn->xfer, iobuf, meta );
143}
144
145/**
146 * Close HTTP connection transport layer interface
147 *
148 * @v http HTTP connection
149 * @v rc Reason for close
150 */
151static void http_conn_socket_close ( struct http_connection *conn, int rc ) {
152
153 /* If we are reopenable (i.e. we are a recycled connection
154 * from the connection pool, and we have received no data from
155 * the underlying socket since we were pooled), then suggest
156 * that the client should reopen the connection.
157 */
158 if ( pool_is_reopenable ( &conn->pool ) )
159 pool_reopen ( &conn->xfer );
160
161 /* Close the connection */
162 http_conn_close ( conn, rc );
163}
164
165/**
166 * Recycle this connection after closing
167 *
168 * @v http HTTP connection
169 */
170static void http_conn_xfer_recycle ( struct http_connection *conn ) {
171
172 /* Mark connection as recyclable */
173 pool_recyclable ( &conn->pool );
174 DBGC2 ( conn, "HTTPCONN %p keepalive enabled\n", conn );
175}
176
177/**
178 * Close HTTP connection data transfer interface
179 *
180 * @v conn HTTP connection
181 * @v rc Reason for close
182 */
183static void http_conn_xfer_close ( struct http_connection *conn, int rc ) {
184
185 /* Add to the connection pool if keepalive is enabled and no
186 * error occurred.
187 */
188 if ( ( rc == 0 ) && pool_is_recyclable ( &conn->pool ) ) {
189 intf_restart ( &conn->xfer, rc );
190 pool_add ( &conn->pool, &http_connection_pool,
192 DBGC2 ( conn, "HTTPCONN %p pooled %s://%s\n",
193 conn, conn->scheme->name, conn->uri->host );
194 return;
195 }
196
197 /* Otherwise, close the connection */
198 http_conn_close ( conn, rc );
199}
200
201/** HTTP connection socket interface operations */
208
209/** HTTP connection socket interface descriptor */
211 INTF_DESC_PASSTHRU ( struct http_connection, socket,
213
214/** HTTP connection data transfer interface operations */
221
222/** HTTP connection data transfer interface descriptor */
224 INTF_DESC_PASSTHRU ( struct http_connection, xfer,
226
227/**
228 * Connect to an HTTP server
229 *
230 * @v xfer Data transfer interface
231 * @v uri Connection URI
232 * @ret rc Return status code
233 *
234 * HTTP connections are pooled. The caller should be prepared to
235 * receive a pool_reopen() message.
236 */
237int http_connect ( struct interface *xfer, struct uri *uri ) {
238 struct http_connection *conn;
239 struct http_scheme *scheme;
240 struct sockaddr_tcpip server;
241 unsigned int port;
242 int rc;
243
244 /* Identify scheme */
245 scheme = http_scheme ( uri );
246 if ( ! scheme )
247 return -ENOTSUP;
248
249 /* Sanity check */
250 if ( ! uri->host )
251 return -EINVAL;
252
253 /* Identify port */
254 port = uri_port ( uri, scheme->port );
255
256 /* Look for a reusable connection in the pool. Reuse the most
257 * recent connection in order to accommodate authentication
258 * schemes that break the stateless nature of HTTP and rely on
259 * the same connection being reused for authentication
260 * responses.
261 */
262 list_for_each_entry_reverse ( conn, &http_connection_pool, pool.list ) {
263
264 /* Sanity checks */
265 assert ( conn->uri != NULL );
266 assert ( conn->uri->host != NULL );
267
268 /* Reuse connection, if possible */
269 if ( ( scheme == conn->scheme ) &&
270 ( strcmp ( uri->host, conn->uri->host ) == 0 ) &&
271 ( port == uri_port ( conn->uri, scheme->port ) ) ) {
272
273 /* Remove from connection pool, stop timer,
274 * attach to parent interface, and return.
275 */
276 pool_del ( &conn->pool );
277 intf_plug_plug ( &conn->xfer, xfer );
278 DBGC2 ( conn, "HTTPCONN %p reused %s://%s:%d\n", conn,
279 conn->scheme->name, conn->uri->host, port );
280 return 0;
281 }
282 }
283
284 /* Allocate and initialise structure */
285 conn = zalloc ( sizeof ( *conn ) );
286 if ( ! conn ) {
287 rc = -ENOMEM;
288 goto err_alloc;
289 }
290 ref_init ( &conn->refcnt, http_conn_free );
291 conn->uri = uri_get ( uri );
292 conn->scheme = scheme;
293 intf_init ( &conn->socket, &http_conn_socket_desc, &conn->refcnt );
294 intf_init ( &conn->xfer, &http_conn_xfer_desc, &conn->refcnt );
295 pool_init ( &conn->pool, http_conn_expired, &conn->refcnt );
296
297 /* Open socket */
298 memset ( &server, 0, sizeof ( server ) );
299 server.st_port = htons ( port );
300 if ( ( rc = xfer_open_named_socket ( &conn->socket, SOCK_STREAM,
301 ( struct sockaddr * ) &server,
302 uri->host, NULL ) ) != 0 )
303 goto err_open;
304
305 /* Add filter, if any */
306 if ( scheme->filter && ( ( rc = scheme->filter ( conn ) ) != 0 ) )
307 goto err_filter;
308
309 /* Attach to parent interface, mortalise self, and return */
310 intf_plug_plug ( &conn->xfer, xfer );
311 ref_put ( &conn->refcnt );
312
313 DBGC2 ( conn, "HTTPCONN %p created %s://%s:%d\n", conn,
314 conn->scheme->name, conn->uri->host, port );
315 return 0;
316
317 err_filter:
318 err_open:
319 DBGC2 ( conn, "HTTPCONN %p could not create %s://%s:%d: %s\n", conn,
320 conn->scheme->name, conn->uri->host, port, strerror ( rc ) );
321 http_conn_close ( conn, rc );
322 ref_put ( &conn->refcnt );
323 err_alloc:
324 return rc;
325}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
u8 port
Port number.
Definition CIB_PRM.h:3
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define SOCK_STREAM
Definition socket.h:25
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Hyper Text Transport Protocol.
#define HTTP_SCHEMES
HTTP scheme table.
Definition http.h:55
static struct interface_descriptor http_conn_xfer_desc
HTTP connection data transfer interface descriptor.
Definition httpconn.c:223
static void http_conn_socket_close(struct http_connection *conn, int rc)
Close HTTP connection transport layer interface.
Definition httpconn.c:151
static struct http_scheme * http_scheme(struct uri *uri)
Identify HTTP scheme.
Definition httpconn.c:59
#define HTTP_CONN_EXPIRY
HTTP pooled connection expiry time.
Definition httpconn.c:48
static struct interface_operation http_conn_socket_operations[]
HTTP connection socket interface operations.
Definition httpconn.c:202
static struct interface_descriptor http_conn_socket_desc
HTTP connection socket interface descriptor.
Definition httpconn.c:210
static int http_conn_socket_deliver(struct http_connection *conn, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive data from transport layer interface.
Definition httpconn.c:134
static void http_conn_xfer_recycle(struct http_connection *conn)
Recycle this connection after closing.
Definition httpconn.c:170
static void http_conn_expired(struct pooled_connection *pool)
Disconnect idle HTTP connection.
Definition httpconn.c:118
static struct interface_operation http_conn_xfer_operations[]
HTTP connection data transfer interface operations.
Definition httpconn.c:215
static void http_conn_close(struct http_connection *conn, int rc)
Close HTTP connection.
Definition httpconn.c:95
static void http_conn_xfer_close(struct http_connection *conn, int rc)
Close HTTP connection data transfer interface.
Definition httpconn.c:183
static void http_conn_free(struct refcnt *refcnt)
Free HTTP connection.
Definition httpconn.c:80
int http_connect(struct interface *xfer, struct uri *uri)
Connect to an HTTP server.
Definition httpconn.c:237
#define htons(value)
Definition byteswap.h:136
Transport-network layer interface.
iPXE timers
String functions.
void * memset(void *dest, int character, size_t len) __nonnull
String functions.
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition interface.c:344
#define INTF_DESC_PASSTHRU(object_type, intf, operations, passthru)
Define an object interface descriptor with pass-through interface.
Definition interface.h:98
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
#define list_for_each_entry_reverse(pos, head, member)
Iterate over entries in a list in reverse order.
Definition list.h:445
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
Data transfer interface opening.
void pool_add(struct pooled_connection *pool, struct list_head *list, unsigned long expiry)
Add connection to pool.
Definition pool.c:64
void pool_recycle(struct interface *intf)
Recycle this connection after closing.
Definition pool.c:42
void pool_del(struct pooled_connection *pool)
Remove connection from pool.
Definition pool.c:83
void pool_reopen(struct interface *intf)
Reopen a defunct connection.
Definition pool.c:52
Pooled connections.
timer_init & pool
Definition pool.h:66
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
int xfer_open_named_socket(struct interface *xfer, int semantics, struct sockaddr *peer, const char *name, struct sockaddr *local)
Open named socket.
Definition resolv.c:403
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int strcmp(const char *first, const char *second)
Compare strings.
Definition string.c:174
int strcasecmp(const char *first, const char *second)
Compare case-insensitive strings.
Definition string.c:209
An HTTP connection.
Definition http.h:72
struct interface socket
Transport layer interface.
Definition http.h:85
struct uri * uri
Connection URI.
Definition http.h:81
struct pooled_connection pool
Pooled connection.
Definition http.h:89
struct refcnt refcnt
Reference count.
Definition http.h:74
struct interface xfer
Data transfer interface.
Definition http.h:87
struct http_scheme * scheme
HTTP scheme.
Definition http.h:83
An HTTP URI scheme.
Definition http.h:41
unsigned int port
Default port.
Definition http.h:45
int(* filter)(struct http_connection *conn)
Transport-layer filter (if any)
Definition http.h:51
const char * name
Scheme name (e.g.
Definition http.h:43
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
A pooled connection.
Definition pool.h:18
A reference counter.
Definition refcnt.h:27
TCP/IP socket address.
Definition tcpip.h:76
uint16_t st_port
TCP/IP port.
Definition tcpip.h:82
Generalized socket address structure.
Definition socket.h:97
A Uniform Resource Identifier.
Definition uri.h:65
const char * host
Host name.
Definition uri.h:77
const char * scheme
Scheme.
Definition uri.h:69
Data transfer metadata.
Definition xfer.h:23
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
unsigned int uri_port(const struct uri *uri, unsigned int default_port)
Get port from URI.
Definition uri.c:457
Uniform Resource Identifiers.
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition uri.h:195
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition uri.h:206
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
Data transfer interfaces.