iPXE
peermux.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 (at your option) 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#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <errno.h>
31#include <ipxe/uri.h>
32#include <ipxe/xferbuf.h>
33#include <ipxe/job.h>
34#include <ipxe/peerblk.h>
35#include <ipxe/peermux.h>
36
37/** @file
38 *
39 * Peer Content Caching and Retrieval (PeerDist) protocol multiplexer
40 *
41 */
42
43/**
44 * Free PeerDist download multiplexer
45 *
46 * @v refcnt Reference count
47 */
48static void peermux_free ( struct refcnt *refcnt ) {
49 struct peerdist_multiplexer *peermux =
51
52 uri_put ( peermux->uri );
53 xferbuf_free ( &peermux->buffer );
54 free ( peermux );
55}
56
57/**
58 * Close PeerDist download multiplexer
59 *
60 * @v peermux PeerDist download multiplexer
61 * @v rc Reason for close
62 */
63static void peermux_close ( struct peerdist_multiplexer *peermux, int rc ) {
64 unsigned int i;
65
66 /* Stop block download initiation process */
67 process_del ( &peermux->process );
68
69 /* Shut down all block downloads */
70 for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ )
71 intf_shutdown ( &peermux->block[i].xfer, rc );
72
73 /* Shut down all other interfaces (which may be connected to
74 * the same object).
75 */
76 intf_nullify ( &peermux->info ); /* avoid potential loops */
77 intf_shutdown ( &peermux->xfer, rc );
78 intf_shutdown ( &peermux->info, rc );
79}
80
81/**
82 * Report progress of PeerDist download
83 *
84 * @v peermux PeerDist download multiplexer
85 * @v progress Progress report to fill in
86 * @ret ongoing_rc Ongoing job status code (if known)
87 */
88static int peermux_progress ( struct peerdist_multiplexer *peermux,
89 struct job_progress *progress ) {
90 struct peerdist_statistics *stats = &peermux->stats;
91 unsigned int percentage;
92
93 /* Construct PeerDist status message */
94 if ( stats->total ) {
95 percentage = ( ( 100 * stats->local ) / stats->total );
96 snprintf ( progress->message, sizeof ( progress->message ),
97 "%3d%% from %d peers", percentage, stats->peers );
98 }
99
100 return 0;
101}
102
103/**
104 * Receive content information
105 *
106 * @v peermux PeerDist download multiplexer
107 * @v iobuf I/O buffer
108 * @v meta Data transfer metadata
109 * @ret rc Return status code
110 */
111static int peermux_info_deliver ( struct peerdist_multiplexer *peermux,
112 struct io_buffer *iobuf,
113 struct xfer_metadata *meta ) {
114 int rc;
115
116 /* Add data to buffer */
117 if ( ( rc = xferbuf_deliver ( &peermux->buffer, iobuf, meta ) ) != 0 )
118 goto err;
119
120 return 0;
121
122 err:
123 peermux_close ( peermux, rc );
124 return rc;
125}
126
127/**
128 * Close content information interface
129 *
130 * @v peermux PeerDist download multiplexer
131 * @v rc Reason for close
132 */
133static void peermux_info_close ( struct peerdist_multiplexer *peermux, int rc ){
134 struct xfer_buffer *buffer = &peermux->buffer;
135 struct peerdist_info *info = &peermux->cache.info;
136 size_t len;
137
138 /* Terminate download on error */
139 if ( rc != 0 )
140 goto err;
141
142 /* Successfully closing the content information interface
143 * indicates that the content information has been fully
144 * received, and initiates the actual PeerDist download.
145 */
146
147 /* Shut down content information interface */
148 intf_shutdown ( &peermux->info, rc );
149
150 /* Parse content information */
151 if ( ( rc = peerdist_info ( buffer->data, buffer->len, info ) ) != 0 ) {
152 DBGC ( peermux, "PEERMUX %p could not parse content info: %s\n",
153 peermux, strerror ( rc ) );
154 goto err;
155 }
156
157 /* Notify recipient of total download size */
158 len = ( info->trim.end - info->trim.start );
159 if ( ( rc = xfer_seek ( &peermux->xfer, len ) ) != 0 ) {
160 DBGC ( peermux, "PEERMUX %p could not presize buffer: %s\n",
161 peermux, strerror ( rc ) );
162 goto err;
163 }
164 xfer_seek ( &peermux->xfer, 0 );
165
166 /* Start block download process */
167 process_add ( &peermux->process );
168
169 return;
170
171 err:
172 peermux_close ( peermux, rc );
173}
174
175/**
176 * Initiate multiplexed block download
177 *
178 * @v peermux PeerDist download multiplexer
179 */
180static void peermux_step ( struct peerdist_multiplexer *peermux ) {
181 struct peerdist_info *info = &peermux->cache.info;
182 struct peerdist_info_segment *segment = &peermux->cache.segment;
183 struct peerdist_info_block *block = &peermux->cache.block;
184 struct peerdist_multiplexed_block *peermblk;
185 unsigned int next_segment;
186 unsigned int next_block;
187 int rc;
188
189 /* Stop initiation process if all block downloads are busy */
190 peermblk = list_first_entry ( &peermux->idle,
192 if ( ! peermblk ) {
194 return;
195 }
196
197 /* Increment block index */
198 next_block = ( block->index + 1 );
199
200 /* Move to first/next segment, if applicable */
201 if ( next_block >= segment->blocks ) {
202
203 /* Reset block index */
204 next_block = 0;
205
206 /* Calculate segment index */
207 next_segment = ( segment->info ? ( segment->index + 1 ) : 0 );
208
209 /* If we have finished all segments and have no
210 * remaining block downloads, then we are finished.
211 */
212 if ( next_segment >= info->segments ) {
214 if ( list_empty ( &peermux->busy ) )
215 peermux_close ( peermux, 0 );
216 return;
217 }
218
219 /* Get content information segment */
221 next_segment ) ) != 0 ) {
222 DBGC ( peermux, "PEERMUX %p could not get segment %d "
223 "information: %s\n", peermux, next_segment,
224 strerror ( rc ) );
225 goto err;
226 }
227 }
228
229 /* Get content information block */
230 if ( ( rc = peerdist_info_block ( segment, block, next_block ) ) != 0 ){
231 DBGC ( peermux, "PEERMUX %p could not get segment %d block "
232 "%d information: %s\n", peermux, segment->index,
233 next_block, strerror ( rc ) );
234 goto err;
235 }
236
237 /* Ignore block if it lies entirely outside the trimmed range */
238 if ( block->trim.start == block->trim.end ) {
239 DBGC ( peermux, "PEERMUX %p skipping segment %d block %d\n",
240 peermux, segment->index, block->index );
241 return;
242 }
243
244 /* Start downloading this block */
245 if ( ( rc = peerblk_open ( &peermblk->xfer, peermux->uri,
246 block ) ) != 0 ) {
247 DBGC ( peermux, "PEERMUX %p could not start download for "
248 "segment %d block %d: %s\n", peermux, segment->index,
249 block->index, strerror ( rc ) );
250 goto err;
251 }
252
253 /* Move to list of busy block downloads */
254 list_del ( &peermblk->list );
255 list_add_tail ( &peermblk->list, &peermux->busy );
256
257 return;
258
259 err:
261}
262
263/**
264 * Receive data from multiplexed block download
265 *
266 * @v peermblk PeerDist multiplexed block download
267 * @v iobuf I/O buffer
268 * @v meta Data transfer metadata
269 * @ret rc Return status code
270 */
272 struct io_buffer *iobuf,
273 struct xfer_metadata *meta ) {
274 struct peerdist_multiplexer *peermux = peermblk->peermux;
275
276 /* Sanity check: all block downloads must use absolute
277 * positions for all deliveries, since they run concurrently.
278 */
279 assert ( meta->flags & XFER_FL_ABS_OFFSET );
280
281 /* We can't use a simple passthrough interface descriptor,
282 * since there are multiple block download interfaces.
283 */
284 return xfer_deliver ( &peermux->xfer, iob_disown ( iobuf ), meta );
285}
286
287/**
288 * Get multiplexed block download underlying data transfer buffer
289 *
290 * @v peermblk PeerDist multiplexed download block
291 * @ret xferbuf Data transfer buffer, or NULL on error
292 */
293static struct xfer_buffer *
295 struct peerdist_multiplexer *peermux = peermblk->peermux;
296
297 /* We can't use a simple passthrough interface descriptor,
298 * since there are multiple block download interfaces.
299 */
300 return xfer_buffer ( &peermux->xfer );
301}
302
303/**
304 * Record peer discovery statistics
305 *
306 * @v peermblk PeerDist multiplexed block download
307 * @v peer Selected peer (or NULL)
308 * @v peers List of available peers
309 */
310static void peermux_block_stat ( struct peerdist_multiplexed_block *peermblk,
311 struct peerdisc_peer *peer,
312 struct list_head *peers ) {
313 struct peerdist_multiplexer *peermux = peermblk->peermux;
314 struct peerdist_statistics *stats = &peermux->stats;
315 struct peerdisc_peer *tmp;
316 unsigned int count = 0;
317
318 /* Record maximum number of available peers */
319 list_for_each_entry ( tmp, peers, list )
320 count++;
321 if ( count > stats->peers )
322 stats->peers = count;
323
324 /* Update block counts */
325 if ( peer )
326 stats->local++;
327 stats->total++;
328 DBGC2 ( peermux, "PEERMUX %p downloaded %d/%d from %d peers\n",
329 peermux, stats->local, stats->total, stats->peers );
330}
331
332/**
333 * Close multiplexed block download
334 *
335 * @v peermblk PeerDist multiplexed block download
336 * @v rc Reason for close
337 */
338static void peermux_block_close ( struct peerdist_multiplexed_block *peermblk,
339 int rc ) {
340 struct peerdist_multiplexer *peermux = peermblk->peermux;
341
342 /* Move to list of idle downloads */
343 list_del ( &peermblk->list );
344 list_add_tail ( &peermblk->list, &peermux->idle );
345
346 /* If any error occurred, terminate the whole multiplexer */
347 if ( rc != 0 ) {
348 peermux_close ( peermux, rc );
349 return;
350 }
351
352 /* Restart data transfer interface */
353 intf_restart ( &peermblk->xfer, rc );
354
355 /* Restart block download initiation process */
356 process_add ( &peermux->process );
357}
358
359/** Data transfer interface operations */
365
366/** Data transfer interface descriptor */
370
371/** Content information interface operations */
378
379/** Content information interface descriptor */
383
384/** Block download data transfer interface operations */
395
396/** Block download data transfer interface descriptor */
400
401/** Block download initiation process descriptor */
404
405/**
406 * Add PeerDist content-encoding filter
407 *
408 * @v xfer Data transfer interface
409 * @v info Content information interface
410 * @v uri Original URI
411 * @ret rc Return status code
412 */
413int peermux_filter ( struct interface *xfer, struct interface *info,
414 struct uri *uri ) {
415 struct peerdist_multiplexer *peermux;
416 struct peerdist_multiplexed_block *peermblk;
417 unsigned int i;
418
419 /* Allocate and initialise structure */
420 peermux = zalloc ( sizeof ( *peermux ) );
421 if ( ! peermux )
422 return -ENOMEM;
426 peermux->uri = uri_get ( uri );
429 &peermux->refcnt );
432 for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ ) {
433 peermblk = &peermux->block[i];
434 peermblk->peermux = peermux;
435 list_add_tail ( &peermblk->list, &peermux->idle );
436 intf_init ( &peermblk->xfer, &peermux_block_desc,
437 &peermux->refcnt );
438 }
439
440 /* Attach to parent interfaces, mortalise self, and return */
443 ref_put ( &peermux->refcnt );
444 return 0;
445}
u32 info
Definition ar9003_mac.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
static unsigned int count
Number of entries.
Definition dwmac.h:220
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition netvsc.h:5
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
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
void intf_nullify(struct interface *intf)
Ignore all further operations on an object interface.
Definition interface.c:130
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
#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 iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
Job control interfaces.
uint16_t segment
Code segment.
Definition librm.h:3
unsigned long tmp
Definition linux_pci.h:65
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition list.h:334
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition list.h:94
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
#define list_empty(list)
Test whether a list is empty.
Definition list.h:137
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
int peerblk_open(struct interface *xfer, struct uri *uri, struct peerdist_info_block *block)
Open PeerDist block download.
Definition peerblk.c:1434
Peer Content Caching and Retrieval (PeerDist) protocol block downloads.
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Definition peerdisc.c:101
static int peermux_block_deliver(struct peerdist_multiplexed_block *peermblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive data from multiplexed block download.
Definition peermux.c:271
static struct interface_descriptor peermux_block_desc
Block download data transfer interface descriptor.
Definition peermux.c:397
static void peermux_info_close(struct peerdist_multiplexer *peermux, int rc)
Close content information interface.
Definition peermux.c:133
static void peermux_step(struct peerdist_multiplexer *peermux)
Initiate multiplexed block download.
Definition peermux.c:180
static struct interface_operation peermux_xfer_operations[]
Data transfer interface operations.
Definition peermux.c:360
static void peermux_block_stat(struct peerdist_multiplexed_block *peermblk, struct peerdisc_peer *peer, struct list_head *peers)
Record peer discovery statistics.
Definition peermux.c:310
static struct xfer_buffer * peermux_block_buffer(struct peerdist_multiplexed_block *peermblk)
Get multiplexed block download underlying data transfer buffer.
Definition peermux.c:294
static void peermux_free(struct refcnt *refcnt)
Free PeerDist download multiplexer.
Definition peermux.c:48
static struct interface_descriptor peermux_xfer_desc
Data transfer interface descriptor.
Definition peermux.c:367
int peermux_filter(struct interface *xfer, struct interface *info, struct uri *uri)
Add PeerDist content-encoding filter.
Definition peermux.c:413
static struct interface_operation peermux_info_operations[]
Content information interface operations.
Definition peermux.c:372
static struct interface_operation peermux_block_operations[]
Block download data transfer interface operations.
Definition peermux.c:385
static void peermux_block_close(struct peerdist_multiplexed_block *peermblk, int rc)
Close multiplexed block download.
Definition peermux.c:338
static void peermux_close(struct peerdist_multiplexer *peermux, int rc)
Close PeerDist download multiplexer.
Definition peermux.c:63
static struct process_descriptor peermux_process_desc
Block download initiation process descriptor.
Definition peermux.c:402
static struct interface_descriptor peermux_info_desc
Content information interface descriptor.
Definition peermux.c:380
static int peermux_info_deliver(struct peerdist_multiplexer *peermux, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive content information.
Definition peermux.c:111
static int peermux_progress(struct peerdist_multiplexer *peermux, struct job_progress *progress)
Report progress of PeerDist download.
Definition peermux.c:88
Peer Content Caching and Retrieval (PeerDist) protocol multiplexer.
#define PEERMUX_MAX_BLOCKS
Maximum number of concurrent block downloads.
Definition peermux.h:23
void process_del(struct process *process)
Remove process from process list.
Definition process.c:80
void process_add(struct process *process)
Add process to process list.
Definition process.c:60
static void process_init_stopped(struct process *process, struct process_descriptor *desc, struct refcnt *refcnt)
Initialise process without adding to process list.
Definition process.h:146
#define PROC_DESC(object_type, process, _step)
Define a process descriptor.
Definition process.h:83
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
#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
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
Job progress.
Definition job.h:16
char message[32]
Message (optional)
Definition job.h:33
A doubly-linked list entry (or list head)
Definition list.h:19
A PeerDist discovery peer.
Definition peerdisc.h:72
struct list_head list
List of peers.
Definition peerdisc.h:74
A content information block.
Definition pccrc.h:394
struct peerdist_info info
Content information.
Definition peermux.h:28
struct peerdist_info_block block
Content information block.
Definition peermux.h:32
struct peerdist_info_segment segment
Content information segment.
Definition peermux.h:30
A content information segment.
Definition pccrc.h:347
Content information.
Definition pccrc.h:317
A PeerDist multiplexed block download.
Definition peermux.h:36
struct peerdist_multiplexer * peermux
PeerDist download multiplexer.
Definition peermux.h:38
struct interface xfer
Data transfer interface.
Definition peermux.h:42
struct list_head list
List of multiplexed blocks.
Definition peermux.h:40
A PeerDist download multiplexer.
Definition peermux.h:56
struct peerdist_statistics stats
Statistics.
Definition peermux.h:81
struct xfer_buffer buffer
Content information data transfer buffer.
Definition peermux.h:67
struct list_head idle
List of idle block downloads.
Definition peermux.h:76
struct peerdist_multiplexed_block block[PEERMUX_MAX_BLOCKS]
Block downloads.
Definition peermux.h:78
struct interface info
Content information interface.
Definition peermux.h:62
struct peerdist_info_cache cache
Content information cache.
Definition peermux.h:69
struct list_head busy
List of busy block downloads.
Definition peermux.h:74
struct refcnt refcnt
Reference count.
Definition peermux.h:58
struct uri * uri
Original URI.
Definition peermux.h:64
struct process process
Block download initiation process.
Definition peermux.h:72
struct interface xfer
Data transfer interface.
Definition peermux.h:60
PeerDist statistics.
Definition peermux.h:46
unsigned int total
Number of blocks downloaded in total.
Definition peermux.h:50
unsigned int peers
Maximum observed number of peers.
Definition peermux.h:48
unsigned int local
Number of blocks downloaded from peers.
Definition peermux.h:52
A process descriptor.
Definition process.h:32
A process.
Definition process.h:18
A reference counter.
Definition refcnt.h:27
A Uniform Resource Identifier.
Definition uri.h:65
A data transfer buffer.
Definition xferbuf.h:19
Data transfer metadata.
Definition xfer.h:23
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 snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
int xfer_seek(struct interface *intf, off_t offset)
Seek to position.
Definition xfer.c:352
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
Definition xferbuf.c:306
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
Definition xferbuf.c:74
int xferbuf_deliver(struct xfer_buffer *xferbuf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Add received data to data transfer buffer.
Definition xferbuf.c:175
Data transfer buffer.
static void xferbuf_umalloc_init(struct xfer_buffer *xferbuf)
Initialise umalloc()-based data transfer buffer.
Definition xferbuf.h:67