iPXE
peerblk.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/http.h>
32#include <ipxe/iobuf.h>
33#include <ipxe/xfer.h>
34#include <ipxe/uri.h>
35#include <ipxe/timer.h>
36#include <ipxe/profile.h>
37#include <ipxe/fault.h>
38#include <ipxe/pccrr.h>
39#include <ipxe/peerblk.h>
40
41/** @file
42 *
43 * Peer Content Caching and Retrieval (PeerDist) protocol block downloads
44 *
45 */
46
47/** PeerDist decryption chunksize
48 *
49 * This is a policy decision.
50 */
51#define PEERBLK_DECRYPT_CHUNKSIZE 2048
52
53/** PeerDist maximum number of concurrent raw block downloads
54 *
55 * Raw block downloads are expensive if the origin server uses HTTPS,
56 * since each concurrent download will require local TLS resources
57 * (including potentially large received encrypted data buffers).
58 *
59 * Raw block downloads may also be prohibitively slow to initiate when
60 * the origin server is using HTTPS and client certificates. Origin
61 * servers for PeerDist downloads are likely to be running IIS, which
62 * has a bug that breaks session resumption and requires each
63 * connection to go through the full client certificate verification.
64 *
65 * Limit the total number of concurrent raw block downloads to
66 * ameliorate these problems.
67 *
68 * This is a policy decision.
69 */
70#define PEERBLK_RAW_MAX 2
71
72/** PeerDist raw block download attempt initial progress timeout
73 *
74 * This is a policy decision.
75 */
76#define PEERBLK_RAW_OPEN_TIMEOUT ( 10 * TICKS_PER_SEC )
77
78/** PeerDist raw block download attempt ongoing progress timeout
79 *
80 * This is a policy decision.
81 */
82#define PEERBLK_RAW_RX_TIMEOUT ( 15 * TICKS_PER_SEC )
83
84/** PeerDist retrieval protocol block download attempt initial progress timeout
85 *
86 * This is a policy decision.
87 */
88#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT ( 3 * TICKS_PER_SEC )
89
90/** PeerDist retrieval protocol block download attempt ongoing progress timeout
91 *
92 * This is a policy decision.
93 */
94#define PEERBLK_RETRIEVAL_RX_TIMEOUT ( 5 * TICKS_PER_SEC )
95
96/** PeerDist maximum number of full download attempt cycles
97 *
98 * This is the maximum number of times that we will try a full cycle
99 * of download attempts (i.e. a retrieval protocol download attempt
100 * from each discovered peer plus a raw download attempt from the
101 * origin server).
102 *
103 * This is a policy decision.
104 */
105#define PEERBLK_MAX_ATTEMPT_CYCLES 4
106
107/** PeerDist block download profiler */
108static struct profiler peerblk_download_profiler __profiler =
109 { .name = "peerblk.download" };
110
111/** PeerDist block download attempt success profiler */
112static struct profiler peerblk_attempt_success_profiler __profiler =
113 { .name = "peerblk.attempt.success" };
114
115/** PeerDist block download attempt failure profiler */
116static struct profiler peerblk_attempt_failure_profiler __profiler =
117 { .name = "peerblk.attempt.failure" };
118
119/** PeerDist block download attempt timeout profiler */
120static struct profiler peerblk_attempt_timeout_profiler __profiler =
121 { .name = "peerblk.attempt.timeout" };
122
123/** PeerDist block download discovery success profiler */
124static struct profiler peerblk_discovery_success_profiler __profiler =
125 { .name = "peerblk.discovery.success" };
126
127/** PeerDist block download discovery timeout profiler */
128static struct profiler peerblk_discovery_timeout_profiler __profiler =
129 { .name = "peerblk.discovery.timeout" };
130
131static void peerblk_dequeue ( struct peerdist_block *peerblk );
132
133/**
134 * Get profiling timestamp
135 *
136 * @ret timestamp Timestamp
137 */
138static inline __attribute__ (( always_inline )) unsigned long
140
141 if ( PROFILING ) {
142 return currticks();
143 } else {
144 return 0;
145 }
146}
147
148/**
149 * Free PeerDist block download
150 *
151 * @v refcnt Reference count
152 */
153static void peerblk_free ( struct refcnt *refcnt ) {
154 struct peerdist_block *peerblk =
156
157 uri_put ( peerblk->uri );
158 free ( peerblk->cipherctx );
159 free ( peerblk );
160}
161
162/**
163 * Reset PeerDist block download attempt
164 *
165 * @v peerblk PeerDist block download
166 * @v rc Reason for reset
167 */
168static void peerblk_reset ( struct peerdist_block *peerblk, int rc ) {
169
170 /* Stop decryption process */
171 process_del ( &peerblk->process );
172
173 /* Stop timer */
174 stop_timer ( &peerblk->timer );
175
176 /* Abort any current download attempt */
177 intf_restart ( &peerblk->raw, rc );
178 intf_restart ( &peerblk->retrieval, rc );
179
180 /* Remove from download queue, if applicable */
181 if ( peerblk->queue )
182 peerblk_dequeue ( peerblk );
183
184 /* Empty received data buffer */
185 xferbuf_free ( &peerblk->buffer );
186 peerblk->pos = 0;
187
188 /* Reset digest and free cipher context */
189 digest_init ( peerblk->digest, peerblk->digestctx );
190 free ( peerblk->cipherctx );
191 peerblk->cipherctx = NULL;
192 peerblk->cipher = NULL;
193
194 /* Reset trim thresholds */
195 peerblk->start = ( peerblk->trim.start - peerblk->range.start );
196 peerblk->end = ( peerblk->trim.end - peerblk->range.start );
197 assert ( peerblk->start <= peerblk->end );
198}
199
200/**
201 * Close PeerDist block download
202 *
203 * @v peerblk PeerDist block download
204 * @v rc Reason for close
205 */
206static void peerblk_close ( struct peerdist_block *peerblk, int rc ) {
207 unsigned long now = peerblk_timestamp();
208
209 /* Profile overall block download */
210 profile_custom ( &peerblk_download_profiler,
211 ( now - peerblk->started ) );
212
213 /* Reset download attempt */
214 peerblk_reset ( peerblk, rc );
215
216 /* Close discovery */
217 peerdisc_close ( &peerblk->discovery );
218
219 /* Shut down all interfaces */
220 intf_shutdown ( &peerblk->retrieval, rc );
221 intf_shutdown ( &peerblk->raw, rc );
222 intf_shutdown ( &peerblk->xfer, rc );
223}
224
225/**
226 * Calculate offset within overall download
227 *
228 * @v peerblk PeerDist block download
229 * @v pos Position within incoming data stream
230 * @ret offset Offset within overall download
231 */
232static inline __attribute__ (( always_inline )) size_t
233peerblk_offset ( struct peerdist_block *peerblk, size_t pos ) {
234
235 return ( ( pos - peerblk->start ) + peerblk->offset );
236}
237
238/**
239 * Deliver download attempt data block
240 *
241 * @v peerblk PeerDist block download
242 * @v iobuf I/O buffer
243 * @v meta Original data transfer metadata
244 * @v pos Position within incoming data stream
245 * @ret rc Return status code
246 */
247static int peerblk_deliver ( struct peerdist_block *peerblk,
248 struct io_buffer *iobuf,
249 struct xfer_metadata *meta, size_t pos ) {
250 struct xfer_metadata xfer_meta;
251 size_t len = iob_len ( iobuf );
252 size_t start = pos;
253 size_t end = ( pos + len );
254 int rc;
255
256 /* Discard zero-length packets and packets which lie entirely
257 * outside the trimmed range.
258 */
259 if ( ( start >= peerblk->end ) || ( end <= peerblk->start ) ||
260 ( len == 0 ) ) {
261 free_iob ( iobuf );
262 return 0;
263 }
264
265 /* Truncate data to within trimmed range */
267 iob_pull ( iobuf, ( peerblk->start - start ) );
268 start = peerblk->start;
269 }
270 if ( end > peerblk->end ) {
271 iob_unput ( iobuf, ( end - peerblk->end ) );
272 end = peerblk->end;
273 }
274
275 /* Construct metadata */
276 memcpy ( &xfer_meta, meta, sizeof ( xfer_meta ) );
277 xfer_meta.flags |= XFER_FL_ABS_OFFSET;
278 xfer_meta.offset = peerblk_offset ( peerblk, start );
279
280 /* Deliver data */
281 if ( ( rc = xfer_deliver ( &peerblk->xfer, iob_disown ( iobuf ),
282 &xfer_meta ) ) != 0 ) {
283 DBGC ( peerblk, "PEERBLK %p %d.%d could not deliver data: %s\n",
284 peerblk, peerblk->segment, peerblk->block,
285 strerror ( rc ) );
286 return rc;
287 }
288
289 return 0;
290}
291
292/**
293 * Finish PeerDist block download attempt
294 *
295 * @v peerblk PeerDist block download
296 * @v rc Reason for close
297 */
298static void peerblk_done ( struct peerdist_block *peerblk, int rc ) {
299 struct digest_algorithm *digest = peerblk->digest;
300 struct peerdisc_segment *segment = peerblk->discovery.segment;
301 struct peerdisc_peer *head;
302 struct peerdisc_peer *peer;
303 uint8_t hash[digest->digestsize];
304 unsigned long now = peerblk_timestamp();
305
306 /* Check for errors on completion */
307 if ( rc != 0 ) {
308 DBGC ( peerblk, "PEERBLK %p %d.%d attempt failed: %s\n",
309 peerblk, peerblk->segment, peerblk->block,
310 strerror ( rc ) );
311 goto err;
312 }
313
314 /* Check digest */
315 digest_final ( digest, peerblk->digestctx, hash );
316 if ( memcmp ( hash, peerblk->hash, peerblk->digestsize ) != 0 ) {
317 DBGC ( peerblk, "PEERBLK %p %d.%d digest mismatch:\n",
318 peerblk, peerblk->segment, peerblk->block );
319 DBGC_HDA ( peerblk, 0, hash, peerblk->digestsize );
320 DBGC_HDA ( peerblk, 0, peerblk->hash, peerblk->digestsize );
321 rc = -EIO;
322 goto err;
323 }
324
325 /* Profile successful attempt */
326 profile_custom ( &peerblk_attempt_success_profiler,
327 ( now - peerblk->attempted ) );
328
329 /* Report peer statistics */
330 head = list_entry ( &segment->peers, struct peerdisc_peer, list );
331 peer = ( ( peerblk->peer == head ) ? NULL : peerblk->peer );
332 peerdisc_stat ( &peerblk->xfer, peer, &segment->peers );
333
334 /* Close download */
335 peerblk_close ( peerblk, 0 );
336 return;
337
338 err:
339 /* Record failure reason and schedule a retry attempt */
340 profile_custom ( &peerblk_attempt_failure_profiler,
341 ( now - peerblk->attempted ) );
342 peerblk_reset ( peerblk, rc );
343 peerblk->rc = rc;
344 start_timer_nodelay ( &peerblk->timer );
345}
346
347/******************************************************************************
348 *
349 * Raw block download attempts (using an HTTP range request)
350 *
351 ******************************************************************************
352 */
353
354/**
355 * Open PeerDist raw block download attempt
356 *
357 * @v peerblk PeerDist block download
358 * @ret rc Return status code
359 */
360static int peerblk_raw_open ( struct peerdist_block *peerblk ) {
362 int rc;
363
364 DBGC2 ( peerblk, "PEERBLK %p %d.%d attempting raw range request\n",
365 peerblk, peerblk->segment, peerblk->block );
366
367 /* Construct HTTP range */
368 memset ( &range, 0, sizeof ( range ) );
369 range.start = peerblk->range.start;
370 range.len = ( peerblk->range.end - peerblk->range.start );
371
372 /* Initiate range request to retrieve block */
373 if ( ( rc = http_open ( &peerblk->raw, &http_get, peerblk->uri,
374 &range, NULL ) ) != 0 ) {
375 DBGC ( peerblk, "PEERBLK %p %d.%d could not create range "
376 "request: %s\n", peerblk, peerblk->segment,
377 peerblk->block, strerror ( rc ) );
378 return rc;
379 }
380
381 /* Annul HTTP connection (for testing) if applicable. Do not
382 * report as an immediate error, in order to test our ability
383 * to recover from a totally unresponsive HTTP server.
384 */
385 if ( inject_fault ( PEERBLK_ANNUL_RATE ) )
386 intf_restart ( &peerblk->raw, 0 );
387
388 /* Start download attempt timer */
389 peerblk->rc = -ETIMEDOUT;
391
392 return 0;
393}
394
395/**
396 * Receive PeerDist raw data
397 *
398 * @v peerblk PeerDist block download
399 * @v iobuf I/O buffer
400 * @v meta Data transfer metadata
401 * @ret rc Return status code
402 */
403static int peerblk_raw_rx ( struct peerdist_block *peerblk,
404 struct io_buffer *iobuf,
405 struct xfer_metadata *meta ) {
406 size_t len = iob_len ( iobuf );
407 size_t pos = peerblk->pos;
408 size_t mid = ( ( peerblk->range.end - peerblk->range.start ) / 2 );
409 int rc;
410
411 /* Corrupt received data (for testing) if applicable */
412 inject_corruption ( PEERBLK_CORRUPT_RATE, iobuf->data, len );
413
414 /* Fail if data is delivered out of order, since the streaming
415 * digest requires strict ordering.
416 */
417 if ( ( rc = xfer_check_order ( meta, &peerblk->pos, len ) ) != 0 )
418 goto err;
419
420 /* Add data to digest */
421 digest_update ( peerblk->digest, peerblk->digestctx, iobuf->data, len );
422
423 /* Deliver data */
424 if ( ( rc = peerblk_deliver ( peerblk, iob_disown ( iobuf ), meta,
425 pos ) ) != 0 )
426 goto err;
427
428 /* Extend download attempt timer */
430
431 /* Stall download attempt (for testing) if applicable */
432 if ( ( pos < mid ) && ( ( pos + len ) >= mid ) &&
433 ( ( rc = inject_fault ( PEERBLK_STALL_RATE ) ) != 0 ) ) {
434 intf_restart ( &peerblk->raw, rc );
435 }
436
437 return 0;
438
439 err:
440 free_iob ( iobuf );
441 peerblk_done ( peerblk, rc );
442 return rc;
443}
444
445/**
446 * Close PeerDist raw block download attempt
447 *
448 * @v peerblk PeerDist block download
449 * @v rc Reason for close
450 */
451static void peerblk_raw_close ( struct peerdist_block *peerblk, int rc ) {
452
453 /* Restart interface */
454 intf_restart ( &peerblk->raw, rc );
455
456 /* Fail immediately if we have an error */
457 if ( rc != 0 )
458 goto done;
459
460 /* Abort download attempt (for testing) if applicable */
461 if ( ( rc = inject_fault ( PEERBLK_ABORT_RATE ) ) != 0 )
462 goto done;
463
464 done:
465 /* Complete download attempt */
466 peerblk_done ( peerblk, rc );
467}
468
469/******************************************************************************
470 *
471 * Block download queue
472 *
473 ******************************************************************************
474 */
475
476/**
477 * PeerDist block download queue process
478 *
479 * @v queue Block download queue
480 */
481static void peerblk_step ( struct peerdist_block_queue *queue ) {
482 struct peerdist_block *peerblk;
483 int rc;
484
485 /* Do nothing yet if we have too many open block downloads */
486 if ( queue->count >= queue->max )
487 return;
488
489 /* Do nothing unless there are queued block downloads */
490 peerblk = list_first_entry ( &queue->list, struct peerdist_block,
491 queued );
492 if ( ! peerblk )
493 return;
494
495 /* Reschedule queue process */
496 process_add ( &queue->process );
497
498 /* Remove block from queue */
499 list_del ( &peerblk->queued );
500 INIT_LIST_HEAD ( &peerblk->queued );
501
502 /* Attempt download */
503 if ( ( rc = queue->open ( peerblk ) ) != 0 ) {
504 peerblk_close ( peerblk, rc );
505 return;
506 }
507
508 /* Increment open block download count */
509 queue->count++;
510}
511
512/**
513 * Add block to download queue
514 *
515 * @v peerblk PeerDist block download
516 * @v queue Block download queue
517 */
518static void peerblk_enqueue ( struct peerdist_block *peerblk,
519 struct peerdist_block_queue *queue ) {
520
521 /* Sanity checks */
522 assert ( peerblk->queue == NULL );
523 assert ( list_empty ( &peerblk->queued ) );
524
525 /* Add block to queue */
526 peerblk->queue = queue;
527 list_add_tail ( &peerblk->queued, &queue->list );
528
529 /* Schedule queue process */
530 process_add ( &queue->process );
531}
532
533/**
534 * Remove block from download queue
535 *
536 * @v peerblk PeerDist block download
537 */
538static void peerblk_dequeue ( struct peerdist_block *peerblk ) {
539 struct peerdist_block_queue *queue = peerblk->queue;
540
541 /* Sanity checks */
542 assert ( queue != NULL );
543
544 /* Remove block from queue */
545 peerblk->queue = NULL;
546 if ( list_empty ( &peerblk->queued ) ) {
547
548 /* Open download: decrement count and reschedule queue */
549 queue->count--;
550 process_add ( &queue->process );
551
552 } else {
553
554 /* Queued download: remove from queue */
555 list_del ( &peerblk->queued );
556 INIT_LIST_HEAD ( &peerblk->queued );
557 }
558}
559
560/** PeerDist block download queue process descriptor */
563
564/** Raw block download queue */
566 .process = PROC_INIT ( peerblk_raw_queue.process, &peerblk_queue_desc ),
567 .list = LIST_HEAD_INIT ( peerblk_raw_queue.list ),
568 .max = PEERBLK_RAW_MAX,
569 .open = peerblk_raw_open,
570};
571
572/******************************************************************************
573 *
574 * Retrieval protocol block download attempts (using HTTP POST)
575 *
576 ******************************************************************************
577 */
578
579/**
580 * Construct PeerDist retrieval protocol URI
581 *
582 * @v location Peer location
583 * @ret uri Retrieval URI, or NULL on error
584 */
585static struct uri * peerblk_retrieval_uri ( const char *location ) {
586 char uri_string[ 7 /* "http://" */ + strlen ( location ) +
587 sizeof ( PEERDIST_MAGIC_PATH /* includes NUL */ ) ];
588
589 /* Construct URI string */
590 snprintf ( uri_string, sizeof ( uri_string ),
591 ( "http://%s" PEERDIST_MAGIC_PATH ), location );
592
593 /* Parse URI string */
594 return parse_uri ( uri_string );
595}
596
597/**
598 * Open PeerDist retrieval protocol block download attempt
599 *
600 * @v peerblk PeerDist block download
601 * @v location Peer location
602 * @ret rc Return status code
603 */
604static int peerblk_retrieval_open ( struct peerdist_block *peerblk,
605 const char *location ) {
606 size_t digestsize = peerblk->digestsize;
608 peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *rsp;
609 struct http_request_content content;
610 struct uri *uri;
611 int rc;
612
613 DBGC2 ( peerblk, "PEERBLK %p %d.%d attempting retrieval from %s\n",
614 peerblk, peerblk->segment, peerblk->block, location );
615
616 /* Construct block fetch request */
617 memset ( &req, 0, sizeof ( req ) );
618 req.getblks.hdr.version.raw = htonl ( PEERDIST_MSG_GETBLKS_VERSION );
619 req.getblks.hdr.type = htonl ( PEERDIST_MSG_GETBLKS_TYPE );
620 req.getblks.hdr.len = htonl ( sizeof ( req ) );
621 req.getblks.hdr.algorithm = htonl ( PEERDIST_MSG_AES_128_CBC );
622 req.segment.segment.digestsize = htonl ( digestsize );
623 memcpy ( req.segment.id, peerblk->id, digestsize );
624 req.ranges.ranges.count = htonl ( 1 );
625 req.ranges.range[0].first = htonl ( peerblk->block );
626 req.ranges.range[0].count = htonl ( 1 );
627
628 /* Construct POST request content */
629 memset ( &content, 0, sizeof ( content ) );
630 content.data = &req;
631 content.len = sizeof ( req );
632
633 /* Construct URI */
634 if ( ( uri = peerblk_retrieval_uri ( location ) ) == NULL ) {
635 rc = -ENOMEM;
636 goto err_uri;
637 }
638
639 /* Update trim thresholds */
640 peerblk->start += offsetof ( typeof ( *rsp ), msg.vrf );
641 peerblk->end += offsetof ( typeof ( *rsp ), msg.vrf );
642
643 /* Initiate HTTP POST to retrieve block */
644 if ( ( rc = http_open ( &peerblk->retrieval, &http_post, uri,
645 NULL, &content ) ) != 0 ) {
646 DBGC ( peerblk, "PEERBLK %p %d.%d could not create retrieval "
647 "request: %s\n", peerblk, peerblk->segment,
648 peerblk->block, strerror ( rc ) );
649 goto err_open;
650 }
651
652 /* Annul HTTP connection (for testing) if applicable. Do not
653 * report as an immediate error, in order to test our ability
654 * to recover from a totally unresponsive HTTP server.
655 */
656 if ( inject_fault ( PEERBLK_ANNUL_RATE ) )
657 intf_restart ( &peerblk->retrieval, 0 );
658
659 /* Start download attempt timer */
660 peerblk->rc = -ETIMEDOUT;
662
663 err_open:
664 uri_put ( uri );
665 err_uri:
666 return rc;
667}
668
669/**
670 * Receive PeerDist retrieval protocol data
671 *
672 * @v peerblk PeerDist block download
673 * @v iobuf I/O buffer
674 * @v meta Data transfer metadata
675 * @ret rc Return status code
676 */
677static int peerblk_retrieval_rx ( struct peerdist_block *peerblk,
678 struct io_buffer *iobuf,
679 struct xfer_metadata *meta ) {
680 size_t len = iob_len ( iobuf );
681 size_t start;
682 size_t end;
683 size_t before;
684 size_t after;
685 size_t cut;
686 int rc;
687
688 /* Some genius at Microsoft thought it would be a great idea
689 * to place the AES-CBC initialisation vector *after* the
690 * encrypted data, thereby making it logically impossible to
691 * decrypt each packet as it arrives.
692 *
693 * To work around this mindless stupidity, we deliver the
694 * ciphertext as-is and later use xfer_buffer() to obtain
695 * access to the underlying data transfer buffer in order to
696 * perform the decryption.
697 *
698 * There will be some data both before and after the bytes
699 * corresponding to the trimmed plaintext: a MSG_BLK
700 * header/footer, some block padding for the AES-CBC cipher,
701 * and a possibly large quantity of unwanted ciphertext which
702 * is excluded from the trimmed content range. We store this
703 * data in a local data transfer buffer. If the amount of
704 * data to be stored is too large, we will fail allocation and
705 * so eventually fall back to using a range request (which
706 * does not require this kind of temporary storage
707 * allocation).
708 */
709
710 /* Corrupt received data (for testing) if applicable */
711 inject_corruption ( PEERBLK_CORRUPT_RATE, iobuf->data, len );
712
713 /* Calculate start and end positions of this buffer */
714 start = peerblk->pos;
715 if ( meta->flags & XFER_FL_ABS_OFFSET )
716 start = 0;
717 start += meta->offset;
718 end = ( start + len );
719
720 /* Buffer any data before the trimmed content */
721 if ( ( start < peerblk->start ) && ( len > 0 ) ) {
722
723 /* Calculate length of data before the trimmed content */
724 before = ( peerblk->start - start );
725 if ( before > len )
726 before = len;
727
728 /* Buffer data before the trimmed content */
729 if ( ( rc = xferbuf_write ( &peerblk->buffer, start,
730 iobuf->data, before ) ) != 0 ) {
731 DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
732 "data: %s\n", peerblk, peerblk->segment,
733 peerblk->block, strerror ( rc ) );
734 goto err;
735 }
736 }
737
738 /* Buffer any data after the trimmed content */
739 if ( ( end > peerblk->end ) && ( len > 0 ) ) {
740
741 /* Calculate length of data after the trimmed content */
742 after = ( end - peerblk->end );
743 if ( after > len )
744 after = len;
745
746 /* Buffer data after the trimmed content */
747 cut = ( peerblk->end - peerblk->start );
748 if ( ( rc = xferbuf_write ( &peerblk->buffer,
749 ( end - after - cut ),
750 ( iobuf->data + len - after ),
751 after ) ) != 0 ) {
752 DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
753 "data: %s\n", peerblk, peerblk->segment,
754 peerblk->block, strerror ( rc ) );
755 goto err;
756 }
757 }
758
759 /* Deliver any remaining data */
760 if ( ( rc = peerblk_deliver ( peerblk, iob_disown ( iobuf ), meta,
761 start ) ) != 0 )
762 goto err;
763
764 /* Update position */
765 peerblk->pos = end;
766
767 /* Extend download attempt timer */
769
770 /* Stall download attempt (for testing) if applicable */
771 if ( ( start < peerblk->end ) && ( end >= peerblk->end ) &&
772 ( ( rc = inject_fault ( PEERBLK_STALL_RATE ) ) != 0 ) ) {
773 intf_restart ( &peerblk->retrieval, rc );
774 }
775
776 return 0;
777
778 err:
779 free_iob ( iobuf );
780 peerblk_done ( peerblk, rc );
781 return rc;
782}
783
784/**
785 * Parse retrieval protocol message header
786 *
787 * @v peerblk PeerDist block download
788 * @ret rc Return status code
789 */
790static int peerblk_parse_header ( struct peerdist_block *peerblk ) {
791 struct {
794 } __attribute__ (( packed )) *msg = peerblk->buffer.data;
795 struct cipher_algorithm *cipher;
796 size_t len = peerblk->buffer.len;
797 size_t keylen = 0;
798 int rc;
799
800 /* Check message length */
801 if ( len < sizeof ( *msg ) ) {
802 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for header "
803 "(%zd bytes)\n", peerblk, peerblk->segment,
804 peerblk->block, len );
805 return -ERANGE;
806 }
807
808 /* Check message type */
809 if ( msg->msg.type != htonl ( PEERDIST_MSG_BLK_TYPE ) ) {
810 DBGC ( peerblk, "PEERBLK %p %d.%d unexpected message type "
811 "%#08x\n", peerblk, peerblk->segment, peerblk->block,
812 ntohl ( msg->msg.type ) );
813 return -EPROTO;
814 }
815
816 /* Determine cipher algorithm and key length */
817 cipher = &aes_cbc_algorithm;
818 switch ( msg->msg.algorithm ) {
820 cipher = NULL;
821 break;
823 keylen = ( 128 / 8 );
824 break;
826 keylen = ( 192 / 8 );
827 break;
829 keylen = ( 256 / 8 );
830 break;
831 default:
832 DBGC ( peerblk, "PEERBLK %p %d.%d unrecognised algorithm "
833 "%#08x\n", peerblk, peerblk->segment, peerblk->block,
834 ntohl ( msg->msg.algorithm ) );
835 return -ENOTSUP;
836 }
837 DBGC2 ( peerblk, "PEERBLK %p %d.%d using %s with %zd-bit key\n",
838 peerblk, peerblk->segment, peerblk->block,
839 ( cipher ? cipher->name : "plaintext" ), ( 8 * keylen ) );
840
841 /* Sanity check key length against maximum secret length */
842 if ( keylen > peerblk->digestsize ) {
843 DBGC ( peerblk, "PEERBLK %p %d.%d %zd-byte secret too short "
844 "for %zd-bit key\n", peerblk, peerblk->segment,
845 peerblk->block, peerblk->digestsize, ( 8 * keylen ) );
846 return -EPROTO;
847 }
848
849 /* Allocate cipher context, if applicable. Freeing the cipher
850 * context (on error or otherwise) is handled by peerblk_reset().
851 */
852 peerblk->cipher = cipher;
853 assert ( peerblk->cipherctx == NULL );
854 if ( cipher ) {
855 peerblk->cipherctx = malloc ( cipher->ctxsize );
856 if ( ! peerblk->cipherctx )
857 return -ENOMEM;
858 }
859
860 /* Initialise cipher, if applicable */
861 if ( cipher &&
862 ( rc = cipher_setkey ( cipher, peerblk->cipherctx, peerblk->secret,
863 keylen ) ) != 0 ) {
864 DBGC ( peerblk, "PEERBLK %p %d.%d could not set key: %s\n",
865 peerblk, peerblk->segment, peerblk->block,
866 strerror ( rc ) );
867 return rc;
868 }
869
870 return 0;
871}
872
873/**
874 * Parse retrieval protocol message segment and block details
875 *
876 * @v peerblk PeerDist block download
877 * @v buf_len Length of buffered data to fill in
878 * @ret rc Return status code
879 */
880static int peerblk_parse_block ( struct peerdist_block *peerblk,
881 size_t *buf_len ) {
882 size_t digestsize = peerblk->digestsize;
883 peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *msg = peerblk->buffer.data;
884 size_t len = peerblk->buffer.len;
885 size_t data_len;
886 size_t total;
887
888 /* Check message length */
889 if ( len < offsetof ( typeof ( *msg ), msg.block.data ) ) {
890 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
891 "zero-length data (%zd bytes)\n", peerblk,
892 peerblk->segment, peerblk->block, len );
893 return -ERANGE;
894 }
895
896 /* Check digest size */
897 if ( ntohl ( msg->msg.segment.segment.digestsize ) != digestsize ) {
898 DBGC ( peerblk, "PEERBLK %p %d.%d incorrect digest size %d\n",
899 peerblk, peerblk->segment, peerblk->block,
900 ntohl ( msg->msg.segment.segment.digestsize ) );
901 return -EPROTO;
902 }
903
904 /* Check segment ID */
905 if ( memcmp ( msg->msg.segment.id, peerblk->id, digestsize ) != 0 ) {
906 DBGC ( peerblk, "PEERBLK %p %d.%d segment ID mismatch\n",
907 peerblk, peerblk->segment, peerblk->block );
908 return -EPROTO;
909 }
910
911 /* Check block ID */
912 if ( ntohl ( msg->msg.index ) != peerblk->block ) {
913 DBGC ( peerblk, "PEERBLK %p %d.%d block ID mismatch (got %d)\n",
914 peerblk, peerblk->segment, peerblk->block,
915 ntohl ( msg->msg.index ) );
916 return -EPROTO;
917 }
918
919 /* Check for missing blocks */
920 data_len = be32_to_cpu ( msg->msg.block.block.len );
921 if ( ! data_len ) {
922 DBGC ( peerblk, "PEERBLK %p %d.%d block not found\n",
923 peerblk, peerblk->segment, peerblk->block );
924 return -ENOENT;
925 }
926
927 /* Check for underlength blocks */
928 if ( data_len < ( peerblk->range.end - peerblk->range.start ) ) {
929 DBGC ( peerblk, "PEERBLK %p %d.%d underlength block (%zd "
930 "bytes)\n", peerblk, peerblk->segment, peerblk->block,
931 data_len );
932 return -ERANGE;
933 }
934
935 /* Calculate buffered data length (i.e. excluding data which
936 * was delivered to the final data transfer buffer).
937 */
938 *buf_len = ( data_len - ( peerblk->end - peerblk->start ) );
939
940 /* Describe data before the trimmed content */
941 peerblk->decrypt[PEERBLK_BEFORE].xferbuf = &peerblk->buffer;
942 peerblk->decrypt[PEERBLK_BEFORE].offset =
943 offsetof ( typeof ( *msg ), msg.block.data );
944 peerblk->decrypt[PEERBLK_BEFORE].len =
945 ( peerblk->start -
946 offsetof ( typeof ( *msg ), msg.block.data ) );
947 total = peerblk->decrypt[PEERBLK_BEFORE].len;
948
949 /* Describe data within the trimmed content */
950 peerblk->decrypt[PEERBLK_DURING].offset =
951 peerblk_offset ( peerblk, peerblk->start );
952 peerblk->decrypt[PEERBLK_DURING].len =
953 ( peerblk->end - peerblk->start );
954 total += peerblk->decrypt[PEERBLK_DURING].len;
955
956 /* Describe data after the trimmed content */
957 peerblk->decrypt[PEERBLK_AFTER].xferbuf = &peerblk->buffer;
958 peerblk->decrypt[PEERBLK_AFTER].offset = peerblk->start;
959 peerblk->decrypt[PEERBLK_AFTER].len =
960 ( offsetof ( typeof ( *msg ), msg.block.data )
961 + *buf_len - peerblk->start );
962 total += peerblk->decrypt[PEERBLK_AFTER].len;
963
964 /* Sanity check */
965 assert ( total == be32_to_cpu ( msg->msg.block.block.len ) );
966
967 /* Initialise cipher and digest lengths */
968 peerblk->cipher_remaining = total;
969 peerblk->digest_remaining =
970 ( peerblk->range.end - peerblk->range.start );
971 assert ( peerblk->cipher_remaining >= peerblk->digest_remaining );
972
973 return 0;
974}
975
976/**
977 * Parse retrieval protocol message useless details
978 *
979 * @v peerblk PeerDist block download
980 * @v buf_len Length of buffered data
981 * @v vrf_len Length of uselessness to fill in
982 * @ret rc Return status code
983 */
984static int peerblk_parse_useless ( struct peerdist_block *peerblk,
985 size_t buf_len, size_t *vrf_len ) {
986 size_t digestsize = peerblk->digestsize;
987 peerblk_msg_blk_t ( digestsize, buf_len, 0, 0 ) *msg =
988 peerblk->buffer.data;
989 size_t len = peerblk->buffer.len;
990
991 /* Check message length */
992 if ( len < offsetof ( typeof ( *msg ), msg.vrf.data ) ) {
993 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
994 "zero-length uselessness (%zd bytes)\n", peerblk,
995 peerblk->segment, peerblk->block, len );
996 return -ERANGE;
997 }
998
999 /* Extract length of uselessness */
1000 *vrf_len = be32_to_cpu ( msg->msg.vrf.vrf.len );
1001
1002 return 0;
1003}
1004
1005/**
1006 * Parse retrieval protocol message initialisation vector details
1007 *
1008 * @v peerblk PeerDist block download
1009 * @v buf_len Length of buffered data
1010 * @v vrf_len Length of uselessness
1011 * @ret rc Return status code
1012 */
1013static int peerblk_parse_iv ( struct peerdist_block *peerblk, size_t buf_len,
1014 size_t vrf_len ) {
1015 size_t digestsize = peerblk->digestsize;
1016 size_t blksize = peerblk->cipher->blocksize;
1017 peerblk_msg_blk_t ( digestsize, buf_len, vrf_len, blksize ) *msg =
1018 peerblk->buffer.data;
1019 size_t len = peerblk->buffer.len;
1020
1021 /* Check message length */
1022 if ( len < sizeof ( *msg ) ) {
1023 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
1024 "initialisation vector (%zd bytes)\n", peerblk,
1025 peerblk->segment, peerblk->block, len );
1026 return -ERANGE;
1027 }
1028
1029 /* Check initialisation vector size */
1030 if ( ntohl ( msg->msg.iv.iv.blksize ) != blksize ) {
1031 DBGC ( peerblk, "PEERBLK %p %d.%d incorrect IV size %d\n",
1032 peerblk, peerblk->segment, peerblk->block,
1033 ntohl ( msg->msg.iv.iv.blksize ) );
1034 return -EPROTO;
1035 }
1036
1037 /* Set initialisation vector */
1038 cipher_setiv ( peerblk->cipher, peerblk->cipherctx, msg->msg.iv.data,
1039 blksize );
1040
1041 return 0;
1042}
1043
1044/**
1045 * Read from decryption buffers
1046 *
1047 * @v peerblk PeerDist block download
1048 * @v data Data buffer
1049 * @v len Length to read
1050 * @ret rc Return status code
1051 */
1052static int peerblk_decrypt_read ( struct peerdist_block *peerblk,
1053 void *data, size_t len ) {
1054 struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
1055 size_t frag_len;
1056 int rc;
1057
1058 /* Read from each decryption buffer in turn */
1059 for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
1060
1061 /* Calculate length to use from this buffer */
1062 frag_len = decrypt->len;
1063 if ( frag_len > len )
1064 frag_len = len;
1065 if ( ! frag_len )
1066 continue;
1067
1068 /* Read from this buffer */
1069 if ( ( rc = xferbuf_read ( decrypt->xferbuf, decrypt->offset,
1070 data, frag_len ) ) != 0 )
1071 return rc;
1072 }
1073
1074 return 0;
1075}
1076
1077/**
1078 * Write to decryption buffers and update offsets and lengths
1079 *
1080 * @v peerblk PeerDist block download
1081 * @v data Data buffer
1082 * @v len Length to read
1083 * @ret rc Return status code
1084 */
1085static int peerblk_decrypt_write ( struct peerdist_block *peerblk,
1086 const void *data, size_t len ) {
1087 struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
1088 size_t frag_len;
1089 int rc;
1090
1091 /* Write to each decryption buffer in turn */
1092 for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
1093
1094 /* Calculate length to use from this buffer */
1095 frag_len = decrypt->len;
1096 if ( frag_len > len )
1097 frag_len = len;
1098 if ( ! frag_len )
1099 continue;
1100
1101 /* Write to this buffer */
1102 if ( ( rc = xferbuf_write ( decrypt->xferbuf, decrypt->offset,
1103 data, frag_len ) ) != 0 )
1104 return rc;
1105
1106 /* Update offset and length */
1107 decrypt->offset += frag_len;
1108 decrypt->len -= frag_len;
1109 }
1110
1111 return 0;
1112}
1113
1114/**
1115 * Decrypt one chunk of PeerDist retrieval protocol data
1116 *
1117 * @v peerblk PeerDist block download
1118 */
1119static void peerblk_decrypt ( struct peerdist_block *peerblk ) {
1120 struct cipher_algorithm *cipher = peerblk->cipher;
1121 struct digest_algorithm *digest = peerblk->digest;
1122 struct xfer_buffer *xferbuf;
1123 size_t cipher_len;
1124 size_t digest_len;
1125 void *data;
1126 int rc;
1127
1128 /* Sanity check */
1129 assert ( ( PEERBLK_DECRYPT_CHUNKSIZE % cipher->blocksize ) == 0 );
1130
1131 /* Get the underlying data transfer buffer */
1132 xferbuf = xfer_buffer ( &peerblk->xfer );
1133 if ( ! xferbuf ) {
1134 DBGC ( peerblk, "PEERBLK %p %d.%d has no underlying data "
1135 "transfer buffer\n", peerblk, peerblk->segment,
1136 peerblk->block );
1137 rc = -ENOTSUP;
1138 goto err_xfer_buffer;
1139 }
1140 peerblk->decrypt[PEERBLK_DURING].xferbuf = xferbuf;
1141
1142 /* Calculate cipher and digest lengths */
1143 cipher_len = PEERBLK_DECRYPT_CHUNKSIZE;
1144 if ( cipher_len > peerblk->cipher_remaining )
1145 cipher_len = peerblk->cipher_remaining;
1146 digest_len = cipher_len;
1147 if ( digest_len > peerblk->digest_remaining )
1148 digest_len = peerblk->digest_remaining;
1149 assert ( ( cipher_len & ( cipher->blocksize - 1 ) ) == 0 );
1150
1151 /* Allocate temporary data buffer */
1152 data = malloc ( cipher_len );
1153 if ( ! data ) {
1154 rc = -ENOMEM;
1155 goto err_alloc_data;
1156 }
1157
1158 /* Read ciphertext */
1159 if ( ( rc = peerblk_decrypt_read ( peerblk, data, cipher_len ) ) != 0 ){
1160 DBGC ( peerblk, "PEERBLK %p %d.%d could not read ciphertext: "
1161 "%s\n", peerblk, peerblk->segment, peerblk->block,
1162 strerror ( rc ) );
1163 goto err_read;
1164 }
1165
1166 /* Decrypt data */
1167 cipher_decrypt ( cipher, peerblk->cipherctx, data, data, cipher_len );
1168
1169 /* Add data to digest */
1170 digest_update ( digest, peerblk->digestctx, data, digest_len );
1171
1172 /* Write plaintext */
1173 if ( ( rc = peerblk_decrypt_write ( peerblk, data, cipher_len ) ) != 0){
1174 DBGC ( peerblk, "PEERBLK %p %d.%d could not write plaintext: "
1175 "%s\n", peerblk, peerblk->segment, peerblk->block,
1176 strerror ( rc ) );
1177 goto err_write;
1178 }
1179
1180 /* Consume input */
1181 peerblk->cipher_remaining -= cipher_len;
1182 peerblk->digest_remaining -= digest_len;
1183
1184 /* Free temporary data buffer */
1185 free ( data );
1186
1187 /* Continue processing until all input is consumed */
1188 if ( peerblk->cipher_remaining )
1189 return;
1190
1191 /* Complete download attempt */
1192 peerblk_done ( peerblk, 0 );
1193 return;
1194
1195 err_write:
1196 err_read:
1197 free ( data );
1198 err_alloc_data:
1199 err_xfer_buffer:
1200 peerblk_done ( peerblk, rc );
1201}
1202
1203/**
1204 * Close PeerDist retrieval protocol block download attempt
1205 *
1206 * @v peerblk PeerDist block download
1207 * @v rc Reason for close
1208 */
1209static void peerblk_retrieval_close ( struct peerdist_block *peerblk, int rc ) {
1210 size_t buf_len;
1211 size_t vrf_len;
1212
1213 /* Restart interface */
1214 intf_restart ( &peerblk->retrieval, rc );
1215
1216 /* Fail immediately if we have an error */
1217 if ( rc != 0 )
1218 goto done;
1219
1220 /* Abort download attempt (for testing) if applicable */
1221 if ( ( rc = inject_fault ( PEERBLK_ABORT_RATE ) ) != 0 )
1222 goto done;
1223
1224 /* Parse message header */
1225 if ( ( rc = peerblk_parse_header ( peerblk ) ) != 0 )
1226 goto done;
1227
1228 /* Parse message segment and block details */
1229 if ( ( rc = peerblk_parse_block ( peerblk, &buf_len ) ) != 0 )
1230 goto done;
1231
1232 /* If the block was plaintext, then there is nothing more to do */
1233 if ( ! peerblk->cipher )
1234 goto done;
1235
1236 /* Parse message useless details */
1237 if ( ( rc = peerblk_parse_useless ( peerblk, buf_len, &vrf_len ) ) != 0)
1238 goto done;
1239
1240 /* Parse message initialisation vector details */
1241 if ( ( rc = peerblk_parse_iv ( peerblk, buf_len, vrf_len ) ) != 0 )
1242 goto done;
1243
1244 /* Fail if decryption length is not aligned to the cipher block size */
1245 if ( peerblk->cipher_remaining & ( peerblk->cipher->blocksize - 1 ) ) {
1246 DBGC ( peerblk, "PEERBLK %p %d.%d unaligned data length %zd\n",
1247 peerblk, peerblk->segment, peerblk->block,
1248 peerblk->cipher_remaining );
1249 rc = -EPROTO;
1250 goto done;
1251 }
1252
1253 /* Stop the download attempt timer: there is no point in
1254 * timing out while decrypting.
1255 */
1256 stop_timer ( &peerblk->timer );
1257
1258 /* Start decryption process */
1259 process_add ( &peerblk->process );
1260 return;
1261
1262 done:
1263 /* Complete download attempt */
1264 peerblk_done ( peerblk, rc );
1265}
1266
1267/******************************************************************************
1268 *
1269 * Retry policy
1270 *
1271 ******************************************************************************
1272 */
1273
1274/**
1275 * Handle PeerDist retry timer expiry
1276 *
1277 * @v timer Retry timer
1278 * @v over Failure indicator
1279 */
1280static void peerblk_expired ( struct retry_timer *timer, int over __unused ) {
1281 struct peerdist_block *peerblk =
1283 struct peerdisc_segment *segment = peerblk->discovery.segment;
1284 struct peerdisc_peer *head;
1285 unsigned long now = peerblk_timestamp();
1286 const char *location;
1287 int rc;
1288
1289 /* Profile discovery timeout, if applicable */
1290 if ( ( peerblk->peer == NULL ) && ( timer->timeout != 0 ) ) {
1291 profile_custom ( &peerblk_discovery_timeout_profiler,
1292 ( now - peerblk->started ) );
1293 DBGC ( peerblk, "PEERBLK %p %d.%d discovery timed out after "
1294 "%ld ticks\n", peerblk, peerblk->segment,
1295 peerblk->block, timer->timeout );
1296 }
1297
1298 /* Profile download timeout, if applicable */
1299 if ( ( peerblk->peer != NULL ) && ( timer->timeout != 0 ) ) {
1300 profile_custom ( &peerblk_attempt_timeout_profiler,
1301 ( now - peerblk->attempted ) );
1302 DBGC ( peerblk, "PEERBLK %p %d.%d timed out after %ld ticks\n",
1303 peerblk, peerblk->segment, peerblk->block,
1304 timer->timeout );
1305 }
1306
1307 /* Abort any current download attempt */
1308 peerblk_reset ( peerblk, -ETIMEDOUT );
1309
1310 /* Record attempt start time */
1311 peerblk->attempted = now;
1312
1313 /* If we have exceeded our maximum number of attempt cycles
1314 * (each cycle comprising a retrieval protocol download from
1315 * each peer in the list followed by a raw download from the
1316 * origin server), then abort the overall download.
1317 */
1318 head = list_entry ( &segment->peers, struct peerdisc_peer, list );
1319 if ( ( peerblk->peer == head ) &&
1320 ( ++peerblk->cycles >= PEERBLK_MAX_ATTEMPT_CYCLES ) ) {
1321 rc = peerblk->rc;
1322 assert ( rc != 0 );
1323 goto err;
1324 }
1325
1326 /* If we have not yet made any download attempts, then move to
1327 * the start of the peer list.
1328 */
1329 if ( peerblk->peer == NULL )
1330 peerblk->peer = head;
1331
1332 /* Attempt retrieval protocol download from next usable peer */
1333 list_for_each_entry_continue ( peerblk->peer, &segment->peers, list ) {
1334
1335 /* Attempt retrieval protocol download from this peer */
1336 location = peerblk->peer->location;
1337 if ( ( rc = peerblk_retrieval_open ( peerblk,
1338 location ) ) != 0 ) {
1339 /* Non-fatal: continue to try next peer */
1340 continue;
1341 }
1342
1343 /* Peer download started */
1344 return;
1345 }
1346
1347 /* Add to raw download queue */
1348 peerblk_enqueue ( peerblk, &peerblk_raw_queue );
1349
1350 return;
1351
1352 err:
1353 peerblk_close ( peerblk, rc );
1354}
1355
1356/**
1357 * Handle PeerDist peer discovery
1358 *
1359 * @v discovery PeerDist discovery client
1360 */
1361static void peerblk_discovered ( struct peerdisc_client *discovery ) {
1362 struct peerdist_block *peerblk =
1364 unsigned long now = peerblk_timestamp();
1365
1366 /* Do nothing unless we are still waiting for the initial
1367 * discovery timeout.
1368 */
1369 if ( ( peerblk->peer != NULL ) || ( peerblk->timer.timeout == 0 ) )
1370 return;
1371
1372 /* Schedule an immediate retry */
1373 start_timer_nodelay ( &peerblk->timer );
1374
1375 /* Profile discovery success */
1376 profile_custom ( &peerblk_discovery_success_profiler,
1377 ( now - peerblk->started ) );
1378}
1379
1380/******************************************************************************
1381 *
1382 * Opener
1383 *
1384 ******************************************************************************
1385 */
1386
1387/** PeerDist block download data transfer interface operations */
1391
1392/** PeerDist block download data transfer interface descriptor */
1395
1396/** PeerDist block download raw data interface operations */
1401
1402/** PeerDist block download raw data interface descriptor */
1405
1406/** PeerDist block download retrieval protocol interface operations */
1411
1412/** PeerDist block download retrieval protocol interface descriptor */
1414 INTF_DESC ( struct peerdist_block, retrieval,
1416
1417/** PeerDist block download decryption process descriptor */
1420
1421/** PeerDist block download discovery operations */
1425
1426/**
1427 * Open PeerDist block download
1428 *
1429 * @v xfer Data transfer interface
1430 * @v uri Original URI
1431 * @v info Content information block
1432 * @ret rc Return status code
1433 */
1434int peerblk_open ( struct interface *xfer, struct uri *uri,
1435 struct peerdist_info_block *block ) {
1436 const struct peerdist_info_segment *segment = block->segment;
1437 const struct peerdist_info *info = segment->info;
1438 struct digest_algorithm *digest = info->digest;
1439 struct peerdist_block *peerblk;
1440 unsigned long timeout;
1441 size_t digestsize;
1442 int rc;
1443
1444 /* Allocate and initialise structure */
1445 peerblk = zalloc ( sizeof ( *peerblk ) + digest->ctxsize );
1446 if ( ! peerblk ) {
1447 rc = -ENOMEM;
1448 goto err_alloc;
1449 }
1450 ref_init ( &peerblk->refcnt, peerblk_free );
1451 intf_init ( &peerblk->xfer, &peerblk_xfer_desc, &peerblk->refcnt );
1452 intf_init ( &peerblk->raw, &peerblk_raw_desc, &peerblk->refcnt );
1454 &peerblk->refcnt );
1455 peerblk->uri = uri_get ( uri );
1456 memcpy ( &peerblk->range, &block->range, sizeof ( peerblk->range ) );
1457 memcpy ( &peerblk->trim, &block->trim, sizeof ( peerblk->trim ) );
1458 peerblk->offset = ( block->trim.start - info->trim.start );
1459 peerblk->digest = info->digest;
1460 peerblk->digestsize = digestsize = info->digestsize;
1461 peerblk->digestctx = ( ( ( void * ) peerblk ) + sizeof ( *peerblk ) );
1462 peerblk->segment = segment->index;
1463 memcpy ( peerblk->id, segment->id, sizeof ( peerblk->id ) );
1464 memcpy ( peerblk->secret, segment->secret, sizeof ( peerblk->secret ) );
1465 peerblk->block = block->index;
1466 memcpy ( peerblk->hash, block->hash, sizeof ( peerblk->hash ) );
1467 xferbuf_malloc_init ( &peerblk->buffer );
1469 &peerblk->refcnt );
1471 INIT_LIST_HEAD ( &peerblk->queued );
1472 timer_init ( &peerblk->timer, peerblk_expired, &peerblk->refcnt );
1473 DBGC2 ( peerblk, "PEERBLK %p %d.%d id %02x%02x%02x%02x%02x..."
1474 "%02x%02x%02x [%08zx,%08zx)", peerblk, peerblk->segment,
1475 peerblk->block, peerblk->id[0], peerblk->id[1], peerblk->id[2],
1476 peerblk->id[3], peerblk->id[4], peerblk->id[ digestsize - 3 ],
1477 peerblk->id[ digestsize - 2 ], peerblk->id[ digestsize - 1 ],
1478 peerblk->range.start, peerblk->range.end );
1479 if ( ( peerblk->trim.start != peerblk->range.start ) ||
1480 ( peerblk->trim.end != peerblk->range.end ) ) {
1481 DBGC2 ( peerblk, " covers [%08zx,%08zx)",
1482 peerblk->trim.start, peerblk->trim.end );
1483 }
1484 DBGC2 ( peerblk, "\n" );
1485
1486 /* Open discovery */
1487 if ( ( rc = peerdisc_open ( &peerblk->discovery, peerblk->id,
1488 peerblk->digestsize ) ) != 0 )
1489 goto err_open_discovery;
1490
1491 /* Schedule a retry attempt either immediately (if we already
1492 * have some peers) or after the discovery timeout.
1493 */
1494 timeout = ( list_empty ( &peerblk->discovery.segment->peers ) ?
1496 start_timer_fixed ( &peerblk->timer, timeout );
1497
1498 /* Record start time */
1499 peerblk->started = peerblk_timestamp();
1500
1501 /* Attach to parent interface, mortalise self, and return */
1502 intf_plug_plug ( xfer, &peerblk->xfer );
1503 ref_put ( &peerblk->refcnt );
1504 return 0;
1505
1506 err_open_discovery:
1507 peerblk_close ( peerblk, rc );
1508 err_alloc:
1509 return rc;
1510}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
__be32 raw[7]
Definition CIB_PRM.h:0
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
struct cipher_algorithm aes_cbc_algorithm
u32 info
Definition ar9003_mac.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
pseudo_bit_t hash[0x00010]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
struct bofm_section_header done
Definition bofm_test.c:46
#define PEERBLK_STALL_RATE
Definition fault.h:28
#define PEERBLK_ABORT_RATE
Definition fault.h:31
#define PEERBLK_ANNUL_RATE
Definition fault.h:25
#define PEERBLK_CORRUPT_RATE
Definition fault.h:34
void timeout(int)
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint16_t queue
Queue ID.
Definition ena.h:11
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
uint32_t start
Starting offset.
Definition netvsc.h:1
uint8_t head
Head number.
Definition int13.h:23
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define EPROTO
Protocol error.
Definition errno.h:625
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EIO
Input/output error.
Definition errno.h:434
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ERANGE
Result too large.
Definition errno.h:640
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Hyper Text Transport Protocol.
struct http_method http_post
HTTP POST method.
Definition httpcore.c:149
struct http_method http_get
HTTP GET method.
Definition httpcore.c:144
int http_open(struct interface *xfer, struct http_method *method, struct uri *uri, struct http_request_range *range, struct http_request_content *content)
Open HTTP transaction.
Definition httpcore.c:642
#define be32_to_cpu(value)
Definition byteswap.h:117
#define ntohl(value)
Definition byteswap.h:135
#define htonl(value)
Definition byteswap.h:134
#define __attribute__(x)
Definition compiler.h:10
static void digest_init(struct digest_algorithm *digest, void *ctx)
Definition crypto.h:219
static int cipher_setkey(struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen)
Definition crypto.h:235
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:230
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition crypto.h:224
static void cipher_setiv(struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen)
Definition crypto.h:241
#define cipher_decrypt(cipher, ctx, src, dst, len)
Definition crypto.h:261
Fault injection.
Profiling.
#define __profiler
Declare a profiler.
Definition profile.h:61
static void profile_custom(struct profiler *profiler, unsigned long sample)
Record profiling sample in custom units.
Definition profile.h:201
#define PROFILING
Definition profile.h:20
iPXE timers
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
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(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
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
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_pull(iobuf, len)
Definition iobuf.h:107
#define iob_unput(iobuf, len)
Definition iobuf.h:140
uint64_t rsp
Definition librm.h:18
uint16_t segment
Code segment.
Definition librm.h:3
uint16_t mid
Middle 16 bits of address.
Definition librm.h:9
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition list.h:334
#define list_entry(list, type, member)
Get the container of a list entry.
Definition list.h:322
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition list.h:31
#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_continue(pos, head, member)
Iterate over entries in a list, starting after current position.
Definition list.h:474
#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
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
uint32_t end
Ending offset.
Definition netvsc.h:7
Peer Content Caching and Retrieval: Retrieval Protocol [MS-PCCRR].
#define peerdist_msg_getblks_t(digestsize, count, vrf_len)
Retrieval protocol block fetch request.
Definition pccrr.h:266
#define PEERDIST_MAGIC_PATH
Magic retrieval URI path.
Definition pccrr.h:18
#define PEERDIST_MSG_GETBLKS_VERSION
Retrieval protocol block fetch request version.
Definition pccrr.h:275
#define PEERDIST_MSG_BLK_TYPE
Retrieval protocol block fetch response type.
Definition pccrr.h:351
@ PEERDIST_MSG_AES_192_CBC
AES-192 in CBC mode.
Definition pccrr.h:174
@ PEERDIST_MSG_AES_128_CBC
AES-128 in CBC mode.
Definition pccrr.h:172
@ PEERDIST_MSG_PLAINTEXT
No encryption.
Definition pccrr.h:170
@ PEERDIST_MSG_AES_256_CBC
AES-256 in CBC mode.
Definition pccrr.h:176
uint32_t blksize
Cipher block size.
Definition pccrr.h:1
#define PEERDIST_MSG_GETBLKS_TYPE
Retrieval protocol block fetch request type.
Definition pccrr.h:278
uint32_t digestsize
Digest size (i.e.
Definition pccrr.h:1
struct pci_range range
PCI bus:dev.fn address range.
Definition pcicloud.c:40
static int peerblk_raw_open(struct peerdist_block *peerblk)
Open PeerDist raw block download attempt.
Definition peerblk.c:360
static struct process_descriptor peerblk_queue_desc
PeerDist block download queue process descriptor.
Definition peerblk.c:561
static void peerblk_enqueue(struct peerdist_block *peerblk, struct peerdist_block_queue *queue)
Add block to download queue.
Definition peerblk.c:518
static struct interface_operation peerblk_retrieval_operations[]
PeerDist block download retrieval protocol interface operations.
Definition peerblk.c:1407
static void peerblk_step(struct peerdist_block_queue *queue)
PeerDist block download queue process.
Definition peerblk.c:481
static int peerblk_parse_useless(struct peerdist_block *peerblk, size_t buf_len, size_t *vrf_len)
Parse retrieval protocol message useless details.
Definition peerblk.c:984
static struct interface_operation peerblk_raw_operations[]
PeerDist block download raw data interface operations.
Definition peerblk.c:1397
static int peerblk_deliver(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta, size_t pos)
Deliver download attempt data block.
Definition peerblk.c:247
static void peerblk_reset(struct peerdist_block *peerblk, int rc)
Reset PeerDist block download attempt.
Definition peerblk.c:168
static int peerblk_parse_block(struct peerdist_block *peerblk, size_t *buf_len)
Parse retrieval protocol message segment and block details.
Definition peerblk.c:880
static int peerblk_decrypt_read(struct peerdist_block *peerblk, void *data, size_t len)
Read from decryption buffers.
Definition peerblk.c:1052
static void peerblk_raw_close(struct peerdist_block *peerblk, int rc)
Close PeerDist raw block download attempt.
Definition peerblk.c:451
static int peerblk_parse_header(struct peerdist_block *peerblk)
Parse retrieval protocol message header.
Definition peerblk.c:790
static int peerblk_parse_iv(struct peerdist_block *peerblk, size_t buf_len, size_t vrf_len)
Parse retrieval protocol message initialisation vector details.
Definition peerblk.c:1013
#define PEERBLK_DECRYPT_CHUNKSIZE
PeerDist decryption chunksize.
Definition peerblk.c:51
#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT
PeerDist retrieval protocol block download attempt initial progress timeout.
Definition peerblk.c:88
#define PEERBLK_RETRIEVAL_RX_TIMEOUT
PeerDist retrieval protocol block download attempt ongoing progress timeout.
Definition peerblk.c:94
#define PEERBLK_RAW_OPEN_TIMEOUT
PeerDist raw block download attempt initial progress timeout.
Definition peerblk.c:76
static struct uri * peerblk_retrieval_uri(const char *location)
Construct PeerDist retrieval protocol URI.
Definition peerblk.c:585
static struct peerdisc_client_operations peerblk_discovery_operations
PeerDist block download discovery operations.
Definition peerblk.c:1422
static struct interface_descriptor peerblk_xfer_desc
PeerDist block download data transfer interface descriptor.
Definition peerblk.c:1393
#define PEERBLK_RAW_MAX
PeerDist maximum number of concurrent raw block downloads.
Definition peerblk.c:70
static void peerblk_discovered(struct peerdisc_client *discovery)
Handle PeerDist peer discovery.
Definition peerblk.c:1361
static int peerblk_retrieval_open(struct peerdist_block *peerblk, const char *location)
Open PeerDist retrieval protocol block download attempt.
Definition peerblk.c:604
static struct interface_operation peerblk_xfer_operations[]
PeerDist block download data transfer interface operations.
Definition peerblk.c:1388
static size_t peerblk_offset(struct peerdist_block *peerblk, size_t pos)
Calculate offset within overall download.
Definition peerblk.c:233
static void peerblk_dequeue(struct peerdist_block *peerblk)
Remove block from download queue.
Definition peerblk.c:538
static struct process_descriptor peerblk_process_desc
PeerDist block download decryption process descriptor.
Definition peerblk.c:1418
static void peerblk_done(struct peerdist_block *peerblk, int rc)
Finish PeerDist block download attempt.
Definition peerblk.c:298
static unsigned long peerblk_timestamp(void)
Get profiling timestamp.
Definition peerblk.c:139
static void peerblk_decrypt(struct peerdist_block *peerblk)
Decrypt one chunk of PeerDist retrieval protocol data.
Definition peerblk.c:1119
static struct interface_descriptor peerblk_retrieval_desc
PeerDist block download retrieval protocol interface descriptor.
Definition peerblk.c:1413
static struct peerdist_block_queue peerblk_raw_queue
Raw block download queue.
Definition peerblk.c:565
#define PEERBLK_MAX_ATTEMPT_CYCLES
PeerDist maximum number of full download attempt cycles.
Definition peerblk.c:105
#define PEERBLK_RAW_RX_TIMEOUT
PeerDist raw block download attempt ongoing progress timeout.
Definition peerblk.c:82
static void peerblk_close(struct peerdist_block *peerblk, int rc)
Close PeerDist block download.
Definition peerblk.c:206
static struct interface_descriptor peerblk_raw_desc
PeerDist block download raw data interface descriptor.
Definition peerblk.c:1403
static int peerblk_retrieval_rx(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive PeerDist retrieval protocol data.
Definition peerblk.c:677
static void peerblk_retrieval_close(struct peerdist_block *peerblk, int rc)
Close PeerDist retrieval protocol block download attempt.
Definition peerblk.c:1209
int peerblk_open(struct interface *xfer, struct uri *uri, struct peerdist_info_block *block)
Open PeerDist block download.
Definition peerblk.c:1434
static int peerblk_raw_rx(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive PeerDist raw data.
Definition peerblk.c:403
static int peerblk_decrypt_write(struct peerdist_block *peerblk, const void *data, size_t len)
Write to decryption buffers and update offsets and lengths.
Definition peerblk.c:1085
static void peerblk_expired(struct retry_timer *timer, int over __unused)
Handle PeerDist retry timer expiry.
Definition peerblk.c:1280
static void peerblk_free(struct refcnt *refcnt)
Free PeerDist block download.
Definition peerblk.c:153
Peer Content Caching and Retrieval (PeerDist) protocol block downloads.
@ PEERBLK_AFTER
Data after the trimmed content.
Definition peerblk.h:41
@ PEERBLK_BEFORE
Data before the trimmed content.
Definition peerblk.h:37
@ PEERBLK_DURING
Data within the trimmed content.
Definition peerblk.h:39
#define peerblk_msg_blk_t(digestsize, len, vrf_len, blksize)
Retrieval protocol block fetch response (including transport header)
Definition peerblk.h:159
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Definition peerdisc.c:101
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
Definition peerdisc.c:560
void peerdisc_close(struct peerdisc_client *peerdisc)
Close PeerDist discovery client.
Definition peerdisc.c:598
unsigned int peerdisc_timeout_secs
Recommended discovery timeout (in seconds)
Definition peerdisc.c:75
static void peerdisc_init(struct peerdisc_client *peerdisc, struct peerdisc_client_operations *op)
Initialise PeerDist discovery.
Definition peerdisc.h:105
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
#define PROC_DESC_ONCE(object_type, process, _step)
Define a process descriptor for a process that runs only once.
Definition process.h:98
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_INIT(_process, _desc)
Initialise a static process.
Definition process.h:132
#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
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#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 memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
A cipher algorithm.
Definition crypto.h:51
const char * name
Algorithm name.
Definition crypto.h:53
size_t blocksize
Block size.
Definition crypto.h:61
size_t ctxsize
Context size.
Definition crypto.h:55
A message digest algorithm.
Definition crypto.h:19
size_t digestsize
Digest size.
Definition crypto.h:27
size_t ctxsize
Context size.
Definition crypto.h:23
HTTP request content descriptor.
Definition http.h:144
size_t len
Content length.
Definition http.h:150
const void * data
Content data (if any)
Definition http.h:148
HTTP request range descriptor.
Definition http.h:136
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
void * data
Start of data.
Definition iobuf.h:53
PeerDist discovery client operations.
Definition peerdisc.h:90
A PeerDist discovery client.
Definition peerdisc.h:80
struct peerdisc_segment * segment
Discovery segment.
Definition peerdisc.h:82
A PeerDist discovery peer.
Definition peerdisc.h:72
struct list_head list
List of peers.
Definition peerdisc.h:74
char location[0]
Peer location.
Definition peerdisc.h:76
A PeerDist discovery segment.
Definition peerdisc.h:43
struct list_head peers
List of discovered peers.
Definition peerdisc.h:64
A PeerDist retrieval protocol decryption buffer descriptor.
Definition peerblk.h:25
struct xfer_buffer * xferbuf
Data transfer buffer.
Definition peerblk.h:27
size_t offset
Offset within data transfer buffer.
Definition peerblk.h:29
size_t len
Length to use from data transfer buffer.
Definition peerblk.h:31
PeerDist block download queue.
Definition peerblk.h:133
A PeerDist block download.
Definition peerblk.h:47
unsigned int segment
Segment index.
Definition peerblk.h:83
struct retry_timer timer
Retry timer.
Definition peerblk.h:120
struct interface raw
Raw data interface.
Definition peerblk.h:53
size_t end
End of trimmed content (relative to incoming data stream)
Definition peerblk.h:98
struct uri * uri
Original URI.
Definition peerblk.h:58
struct cipher_algorithm * cipher
Cipher algorithm.
Definition peerblk.h:78
struct peerdist_block_decrypt decrypt[PEERBLK_NUM_BUFFERS]
Decryption data buffer descriptors.
Definition peerblk.h:105
void * digestctx
Digest context (statically allocated at instantiation time)
Definition peerblk.h:75
size_t start
Start of trimmed content (relative to incoming data stream)
Definition peerblk.h:96
unsigned long started
Time at which block download was started.
Definition peerblk.h:127
struct peerdist_block_queue * queue
Block download queue.
Definition peerblk.h:116
struct digest_algorithm * digest
Digest algorithm.
Definition peerblk.h:67
unsigned int cycles
Number of full attempt cycles completed.
Definition peerblk.h:122
struct peerdist_range range
Content range of this block.
Definition peerblk.h:60
struct xfer_buffer buffer
Data buffer.
Definition peerblk.h:100
size_t digestsize
Digest size.
Definition peerblk.h:73
size_t offset
Offset of first byte in trimmed range within overall download.
Definition peerblk.h:64
uint8_t secret[PEERDIST_DIGEST_MAX_SIZE]
Segment secret.
Definition peerblk.h:87
struct peerdisc_client discovery
Discovery client.
Definition peerblk.h:112
size_t pos
Current position (relative to incoming data stream)
Definition peerblk.h:94
struct interface xfer
Data transfer interface.
Definition peerblk.h:51
struct process process
Decryption process.
Definition peerblk.h:103
void * cipherctx
Cipher context (dynamically allocated as needed)
Definition peerblk.h:80
unsigned long attempted
Time at which most recent attempt was started.
Definition peerblk.h:129
struct peerdist_range trim
Trimmed range of this block.
Definition peerblk.h:62
uint8_t hash[PEERDIST_DIGEST_MAX_SIZE]
Block hash.
Definition peerblk.h:91
size_t cipher_remaining
Remaining decryption length.
Definition peerblk.h:107
unsigned int block
Block index.
Definition peerblk.h:89
struct refcnt refcnt
Reference count.
Definition peerblk.h:49
struct list_head queued
List of queued block downloads.
Definition peerblk.h:118
struct peerdisc_peer * peer
Current position in discovered peer list.
Definition peerblk.h:114
size_t digest_remaining
Remaining digest length (excluding AES padding bytes)
Definition peerblk.h:109
uint8_t id[PEERDIST_DIGEST_MAX_SIZE]
Segment identifier.
Definition peerblk.h:85
struct interface retrieval
Retrieval protocol interface.
Definition peerblk.h:55
int rc
Most recent attempt failure.
Definition peerblk.h:124
A content information block.
Definition pccrc.h:394
A content information segment.
Definition pccrc.h:347
Content information.
Definition pccrc.h:317
Retrieval protocol message header.
Definition pccrr.h:152
Retrieval protocol transport response header.
Definition pccrr.h:180
size_t start
Start offset.
Definition pccrc.h:311
size_t end
End offset.
Definition pccrc.h:313
A process descriptor.
Definition process.h:32
A process.
Definition process.h:18
A data structure for storing profiling information.
Definition profile.h:27
A reference counter.
Definition refcnt.h:27
A retry timer.
Definition retry.h:22
unsigned long timeout
Timeout value (in ticks)
Definition retry.h:28
A timer.
Definition timer.h:29
A Uniform Resource Identifier.
Definition uri.h:65
A data transfer buffer.
Definition xferbuf.h:19
size_t len
Size of data.
Definition xferbuf.h:23
void * data
Data.
Definition xferbuf.h:21
Data transfer metadata.
Definition xfer.h:23
unsigned int flags
Flags.
Definition xfer.h:29
off_t offset
Offset of data within stream.
Definition xfer.h:38
unsigned long currticks(void)
Get current system time in ticks.
Definition timer.c:43
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition ucode.h:15
int32_t after
Final microcode version.
Definition ucode.h:7
int32_t before
Initial microcode version.
Definition ucode.h:5
struct uri * parse_uri(const char *uri_string)
Parse URI.
Definition uri.c:297
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_check_order(struct xfer_metadata *meta, size_t *pos, size_t len)
Check that data is delivered strictly in order.
Definition xfer.c:378
Data transfer interfaces.
#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
int xferbuf_read(struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len)
Read from data transfer buffer.
Definition xferbuf.c:147
int xferbuf_write(struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
Write to data transfer buffer.
Definition xferbuf.c:113
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
Definition xferbuf.c:74
static void xferbuf_malloc_init(struct xfer_buffer *xferbuf)
Initialise malloc()-based data transfer buffer.
Definition xferbuf.h:54