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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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 */
51 static LIST_HEAD ( http_connection_pool );
52 
53 /**
54  * Identify HTTP scheme
55  *
56  * @v uri URI
57  * @ret scheme HTTP scheme, or NULL
58  */
59 static 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  */
80 static 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  */
95 static 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  */
118 static void http_conn_expired ( struct pooled_connection *pool ) {
119  struct http_connection *conn =
120  container_of ( pool, struct http_connection, pool );
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  */
134 static int http_conn_socket_deliver ( struct http_connection *conn,
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  */
151 static 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  */
170 static 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  */
183 static 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 */
205  INTF_OP ( intf_close, struct http_connection *,
207 };
208 
209 /** HTTP connection socket interface descriptor */
211  INTF_DESC_PASSTHRU ( struct http_connection, socket,
213 
214 /** HTTP connection data transfer interface operations */
218  INTF_OP ( intf_close, struct http_connection *,
220 };
221 
222 /** HTTP connection data transfer interface descriptor */
224  INTF_DESC_PASSTHRU ( struct http_connection, xfer,
225  http_conn_xfer_operations, socket );
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  */
237 int 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 }
static struct interface_operation http_conn_socket_operations[]
HTTP connection socket interface operations.
Definition: httpconn.c:202
#define EINVAL
Invalid argument.
Definition: errno.h:429
An object interface operation.
Definition: interface.h:18
TCP/IP socket address.
Definition: tcpip.h:76
struct refcnt refcnt
Reference count.
Definition: http.h:74
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void pool_add(struct pooled_connection *pool, struct list_head *list, unsigned long expiry)
Add connection to pool.
Definition: pool.c:64
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:250
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition: interface.c:344
Data transfer metadata.
Definition: xfer.h:23
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:279
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition: uri.h:206
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition: uri.h:195
static struct interface_descriptor http_conn_socket_desc
HTTP connection socket interface descriptor.
Definition: httpconn.c:210
timer_init & pool
Definition: pool.h:66
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:65
Error codes.
Pooled connections.
unsigned int port
Default port.
Definition: http.h:45
int(* filter)(struct http_connection *conn)
Transport-layer filter (if any)
Definition: http.h:51
#define DBGC(...)
Definition: compiler.h:505
static struct interface_operation http_conn_xfer_operations[]
HTTP connection data transfer interface operations.
Definition: httpconn.c:215
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition: interface.c:108
int strcasecmp(const char *first, const char *second)
Compare case-insensitive strings.
Definition: string.c:209
iPXE timers
A pooled connection.
Definition: pool.h:18
struct interface socket
Transport layer interface.
Definition: http.h:85
Uniform Resource Identifiers.
void pool_del(struct pooled_connection *pool)
Remove connection from pool.
Definition: pool.c:83
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
struct interface xfer
Data transfer interface.
Definition: http.h:87
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:27
int http_connect(struct interface *xfer, struct uri *uri)
Connect to an HTTP server.
Definition: httpconn.c:237
#define ENOMEM
Not enough space.
Definition: errno.h:535
const char * scheme
Scheme.
Definition: uri.h:69
u8 port
Port number.
Definition: CIB_PRM.h:31
static struct http_scheme * http_scheme(struct uri *uri)
Identify HTTP scheme.
Definition: httpconn.c:59
Hyper Text Transport Protocol.
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
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
An object interface.
Definition: interface.h:125
static void http_conn_socket_close(struct http_connection *conn, int rc)
Close HTTP connection transport layer interface.
Definition: httpconn.c:151
#define list_for_each_entry_reverse(pos, head, member)
Iterate over entries in a list in reverse order.
Definition: list.h:445
Transport-network layer interface.
void pool_reopen(struct interface *intf)
Reopen a defunct connection.
Definition: pool.c:52
static void http_conn_xfer_close(struct http_connection *conn, int rc)
Close HTTP connection data transfer interface.
Definition: httpconn.c:183
const char * name
Scheme name (e.g.
Definition: http.h:43
uint16_t st_port
TCP/IP port.
Definition: tcpip.h:82
Generalized socket address structure.
Definition: socket.h:97
An object interface descriptor.
Definition: interface.h:56
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:33
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
static void http_conn_close(struct http_connection *conn, int rc)
Close HTTP connection.
Definition: httpconn.c:95
#define SOCK_STREAM
Definition: socket.h:25
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:195
Data transfer interface opening.
const char * host
Host name.
Definition: uri.h:77
struct http_scheme * scheme
HTTP scheme.
Definition: http.h:83
#define HTTP_SCHEMES
HTTP scheme table.
Definition: http.h:55
#define HTTP_CONN_EXPIRY
HTTP pooled connection expiry time.
Definition: httpconn.c:48
An HTTP URI scheme.
Definition: http.h:41
#define DBGC2(...)
Definition: compiler.h:522
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:174
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
FILE_SECBOOT(PERMITTED)
struct uri * uri
Connection URI.
Definition: http.h:81
static void http_conn_free(struct refcnt *refcnt)
Free HTTP connection.
Definition: httpconn.c:80
unsigned int uri_port(const struct uri *uri, unsigned int default_port)
Get port from URI.
Definition: uri.c:456
A Uniform Resource Identifier.
Definition: uri.h:65
#define INTF_DESC_PASSTHRU(object_type, intf, operations, passthru)
Define an object interface descriptor with pass-through interface.
Definition: interface.h:98
static void http_conn_expired(struct pooled_connection *pool)
Disconnect idle HTTP connection.
Definition: httpconn.c:118
uint8_t meta
Metadata flags.
Definition: ena.h:14
void pool_recycle(struct interface *intf)
Recycle this connection after closing.
Definition: pool.c:42
static void http_conn_xfer_recycle(struct http_connection *conn)
Recycle this connection after closing.
Definition: httpconn.c:170
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:204
struct pooled_connection pool
Pooled connection.
Definition: http.h:89
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
An HTTP connection.
Definition: http.h:72
#define htons(value)
Definition: byteswap.h:136
static LIST_HEAD(http_connection_pool)
HTTP connection pool.
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 ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:107
String functions.
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38
static struct interface_descriptor http_conn_xfer_desc
HTTP connection data transfer interface descriptor.
Definition: httpconn.c:223