iPXE
peerblk.c File Reference

Peer Content Caching and Retrieval (PeerDist) protocol block downloads. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipxe/http.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/uri.h>
#include <ipxe/timer.h>
#include <ipxe/profile.h>
#include <ipxe/fault.h>
#include <ipxe/pccrr.h>
#include <ipxe/peerblk.h>

Go to the source code of this file.

Macros

#define PEERBLK_DECRYPT_CHUNKSIZE   2048
 PeerDist decryption chunksize.
#define PEERBLK_RAW_MAX   2
 PeerDist maximum number of concurrent raw block downloads.
#define PEERBLK_RAW_OPEN_TIMEOUT   ( 10 * TICKS_PER_SEC )
 PeerDist raw block download attempt initial progress timeout.
#define PEERBLK_RAW_RX_TIMEOUT   ( 15 * TICKS_PER_SEC )
 PeerDist raw block download attempt ongoing progress timeout.
#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT   ( 3 * TICKS_PER_SEC )
 PeerDist retrieval protocol block download attempt initial progress timeout.
#define PEERBLK_RETRIEVAL_RX_TIMEOUT   ( 5 * TICKS_PER_SEC )
 PeerDist retrieval protocol block download attempt ongoing progress timeout.
#define PEERBLK_MAX_ATTEMPT_CYCLES   4
 PeerDist maximum number of full download attempt cycles.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 FILE_SECBOOT (PERMITTED)
static void peerblk_dequeue (struct peerdist_block *peerblk)
 Remove block from download queue.
static unsigned long peerblk_timestamp (void)
 Get profiling timestamp.
static void peerblk_free (struct refcnt *refcnt)
 Free PeerDist block download.
static void peerblk_reset (struct peerdist_block *peerblk, int rc)
 Reset PeerDist block download attempt.
static void peerblk_close (struct peerdist_block *peerblk, int rc)
 Close PeerDist block download.
static size_t peerblk_offset (struct peerdist_block *peerblk, size_t pos)
 Calculate offset within overall download.
static int peerblk_deliver (struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta, size_t pos)
 Deliver download attempt data block.
static void peerblk_done (struct peerdist_block *peerblk, int rc)
 Finish PeerDist block download attempt.
static int peerblk_raw_open (struct peerdist_block *peerblk)
 Open PeerDist raw block download attempt.
static int peerblk_raw_rx (struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive PeerDist raw data.
static void peerblk_raw_close (struct peerdist_block *peerblk, int rc)
 Close PeerDist raw block download attempt.
static void peerblk_step (struct peerdist_block_queue *queue)
 PeerDist block download queue process.
static void peerblk_enqueue (struct peerdist_block *peerblk, struct peerdist_block_queue *queue)
 Add block to download queue.
static int peerblk_retrieval_open (struct peerdist_block *peerblk, struct peerdist_retrieval *retrieval, const char *location)
 Open PeerDist retrieval protocol block download attempt.
static int peerblk_retrieval_rx (struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive PeerDist retrieval protocol data.
static int peerblk_parse_header (struct peerdist_block *peerblk)
 Parse retrieval protocol message header.
static int peerblk_parse_block (struct peerdist_block *peerblk, size_t *buf_len)
 Parse retrieval protocol message segment and block details.
static int peerblk_parse_useless (struct peerdist_block *peerblk, size_t buf_len, size_t *vrf_len)
 Parse retrieval protocol message useless details.
static int peerblk_parse_iv (struct peerdist_block *peerblk, size_t buf_len, size_t vrf_len)
 Parse retrieval protocol message initialisation vector details.
static int peerblk_decrypt_read (struct peerdist_block *peerblk, void *data, size_t len)
 Read from decryption buffers.
static int peerblk_decrypt_write (struct peerdist_block *peerblk, const void *data, size_t len)
 Write to decryption buffers and update offsets and lengths.
static void peerblk_decrypt (struct peerdist_block *peerblk)
 Decrypt one chunk of PeerDist retrieval protocol data.
static void peerblk_retrieval_close (struct peerdist_block *peerblk, int rc)
 Close PeerDist retrieval protocol block download attempt.
static void peerblk_expired (struct retry_timer *timer, int over __unused)
 Handle PeerDist retry timer expiry.
static void peerblk_discovered (struct peerdisc_client *discovery)
 Handle PeerDist peer discovery.
int peerblk_open (struct interface *xfer, struct uri *uri, struct peerdist_info_block *block)
 Open PeerDist block download.

Variables

static struct profiler peerblk_download_profiler __profiler
 PeerDist block download profiler.
static struct process_descriptor peerblk_queue_desc
 PeerDist block download queue process descriptor.
static struct peerdist_block_queue peerblk_raw_queue
 Raw block download queue.
static struct interface_operation peerblk_xfer_operations []
 PeerDist block download data transfer interface operations.
static struct interface_descriptor peerblk_xfer_desc
 PeerDist block download data transfer interface descriptor.
static struct interface_operation peerblk_raw_operations []
 PeerDist block download raw data interface operations.
static struct interface_descriptor peerblk_raw_desc
 PeerDist block download raw data interface descriptor.
static struct interface_operation peerblk_retrieval_operations []
 PeerDist block download retrieval protocol interface operations.
static struct interface_descriptor peerblk_retrieval_desc
 PeerDist block download retrieval protocol interface descriptor.
static struct process_descriptor peerblk_process_desc
 PeerDist block download decryption process descriptor.
static struct peerdisc_client_operations peerblk_discovery_operations
 PeerDist block download discovery operations.

Detailed Description

Peer Content Caching and Retrieval (PeerDist) protocol block downloads.

Definition in file peerblk.c.

Macro Definition Documentation

◆ PEERBLK_DECRYPT_CHUNKSIZE

#define PEERBLK_DECRYPT_CHUNKSIZE   2048

PeerDist decryption chunksize.

This is a policy decision.

Definition at line 51 of file peerblk.c.

Referenced by peerblk_decrypt().

◆ PEERBLK_RAW_MAX

#define PEERBLK_RAW_MAX   2

PeerDist maximum number of concurrent raw block downloads.

Raw block downloads are expensive if the origin server uses HTTPS, since each concurrent download will require local TLS resources (including potentially large received encrypted data buffers).

Raw block downloads may also be prohibitively slow to initiate when the origin server is using HTTPS and client certificates. Origin servers for PeerDist downloads are likely to be running IIS, which has a bug that breaks session resumption and requires each connection to go through the full client certificate verification.

Limit the total number of concurrent raw block downloads to ameliorate these problems.

This is a policy decision.

Definition at line 70 of file peerblk.c.

◆ PEERBLK_RAW_OPEN_TIMEOUT

#define PEERBLK_RAW_OPEN_TIMEOUT   ( 10 * TICKS_PER_SEC )

PeerDist raw block download attempt initial progress timeout.

This is a policy decision.

Definition at line 76 of file peerblk.c.

Referenced by peerblk_raw_open().

◆ PEERBLK_RAW_RX_TIMEOUT

#define PEERBLK_RAW_RX_TIMEOUT   ( 15 * TICKS_PER_SEC )

PeerDist raw block download attempt ongoing progress timeout.

This is a policy decision.

Definition at line 82 of file peerblk.c.

Referenced by peerblk_raw_rx().

◆ PEERBLK_RETRIEVAL_OPEN_TIMEOUT

#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT   ( 3 * TICKS_PER_SEC )

PeerDist retrieval protocol block download attempt initial progress timeout.

This is a policy decision.

Definition at line 88 of file peerblk.c.

Referenced by peerblk_retrieval_open().

◆ PEERBLK_RETRIEVAL_RX_TIMEOUT

#define PEERBLK_RETRIEVAL_RX_TIMEOUT   ( 5 * TICKS_PER_SEC )

PeerDist retrieval protocol block download attempt ongoing progress timeout.

This is a policy decision.

Definition at line 94 of file peerblk.c.

Referenced by peerblk_retrieval_rx().

◆ PEERBLK_MAX_ATTEMPT_CYCLES

#define PEERBLK_MAX_ATTEMPT_CYCLES   4

PeerDist maximum number of full download attempt cycles.

This is the maximum number of times that we will try a full cycle of download attempts (i.e. a retrieval protocol download attempt from each discovered peer plus a raw download attempt from the origin server).

This is a policy decision.

Definition at line 105 of file peerblk.c.

Referenced by peerblk_expired().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED )

◆ peerblk_dequeue()

void peerblk_dequeue ( struct peerdist_block * peerblk)
static

Remove block from download queue.

Parameters
peerblkPeerDist block download

Definition at line 538 of file peerblk.c.

538 {
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}
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
uint16_t queue
Queue ID.
Definition ena.h:11
#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 process_add(struct process *process)
Add process to process list.
Definition process.c:60
PeerDist block download queue.
Definition peerblk.h:133
struct peerdist_block_queue * queue
Block download queue.
Definition peerblk.h:116
struct list_head queued
List of queued block downloads.
Definition peerblk.h:118

References assert, INIT_LIST_HEAD, list_del, list_empty, NULL, process_add(), peerdist_block::queue, queue, and peerdist_block::queued.

Referenced by peerblk_reset().

◆ peerblk_timestamp()

unsigned long peerblk_timestamp ( void )
inlinestatic

Get profiling timestamp.

Return values
timestampTimestamp

Definition at line 139 of file peerblk.c.

139 {
140
141 if ( PROFILING ) {
142 return currticks();
143 } else {
144 return 0;
145 }
146}
#define PROFILING
Definition profile.h:20
unsigned long currticks(void)
Get current system time in ticks.
Definition timer.c:43

References currticks(), and PROFILING.

Referenced by peerblk_close(), peerblk_discovered(), peerblk_done(), peerblk_expired(), and peerblk_open().

◆ peerblk_free()

void peerblk_free ( struct refcnt * refcnt)
static

Free PeerDist block download.

Parameters
refcntReference count

Definition at line 153 of file peerblk.c.

153 {
154 struct peerdist_block *peerblk =
156
157 uri_put ( peerblk->uri );
158 free ( peerblk->cipherctx );
159 free ( peerblk );
160}
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
A PeerDist block download.
Definition peerblk.h:47
struct uri * uri
Original URI.
Definition peerblk.h:58
void * cipherctx
Cipher context (dynamically allocated as needed).
Definition peerblk.h:80
A reference counter.
Definition refcnt.h:27
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition uri.h:206

References peerdist_block::cipherctx, container_of, free, peerdist_block::uri, and uri_put().

Referenced by peerblk_open().

◆ peerblk_reset()

void peerblk_reset ( struct peerdist_block * peerblk,
int rc )
static

Reset PeerDist block download attempt.

Parameters
peerblkPeerDist block download
rcReason for reset

Definition at line 168 of file peerblk.c.

168 {
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}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
static void digest_init(struct digest_algorithm *digest, void *ctx)
Definition crypto.h:294
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition interface.c:344
static void peerblk_dequeue(struct peerdist_block *peerblk)
Remove block from download queue.
Definition peerblk.c:538
void process_del(struct process *process)
Remove process from process list.
Definition process.c:80
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
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 cipher_algorithm * cipher
Cipher algorithm.
Definition peerblk.h:78
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
struct digest_algorithm * digest
Digest algorithm.
Definition peerblk.h:67
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 pos
Current position (relative to incoming data stream).
Definition peerblk.h:94
struct process process
Decryption process.
Definition peerblk.h:103
struct peerdist_range trim
Trimmed range of this block.
Definition peerblk.h:62
struct interface retrieval
Retrieval protocol interface.
Definition peerblk.h:55
size_t start
Start offset.
Definition pccrc.h:311
size_t end
End offset.
Definition pccrc.h:313
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
Definition xferbuf.c:88

References assert, peerdist_block::buffer, peerdist_block::cipher, peerdist_block::cipherctx, peerdist_block::digest, digest_init(), peerdist_block::digestctx, peerdist_block::end, peerdist_range::end, free, intf_restart(), NULL, peerblk_dequeue(), peerdist_block::pos, peerdist_block::process, process_del(), peerdist_block::queue, peerdist_block::range, peerdist_block::raw, rc, peerdist_block::retrieval, peerdist_block::start, peerdist_range::start, stop_timer(), peerdist_block::timer, peerdist_block::trim, and xferbuf_free().

Referenced by peerblk_close(), peerblk_done(), and peerblk_expired().

◆ peerblk_close()

void peerblk_close ( struct peerdist_block * peerblk,
int rc )
static

Close PeerDist block download.

Parameters
peerblkPeerDist block download
rcReason for close

Definition at line 206 of file peerblk.c.

206 {
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}
static void profile_custom(struct profiler *profiler, unsigned long sample)
Record profiling sample in custom units.
Definition profile.h:201
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
static void peerblk_reset(struct peerdist_block *peerblk, int rc)
Reset PeerDist block download attempt.
Definition peerblk.c:168
static unsigned long peerblk_timestamp(void)
Get profiling timestamp.
Definition peerblk.c:139
void peerdisc_close(struct peerdisc_client *peerdisc)
Close PeerDist discovery client.
Definition peerdisc.c:618
unsigned long started
Time at which block download was started.
Definition peerblk.h:127
struct peerdisc_client discovery
Discovery client.
Definition peerblk.h:112
struct interface xfer
Data transfer interface.
Definition peerblk.h:51

References peerdist_block::discovery, intf_shutdown(), peerblk_reset(), peerblk_timestamp(), peerdisc_close(), profile_custom(), peerdist_block::raw, rc, peerdist_block::retrieval, peerdist_block::started, and peerdist_block::xfer.

Referenced by peerblk_done(), peerblk_expired(), peerblk_open(), and peerblk_step().

◆ peerblk_offset()

size_t peerblk_offset ( struct peerdist_block * peerblk,
size_t pos )
inlinestatic

Calculate offset within overall download.

Parameters
peerblkPeerDist block download
posPosition within incoming data stream
Return values
offsetOffset within overall download

Definition at line 233 of file peerblk.c.

233 {
234
235 return ( ( pos - peerblk->start ) + peerblk->offset );
236}
size_t offset
Offset of first byte in trimmed range within overall download.
Definition peerblk.h:64

References peerdist_block::offset, peerdist_block::pos, and peerdist_block::start.

Referenced by peerblk_deliver(), and peerblk_parse_block().

◆ peerblk_deliver()

int peerblk_deliver ( struct peerdist_block * peerblk,
struct io_buffer * iobuf,
struct xfer_metadata * meta,
size_t pos )
static

Deliver download attempt data block.

Parameters
peerblkPeerDist block download
iobufI/O buffer
metaOriginal data transfer metadata
posPosition within incoming data stream
Return values
rcReturn status code

Definition at line 247 of file peerblk.c.

249 {
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}
ring len
Length.
Definition dwmac.h:226
uint8_t meta
Metadata flags.
Definition ena.h:3
#define DBGC(...)
Definition compiler.h:530
uint32_t start
Starting offset.
Definition netvsc.h:1
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:277
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
#define iob_pull(iobuf, len)
Definition iobuf.h:167
#define iob_unput(iobuf, len)
Definition iobuf.h:200
uint32_t end
Ending offset.
Definition netvsc.h:7
static size_t peerblk_offset(struct peerdist_block *peerblk, size_t pos)
Calculate offset within overall download.
Definition peerblk.c:233
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
unsigned int segment
Segment index.
Definition peerblk.h:83
unsigned int block
Block index.
Definition peerblk.h:89
Data transfer metadata.
Definition xfer.h:23
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48

References peerdist_block::block, DBGC, end, peerdist_block::end, xfer_metadata::flags, free_iob(), iob_disown, iob_len(), iob_pull, iob_unput, len, memcpy(), meta, xfer_metadata::offset, peerblk_offset(), rc, peerdist_block::segment, peerdist_block::start, start, strerror(), peerdist_block::xfer, xfer_deliver(), and XFER_FL_ABS_OFFSET.

Referenced by peerblk_raw_rx(), and peerblk_retrieval_rx().

◆ peerblk_done()

void peerblk_done ( struct peerdist_block * peerblk,
int rc )
static

Finish PeerDist block download attempt.

Parameters
peerblkPeerDist block download
rcReason for close

Definition at line 298 of file peerblk.c.

298 {
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}
pseudo_bit_t hash[0x00010]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
#define DBGC_HDA(...)
Definition compiler.h:531
uint8_t head
Head number.
Definition int13.h:23
#define EIO
Input/output error.
Definition errno.h:477
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:305
uint16_t segment
Code segment.
Definition librm.h:3
#define list_entry(list, type, member)
Get the container of a list entry.
Definition list.h:322
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
static void peerblk_close(struct peerdist_block *peerblk, int rc)
Close PeerDist block download.
Definition peerblk.c:206
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Definition peerdisc.c:106
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A message digest algorithm.
Definition crypto.h:19
size_t digestsize
Digest size.
Definition crypto.h:27
struct peerdisc_segment * segment
Discovery segment.
Definition peerdisc.h:84
A PeerDist discovery peer.
Definition peerdisc.h:72
struct list_head list
List of peers.
Definition peerdisc.h:74
A PeerDist discovery segment.
Definition peerdisc.h:43
size_t digestsize
Digest size.
Definition peerblk.h:73
unsigned long attempted
Time at which most recent attempt was started.
Definition peerblk.h:129
uint8_t hash[PEERDIST_DIGEST_MAX_SIZE]
Block hash.
Definition peerblk.h:91
struct peerdisc_peer * peer
Current position in discovered peer list.
Definition peerblk.h:114
int rc
Most recent attempt failure.
Definition peerblk.h:124

References peerdist_block::attempted, peerdist_block::block, DBGC, DBGC_HDA, peerdist_block::digest, digest_final(), peerdist_block::digestctx, digest_algorithm::digestsize, peerdist_block::digestsize, peerdist_block::discovery, EIO, hash, peerdist_block::hash, head, peerdisc_peer::list, list_entry, memcmp(), NULL, peer, peerdist_block::peer, peerblk_close(), peerblk_reset(), peerblk_timestamp(), peerdisc_stat(), profile_custom(), peerdist_block::rc, rc, peerdisc_client::segment, peerdist_block::segment, segment, start_timer_nodelay(), strerror(), peerdist_block::timer, and peerdist_block::xfer.

Referenced by peerblk_decrypt(), peerblk_raw_close(), peerblk_raw_rx(), peerblk_retrieval_close(), and peerblk_retrieval_rx().

◆ peerblk_raw_open()

int peerblk_raw_open ( struct peerdist_block * peerblk)
static

Open PeerDist raw block download attempt.

Parameters
peerblkPeerDist block download
Return values
rcReturn status code

Definition at line 360 of file peerblk.c.

360 {
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}
#define PEERBLK_ANNUL_RATE
Definition fault.h:25
#define DBGC2(...)
Definition compiler.h:547
#define ETIMEDOUT
Connection timed out.
Definition errno.h:713
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:665
void * memset(void *dest, int character, size_t len) __nonnull
struct pci_range range
PCI bus:dev.fn address range.
Definition pcicloud.c:40
#define PEERBLK_RAW_OPEN_TIMEOUT
PeerDist raw block download attempt initial progress timeout.
Definition peerblk.c:76
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
HTTP request range descriptor.
Definition http.h:143

References peerdist_block::block, DBGC, DBGC2, peerdist_range::end, ETIMEDOUT, http_open(), intf_restart(), memset(), NULL, PEERBLK_ANNUL_RATE, PEERBLK_RAW_OPEN_TIMEOUT, peerdist_block::range, range, peerdist_block::raw, peerdist_block::rc, rc, peerdist_block::segment, peerdist_range::start, start_timer_fixed(), strerror(), peerdist_block::timer, and peerdist_block::uri.

◆ peerblk_raw_rx()

int peerblk_raw_rx ( struct peerdist_block * peerblk,
struct io_buffer * iobuf,
struct xfer_metadata * meta )
static

Receive PeerDist raw data.

Parameters
peerblkPeerDist block download
iobufI/O buffer
metaData transfer metadata
Return values
rcReturn status code

Definition at line 403 of file peerblk.c.

405 {
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}
#define PEERBLK_STALL_RATE
Definition fault.h:28
#define PEERBLK_CORRUPT_RATE
Definition fault.h:34
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Definition crypto.h:299
uint16_t mid
Middle 16 bits of address.
Definition librm.h:9
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_done(struct peerdist_block *peerblk, int rc)
Finish PeerDist block download attempt.
Definition peerblk.c:298
#define PEERBLK_RAW_RX_TIMEOUT
PeerDist raw block download attempt ongoing progress timeout.
Definition peerblk.c:82
void * data
Start of data.
Definition iobuf.h:113
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

References io_buffer::data, peerdist_block::digest, digest_update(), peerdist_block::digestctx, peerdist_range::end, free_iob(), intf_restart(), iob_disown, iob_len(), len, meta, mid, PEERBLK_CORRUPT_RATE, peerblk_deliver(), peerblk_done(), PEERBLK_RAW_RX_TIMEOUT, PEERBLK_STALL_RATE, peerdist_block::pos, peerdist_block::range, peerdist_block::raw, rc, peerdist_range::start, start_timer_fixed(), peerdist_block::timer, and xfer_check_order().

◆ peerblk_raw_close()

void peerblk_raw_close ( struct peerdist_block * peerblk,
int rc )
static

Close PeerDist raw block download attempt.

Parameters
peerblkPeerDist block download
rcReason for close

Definition at line 451 of file peerblk.c.

451 {
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}
struct bofm_section_header done
Definition bofm_test.c:46
#define PEERBLK_ABORT_RATE
Definition fault.h:31

References done, intf_restart(), PEERBLK_ABORT_RATE, peerblk_done(), peerdist_block::raw, and rc.

◆ peerblk_step()

void peerblk_step ( struct peerdist_block_queue * queue)
static

PeerDist block download queue process.

Parameters
queueBlock download queue

Definition at line 481 of file peerblk.c.

481 {
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}
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition list.h:334

References INIT_LIST_HEAD, list_del, list_first_entry, peerblk_close(), process_add(), queue, peerdist_block::queued, and rc.

◆ peerblk_enqueue()

void peerblk_enqueue ( struct peerdist_block * peerblk,
struct peerdist_block_queue * queue )
static

Add block to download queue.

Parameters
peerblkPeerDist block download
queueBlock download queue

Definition at line 518 of file peerblk.c.

519 {
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}
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition list.h:94

References assert, list_add_tail, list_empty, NULL, process_add(), peerdist_block::queue, queue, and peerdist_block::queued.

Referenced by peerblk_expired().

◆ peerblk_retrieval_open()

int peerblk_retrieval_open ( struct peerdist_block * peerblk,
struct peerdist_retrieval * retrieval,
const char * location )
static

Open PeerDist retrieval protocol block download attempt.

Parameters
peerblkPeerDist block download
retrievalRetrieval protocol
locationPeer location
Return values
rcReturn status code

Definition at line 587 of file peerblk.c.

589 {
590 size_t digestsize = peerblk->digestsize;
591 peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *rsp;
592 int rc;
593
594 DBGC2 ( peerblk, "PEERBLK %p %d.%d attempting %s retrieval from %s\n",
595 peerblk, peerblk->segment, peerblk->block, retrieval->name,
596 location );
597
598 /* Open connection */
599 if ( ( rc = retrieval->open ( &peerblk->retrieval, location,
600 digestsize, peerblk->id,
601 peerblk->block ) ) != 0 ) {
602 DBGC ( peerblk, "PEERBLK %p %d.%d could not create %s "
603 "retrieval request: %s\n", peerblk, peerblk->segment,
604 peerblk->block, retrieval->name, strerror ( rc ) );
605 return rc;
606 }
607
608 /* Update trim thresholds for retrieval protocol format */
609 peerblk->start += offsetof ( typeof ( *rsp ), msg.vrf );
610 peerblk->end += offsetof ( typeof ( *rsp ), msg.vrf );
611
612 /* Annul connection (for testing) if applicable. Do not
613 * report as an immediate error, in order to test our ability
614 * to recover from a totally unresponsive HTTP server.
615 */
616 if ( inject_fault ( PEERBLK_ANNUL_RATE ) )
617 intf_restart ( &peerblk->retrieval, 0 );
618
619 /* Start download attempt timer */
620 peerblk->rc = -ETIMEDOUT;
622
623 return 0;
624}
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
uint64_t rsp
Definition librm.h:18
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
uint32_t digestsize
Digest size (i.e.
Definition pccrr.h:1
#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT
PeerDist retrieval protocol block download attempt initial progress timeout.
Definition peerblk.c:88
#define peerblk_msg_blk_t(digestsize, len, vrf_len, blksize)
Retrieval protocol block fetch response (including transport header).
Definition peerblk.h:159
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
uint8_t id[PEERDIST_DIGEST_MAX_SIZE]
Segment identifier.
Definition peerblk.h:85
const char * name
Name.
Definition pccrr.h:358
int(* open)(struct interface *xfer, const char *location, size_t digestsize, const uint8_t *id, unsigned int block)
Open retrieval protocol connection.
Definition pccrr.h:369

References peerdist_block::block, DBGC, DBGC2, digestsize, peerdist_block::digestsize, peerdist_block::end, ETIMEDOUT, peerdist_block::id, intf_restart(), msg(), peerdist_retrieval::name, offsetof, peerdist_retrieval::open, PEERBLK_ANNUL_RATE, peerblk_msg_blk_t, PEERBLK_RETRIEVAL_OPEN_TIMEOUT, peerdist_block::rc, rc, peerdist_block::retrieval, rsp, peerdist_block::segment, peerdist_block::start, start_timer_fixed(), strerror(), peerdist_block::timer, and typeof().

Referenced by peerblk_expired().

◆ peerblk_retrieval_rx()

int peerblk_retrieval_rx ( struct peerdist_block * peerblk,
struct io_buffer * iobuf,
struct xfer_metadata * meta )
static

Receive PeerDist retrieval protocol data.

Parameters
peerblkPeerDist block download
iobufI/O buffer
metaData transfer metadata
Return values
rcReturn status code

Definition at line 634 of file peerblk.c.

636 {
637 size_t len = iob_len ( iobuf );
638 size_t start;
639 size_t end;
640 size_t before;
641 size_t after;
642 size_t cut;
643 int rc;
644
645 /* Some genius at Microsoft thought it would be a great idea
646 * to place the AES-CBC initialisation vector *after* the
647 * encrypted data, thereby making it logically impossible to
648 * decrypt each packet as it arrives.
649 *
650 * To work around this mindless stupidity, we deliver the
651 * ciphertext as-is and later use xfer_buffer() to obtain
652 * access to the underlying data transfer buffer in order to
653 * perform the decryption.
654 *
655 * There will be some data both before and after the bytes
656 * corresponding to the trimmed plaintext: a MSG_BLK
657 * header/footer, some block padding for the AES-CBC cipher,
658 * and a possibly large quantity of unwanted ciphertext which
659 * is excluded from the trimmed content range. We store this
660 * data in a local data transfer buffer. If the amount of
661 * data to be stored is too large, we will fail allocation and
662 * so eventually fall back to using a range request (which
663 * does not require this kind of temporary storage
664 * allocation).
665 */
666
667 /* Corrupt received data (for testing) if applicable */
668 inject_corruption ( PEERBLK_CORRUPT_RATE, iobuf->data, len );
669
670 /* Calculate start and end positions of this buffer */
671 start = peerblk->pos;
672 if ( meta->flags & XFER_FL_ABS_OFFSET )
673 start = 0;
674 start += meta->offset;
675 end = ( start + len );
676
677 /* Buffer any data before the trimmed content */
678 if ( ( start < peerblk->start ) && ( len > 0 ) ) {
679
680 /* Calculate length of data before the trimmed content */
681 before = ( peerblk->start - start );
682 if ( before > len )
683 before = len;
684
685 /* Buffer data before the trimmed content */
686 if ( ( rc = xferbuf_write ( &peerblk->buffer, start,
687 iobuf->data, before ) ) != 0 ) {
688 DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
689 "data: %s\n", peerblk, peerblk->segment,
690 peerblk->block, strerror ( rc ) );
691 goto err;
692 }
693 }
694
695 /* Buffer any data after the trimmed content */
696 if ( ( end > peerblk->end ) && ( len > 0 ) ) {
697
698 /* Calculate length of data after the trimmed content */
699 after = ( end - peerblk->end );
700 if ( after > len )
701 after = len;
702
703 /* Buffer data after the trimmed content */
704 cut = ( peerblk->end - peerblk->start );
705 if ( ( rc = xferbuf_write ( &peerblk->buffer,
706 ( end - after - cut ),
707 ( iobuf->data + len - after ),
708 after ) ) != 0 ) {
709 DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
710 "data: %s\n", peerblk, peerblk->segment,
711 peerblk->block, strerror ( rc ) );
712 goto err;
713 }
714 }
715
716 /* Deliver any remaining data */
717 if ( ( rc = peerblk_deliver ( peerblk, iob_disown ( iobuf ), meta,
718 start ) ) != 0 )
719 goto err;
720
721 /* Update position */
722 peerblk->pos = end;
723
724 /* Extend download attempt timer */
726
727 /* Stall download attempt (for testing) if applicable */
728 if ( ( start < peerblk->end ) && ( end >= peerblk->end ) &&
729 ( ( rc = inject_fault ( PEERBLK_STALL_RATE ) ) != 0 ) ) {
730 intf_restart ( &peerblk->retrieval, rc );
731 }
732
733 return 0;
734
735 err:
736 free_iob ( iobuf );
737 peerblk_done ( peerblk, rc );
738 return rc;
739}
#define PEERBLK_RETRIEVAL_RX_TIMEOUT
PeerDist retrieval protocol block download attempt ongoing progress timeout.
Definition peerblk.c:94
int32_t after
Final microcode version.
Definition ucode.h:7
int32_t before
Initial microcode version.
Definition ucode.h:5
int xferbuf_write(struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
Write to data transfer buffer.
Definition xferbuf.c:133

References after, before, peerdist_block::block, peerdist_block::buffer, io_buffer::data, DBGC, end, peerdist_block::end, free_iob(), intf_restart(), iob_disown, iob_len(), len, meta, PEERBLK_CORRUPT_RATE, peerblk_deliver(), peerblk_done(), PEERBLK_RETRIEVAL_RX_TIMEOUT, PEERBLK_STALL_RATE, peerdist_block::pos, rc, peerdist_block::retrieval, peerdist_block::segment, peerdist_block::start, start, start_timer_fixed(), strerror(), peerdist_block::timer, XFER_FL_ABS_OFFSET, and xferbuf_write().

◆ peerblk_parse_header()

int peerblk_parse_header ( struct peerdist_block * peerblk)
static

Parse retrieval protocol message header.

Parameters
peerblkPeerDist block download
Return values
rcReturn status code

Definition at line 747 of file peerblk.c.

747 {
748 struct {
751 } __attribute__ (( packed )) *msg = peerblk->buffer.data;
752 struct cipher_algorithm *cipher;
753 size_t len = peerblk->buffer.len;
754 size_t keylen = 0;
755 int rc;
756
757 /* Check message length */
758 if ( len < sizeof ( *msg ) ) {
759 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for header "
760 "(%zd bytes)\n", peerblk, peerblk->segment,
761 peerblk->block, len );
762 return -ERANGE;
763 }
764
765 /* Check message type */
766 if ( msg->msg.type != htonl ( PEERDIST_MSG_BLK_TYPE ) ) {
767 DBGC ( peerblk, "PEERBLK %p %d.%d unexpected message type "
768 "%#08x\n", peerblk, peerblk->segment, peerblk->block,
769 ntohl ( msg->msg.type ) );
770 return -EPROTO;
771 }
772
773 /* Determine cipher algorithm and key length */
774 cipher = &aes_cbc_algorithm;
775 switch ( msg->msg.algorithm ) {
777 cipher = NULL;
778 break;
780 keylen = ( 128 / 8 );
781 break;
783 keylen = ( 192 / 8 );
784 break;
786 keylen = ( 256 / 8 );
787 break;
788 default:
789 DBGC ( peerblk, "PEERBLK %p %d.%d unrecognised algorithm "
790 "%#08x\n", peerblk, peerblk->segment, peerblk->block,
791 ntohl ( msg->msg.algorithm ) );
792 return -ENOTSUP;
793 }
794 DBGC2 ( peerblk, "PEERBLK %p %d.%d using %s with %zd-bit key\n",
795 peerblk, peerblk->segment, peerblk->block,
796 ( cipher ? cipher->name : "plaintext" ), ( 8 * keylen ) );
797
798 /* Sanity check key length against maximum secret length */
799 if ( keylen > peerblk->digestsize ) {
800 DBGC ( peerblk, "PEERBLK %p %d.%d %zd-byte secret too short "
801 "for %zd-bit key\n", peerblk, peerblk->segment,
802 peerblk->block, peerblk->digestsize, ( 8 * keylen ) );
803 return -EPROTO;
804 }
805
806 /* Allocate cipher context, if applicable. Freeing the cipher
807 * context (on error or otherwise) is handled by peerblk_reset().
808 */
809 peerblk->cipher = cipher;
810 assert ( peerblk->cipherctx == NULL );
811 if ( cipher ) {
812 peerblk->cipherctx = malloc ( cipher->ctxsize );
813 if ( ! peerblk->cipherctx )
814 return -ENOMEM;
815 }
816
817 /* Initialise cipher, if applicable */
818 if ( cipher &&
819 ( rc = cipher_setkey ( cipher, peerblk->cipherctx, peerblk->secret,
820 keylen ) ) != 0 ) {
821 DBGC ( peerblk, "PEERBLK %p %d.%d could not set key: %s\n",
822 peerblk, peerblk->segment, peerblk->block,
823 strerror ( rc ) );
824 return rc;
825 }
826
827 return 0;
828}
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
#define EPROTO
Protocol error.
Definition errno.h:668
#define ENOMEM
Not enough space.
Definition errno.h:578
#define ENOTSUP
Operation not supported.
Definition errno.h:633
#define ERANGE
Result too large.
Definition errno.h:683
#define ntohl(value)
Definition byteswap.h:135
#define htonl(value)
Definition byteswap.h:134
#define __attribute__(x)
Definition compiler.h:10
struct cipher_algorithm aes_cbc_algorithm
static int cipher_setkey(struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen)
Definition crypto.h:310
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:677
#define PEERDIST_MSG_BLK_TYPE
Retrieval protocol block fetch response type.
Definition pccrr.h:353
@ PEERDIST_MSG_AES_192_CBC
AES-192 in CBC mode.
Definition pccrr.h:176
@ PEERDIST_MSG_AES_128_CBC
AES-128 in CBC mode.
Definition pccrr.h:174
@ PEERDIST_MSG_PLAINTEXT
No encryption.
Definition pccrr.h:172
@ PEERDIST_MSG_AES_256_CBC
AES-256 in CBC mode.
Definition pccrr.h:178
A cipher algorithm.
Definition crypto.h:58
const char * name
Algorithm name.
Definition crypto.h:60
size_t ctxsize
Context size.
Definition crypto.h:62
uint8_t secret[PEERDIST_DIGEST_MAX_SIZE]
Segment secret.
Definition peerblk.h:87
Retrieval protocol message header.
Definition pccrr.h:154
Retrieval protocol transport response header.
Definition pccrr.h:182
size_t len
Size of data.
Definition xferbuf.h:25
void * data
Data.
Definition xferbuf.h:23

References __attribute__, aes_cbc_algorithm, assert, peerdist_block::block, peerdist_block::buffer, peerdist_block::cipher, cipher_setkey(), peerdist_block::cipherctx, cipher_algorithm::ctxsize, xfer_buffer::data, DBGC, DBGC2, peerdist_block::digestsize, ENOMEM, ENOTSUP, EPROTO, ERANGE, hdr, htonl, len, xfer_buffer::len, malloc(), msg(), cipher_algorithm::name, ntohl, NULL, PEERDIST_MSG_AES_128_CBC, PEERDIST_MSG_AES_192_CBC, PEERDIST_MSG_AES_256_CBC, PEERDIST_MSG_BLK_TYPE, PEERDIST_MSG_PLAINTEXT, rc, peerdist_block::secret, peerdist_block::segment, and strerror().

Referenced by peerblk_retrieval_close().

◆ peerblk_parse_block()

int peerblk_parse_block ( struct peerdist_block * peerblk,
size_t * buf_len )
static

Parse retrieval protocol message segment and block details.

Parameters
peerblkPeerDist block download
buf_lenLength of buffered data to fill in
Return values
rcReturn status code

Definition at line 837 of file peerblk.c.

838 {
839 size_t digestsize = peerblk->digestsize;
840 peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *msg = peerblk->buffer.data;
841 size_t len = peerblk->buffer.len;
842 size_t data_len;
843 size_t total;
844
845 /* Check message length */
846 if ( len < offsetof ( typeof ( *msg ), msg.block.data ) ) {
847 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
848 "zero-length data (%zd bytes)\n", peerblk,
849 peerblk->segment, peerblk->block, len );
850 return -ERANGE;
851 }
852
853 /* Check digest size */
854 if ( ntohl ( msg->msg.segment.segment.digestsize ) != digestsize ) {
855 DBGC ( peerblk, "PEERBLK %p %d.%d incorrect digest size %d\n",
856 peerblk, peerblk->segment, peerblk->block,
857 ntohl ( msg->msg.segment.segment.digestsize ) );
858 return -EPROTO;
859 }
860
861 /* Check segment ID */
862 if ( memcmp ( msg->msg.segment.id, peerblk->id, digestsize ) != 0 ) {
863 DBGC ( peerblk, "PEERBLK %p %d.%d segment ID mismatch\n",
864 peerblk, peerblk->segment, peerblk->block );
865 return -EPROTO;
866 }
867
868 /* Check block ID */
869 if ( ntohl ( msg->msg.index ) != peerblk->block ) {
870 DBGC ( peerblk, "PEERBLK %p %d.%d block ID mismatch (got %d)\n",
871 peerblk, peerblk->segment, peerblk->block,
872 ntohl ( msg->msg.index ) );
873 return -EPROTO;
874 }
875
876 /* Check for missing blocks */
877 data_len = be32_to_cpu ( msg->msg.block.block.len );
878 if ( ! data_len ) {
879 DBGC ( peerblk, "PEERBLK %p %d.%d block not found\n",
880 peerblk, peerblk->segment, peerblk->block );
881 return -ENOENT;
882 }
883
884 /* Check for underlength blocks */
885 if ( data_len < ( peerblk->range.end - peerblk->range.start ) ) {
886 DBGC ( peerblk, "PEERBLK %p %d.%d underlength block (%zd "
887 "bytes)\n", peerblk, peerblk->segment, peerblk->block,
888 data_len );
889 return -ERANGE;
890 }
891
892 /* Calculate buffered data length (i.e. excluding data which
893 * was delivered to the final data transfer buffer).
894 */
895 *buf_len = ( data_len - ( peerblk->end - peerblk->start ) );
896
897 /* Describe data before the trimmed content */
898 peerblk->decrypt[PEERBLK_BEFORE].xferbuf = &peerblk->buffer;
899 peerblk->decrypt[PEERBLK_BEFORE].offset =
900 offsetof ( typeof ( *msg ), msg.block.data );
901 peerblk->decrypt[PEERBLK_BEFORE].len =
902 ( peerblk->start -
903 offsetof ( typeof ( *msg ), msg.block.data ) );
904 total = peerblk->decrypt[PEERBLK_BEFORE].len;
905
906 /* Describe data within the trimmed content */
907 peerblk->decrypt[PEERBLK_DURING].offset =
908 peerblk_offset ( peerblk, peerblk->start );
909 peerblk->decrypt[PEERBLK_DURING].len =
910 ( peerblk->end - peerblk->start );
911 total += peerblk->decrypt[PEERBLK_DURING].len;
912
913 /* Describe data after the trimmed content */
914 peerblk->decrypt[PEERBLK_AFTER].xferbuf = &peerblk->buffer;
915 peerblk->decrypt[PEERBLK_AFTER].offset = peerblk->start;
916 peerblk->decrypt[PEERBLK_AFTER].len =
917 ( offsetof ( typeof ( *msg ), msg.block.data )
918 + *buf_len - peerblk->start );
919 total += peerblk->decrypt[PEERBLK_AFTER].len;
920
921 /* Sanity check */
922 assert ( total == be32_to_cpu ( msg->msg.block.block.len ) );
923
924 /* Initialise cipher and digest lengths */
925 peerblk->cipher_remaining = total;
926 peerblk->digest_remaining =
927 ( peerblk->range.end - peerblk->range.start );
928 assert ( peerblk->cipher_remaining >= peerblk->digest_remaining );
929
930 return 0;
931}
#define ENOENT
No such file or directory.
Definition errno.h:558
#define be32_to_cpu(value)
Definition byteswap.h:117
@ 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
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
struct peerdist_block_decrypt decrypt[PEERBLK_NUM_BUFFERS]
Decryption data buffer descriptors.
Definition peerblk.h:105
size_t cipher_remaining
Remaining decryption length.
Definition peerblk.h:107
size_t digest_remaining
Remaining digest length (excluding AES padding bytes).
Definition peerblk.h:109
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes).
Definition ucode.h:15

References assert, be32_to_cpu, peerdist_block::block, peerdist_block::buffer, peerdist_block::cipher_remaining, xfer_buffer::data, data_len, DBGC, peerdist_block::decrypt, peerdist_block::digest_remaining, digestsize, peerdist_block::digestsize, peerdist_block::end, peerdist_range::end, ENOENT, EPROTO, ERANGE, peerdist_block::id, len, peerdist_block_decrypt::len, xfer_buffer::len, memcmp(), msg(), ntohl, peerdist_block_decrypt::offset, offsetof, PEERBLK_AFTER, PEERBLK_BEFORE, PEERBLK_DURING, peerblk_msg_blk_t, peerblk_offset(), peerdist_block::range, peerdist_block::segment, peerdist_block::start, peerdist_range::start, typeof(), and peerdist_block_decrypt::xferbuf.

Referenced by peerblk_retrieval_close().

◆ peerblk_parse_useless()

int peerblk_parse_useless ( struct peerdist_block * peerblk,
size_t buf_len,
size_t * vrf_len )
static

Parse retrieval protocol message useless details.

Parameters
peerblkPeerDist block download
buf_lenLength of buffered data
vrf_lenLength of uselessness to fill in
Return values
rcReturn status code

Definition at line 941 of file peerblk.c.

942 {
943 size_t digestsize = peerblk->digestsize;
944 peerblk_msg_blk_t ( digestsize, buf_len, 0, 0 ) *msg =
945 peerblk->buffer.data;
946 size_t len = peerblk->buffer.len;
947
948 /* Check message length */
949 if ( len < offsetof ( typeof ( *msg ), msg.vrf.data ) ) {
950 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
951 "zero-length uselessness (%zd bytes)\n", peerblk,
952 peerblk->segment, peerblk->block, len );
953 return -ERANGE;
954 }
955
956 /* Extract length of uselessness */
957 *vrf_len = be32_to_cpu ( msg->msg.vrf.vrf.len );
958
959 return 0;
960}

References be32_to_cpu, peerdist_block::block, peerdist_block::buffer, xfer_buffer::data, DBGC, digestsize, peerdist_block::digestsize, ERANGE, len, xfer_buffer::len, msg(), offsetof, peerblk_msg_blk_t, peerdist_block::segment, and typeof().

Referenced by peerblk_retrieval_close().

◆ peerblk_parse_iv()

int peerblk_parse_iv ( struct peerdist_block * peerblk,
size_t buf_len,
size_t vrf_len )
static

Parse retrieval protocol message initialisation vector details.

Parameters
peerblkPeerDist block download
buf_lenLength of buffered data
vrf_lenLength of uselessness
Return values
rcReturn status code

Definition at line 970 of file peerblk.c.

971 {
972 size_t digestsize = peerblk->digestsize;
973 size_t blksize = peerblk->cipher->blocksize;
974 peerblk_msg_blk_t ( digestsize, buf_len, vrf_len, blksize ) *msg =
975 peerblk->buffer.data;
976 size_t len = peerblk->buffer.len;
977 size_t ivlen;
978 int rc;
979
980 /* Check message length */
981 if ( len < sizeof ( *msg ) ) {
982 DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
983 "initialisation vector (%zd bytes)\n", peerblk,
984 peerblk->segment, peerblk->block, len );
985 return -ERANGE;
986 }
987 ivlen = ntohl ( msg->msg.iv.iv.blksize );
988
989 /* Set initialisation vector */
990 if ( ( rc = cipher_setiv ( peerblk->cipher, peerblk->cipherctx,
991 msg->msg.iv.data, ivlen ) ) != 0 ) {
992 DBGC ( peerblk, "PEERBLK %p %d.%d could not set IV: %s\n",
993 peerblk, peerblk->segment, peerblk->block,
994 strerror ( rc ) );
995 return rc;
996 }
997
998 return 0;
999}
static int cipher_setiv(struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen)
Definition crypto.h:316
uint32_t blksize
Cipher block size.
Definition pccrr.h:1
size_t blocksize
Block size.
Definition crypto.h:68

References blksize, peerdist_block::block, cipher_algorithm::blocksize, peerdist_block::buffer, peerdist_block::cipher, cipher_setiv(), peerdist_block::cipherctx, xfer_buffer::data, DBGC, digestsize, peerdist_block::digestsize, ERANGE, len, xfer_buffer::len, msg(), ntohl, peerblk_msg_blk_t, rc, peerdist_block::segment, and strerror().

Referenced by peerblk_retrieval_close().

◆ peerblk_decrypt_read()

int peerblk_decrypt_read ( struct peerdist_block * peerblk,
void * data,
size_t len )
static

Read from decryption buffers.

Parameters
peerblkPeerDist block download
dataData buffer
lenLength to read
Return values
rcReturn status code

Definition at line 1009 of file peerblk.c.

1010 {
1011 struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
1012 size_t frag_len;
1013 int rc;
1014
1015 /* Read from each decryption buffer in turn */
1016 for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
1017
1018 /* Calculate length to use from this buffer */
1019 frag_len = decrypt->len;
1020 if ( frag_len > len )
1021 frag_len = len;
1022 if ( ! frag_len )
1023 continue;
1024
1025 /* Read from this buffer */
1026 if ( ( rc = xferbuf_read ( decrypt->xferbuf, decrypt->offset,
1027 data, frag_len ) ) != 0 )
1028 return rc;
1029 }
1030
1031 return 0;
1032}
uint8_t data[48]
Additional event data.
Definition ena.h:11
A PeerDist retrieval protocol decryption buffer descriptor.
Definition peerblk.h:25
int xferbuf_read(struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len)
Read from data transfer buffer.
Definition xferbuf.c:166

References data, peerdist_block::decrypt, len, peerdist_block_decrypt::len, peerdist_block_decrypt::offset, rc, peerdist_block_decrypt::xferbuf, and xferbuf_read().

Referenced by peerblk_decrypt().

◆ peerblk_decrypt_write()

int peerblk_decrypt_write ( struct peerdist_block * peerblk,
const void * data,
size_t len )
static

Write to decryption buffers and update offsets and lengths.

Parameters
peerblkPeerDist block download
dataData buffer
lenLength to read
Return values
rcReturn status code

Definition at line 1042 of file peerblk.c.

1043 {
1044 struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
1045 size_t frag_len;
1046 int rc;
1047
1048 /* Write to each decryption buffer in turn */
1049 for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
1050
1051 /* Calculate length to use from this buffer */
1052 frag_len = decrypt->len;
1053 if ( frag_len > len )
1054 frag_len = len;
1055 if ( ! frag_len )
1056 continue;
1057
1058 /* Write to this buffer */
1059 if ( ( rc = xferbuf_write ( decrypt->xferbuf, decrypt->offset,
1060 data, frag_len ) ) != 0 )
1061 return rc;
1062
1063 /* Update offset and length */
1064 decrypt->offset += frag_len;
1065 decrypt->len -= frag_len;
1066 }
1067
1068 return 0;
1069}

References data, peerdist_block::decrypt, len, peerdist_block_decrypt::len, peerdist_block_decrypt::offset, rc, peerdist_block_decrypt::xferbuf, and xferbuf_write().

Referenced by peerblk_decrypt().

◆ peerblk_decrypt()

void peerblk_decrypt ( struct peerdist_block * peerblk)
static

Decrypt one chunk of PeerDist retrieval protocol data.

Parameters
peerblkPeerDist block download

Definition at line 1076 of file peerblk.c.

1076 {
1077 struct cipher_algorithm *cipher = peerblk->cipher;
1078 struct digest_algorithm *digest = peerblk->digest;
1079 struct xfer_buffer *xferbuf;
1080 size_t cipher_len;
1081 size_t digest_len;
1082 void *data;
1083 int rc;
1084
1085 /* Sanity checks */
1086 assert ( ( PEERBLK_DECRYPT_CHUNKSIZE % cipher->blocksize ) == 0 );
1087 if ( peerblk->cipher_remaining & ( cipher->blocksize - 1 ) ) {
1088 DBGC ( peerblk, "PEERBLK %p %d.%d has invalid length %zd\n",
1089 peerblk, peerblk->segment, peerblk->block,
1090 peerblk->cipher_remaining );
1091 rc = -EINVAL;
1092 goto err_blocksize;
1093 }
1094
1095 /* Get the underlying data transfer buffer */
1096 xferbuf = xfer_buffer ( &peerblk->xfer );
1097 if ( ! xferbuf ) {
1098 DBGC ( peerblk, "PEERBLK %p %d.%d has no underlying data "
1099 "transfer buffer\n", peerblk, peerblk->segment,
1100 peerblk->block );
1101 rc = -ENOTSUP;
1102 goto err_xfer_buffer;
1103 }
1104 peerblk->decrypt[PEERBLK_DURING].xferbuf = xferbuf;
1105
1106 /* Calculate cipher and digest lengths */
1107 cipher_len = PEERBLK_DECRYPT_CHUNKSIZE;
1108 if ( cipher_len > peerblk->cipher_remaining )
1109 cipher_len = peerblk->cipher_remaining;
1110 digest_len = cipher_len;
1111 if ( digest_len > peerblk->digest_remaining )
1112 digest_len = peerblk->digest_remaining;
1113 assert ( ( cipher_len & ( cipher->blocksize - 1 ) ) == 0 );
1114
1115 /* Allocate temporary data buffer */
1116 data = malloc ( cipher_len );
1117 if ( ! data ) {
1118 rc = -ENOMEM;
1119 goto err_alloc_data;
1120 }
1121
1122 /* Read ciphertext */
1123 if ( ( rc = peerblk_decrypt_read ( peerblk, data, cipher_len ) ) != 0 ){
1124 DBGC ( peerblk, "PEERBLK %p %d.%d could not read ciphertext: "
1125 "%s\n", peerblk, peerblk->segment, peerblk->block,
1126 strerror ( rc ) );
1127 goto err_read;
1128 }
1129
1130 /* Decrypt data */
1131 cipher_decrypt ( cipher, peerblk->cipherctx, data, data, cipher_len );
1132
1133 /* Add data to digest */
1134 digest_update ( digest, peerblk->digestctx, data, digest_len );
1135
1136 /* Write plaintext */
1137 if ( ( rc = peerblk_decrypt_write ( peerblk, data, cipher_len ) ) != 0){
1138 DBGC ( peerblk, "PEERBLK %p %d.%d could not write plaintext: "
1139 "%s\n", peerblk, peerblk->segment, peerblk->block,
1140 strerror ( rc ) );
1141 goto err_write;
1142 }
1143
1144 /* Consume input */
1145 peerblk->cipher_remaining -= cipher_len;
1146 peerblk->digest_remaining -= digest_len;
1147
1148 /* Free temporary data buffer */
1149 free ( data );
1150
1151 /* Continue processing until all input is consumed */
1152 if ( peerblk->cipher_remaining )
1153 return;
1154
1155 /* Complete download attempt */
1156 peerblk_done ( peerblk, 0 );
1157 return;
1158
1159 err_write:
1160 err_read:
1161 free ( data );
1162 err_alloc_data:
1163 err_xfer_buffer:
1164 err_blocksize:
1165 peerblk_done ( peerblk, rc );
1166}
#define EINVAL
Invalid argument.
Definition errno.h:472
#define cipher_decrypt(cipher, ctx, src, dst, len)
Definition crypto.h:336
static int peerblk_decrypt_read(struct peerdist_block *peerblk, void *data, size_t len)
Read from decryption buffers.
Definition peerblk.c:1009
#define PEERBLK_DECRYPT_CHUNKSIZE
PeerDist decryption chunksize.
Definition peerblk.c:51
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:1042
A data transfer buffer.
Definition xferbuf.h:21
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
Definition xferbuf.c:380

References assert, peerdist_block::block, cipher_algorithm::blocksize, peerdist_block::cipher, cipher_decrypt, peerdist_block::cipher_remaining, peerdist_block::cipherctx, data, DBGC, peerdist_block::decrypt, peerdist_block::digest, peerdist_block::digest_remaining, digest_update(), peerdist_block::digestctx, EINVAL, ENOMEM, ENOTSUP, free, malloc(), PEERBLK_DECRYPT_CHUNKSIZE, peerblk_decrypt_read(), peerblk_decrypt_write(), peerblk_done(), PEERBLK_DURING, rc, peerdist_block::segment, strerror(), peerdist_block::xfer, xfer_buffer(), and peerdist_block_decrypt::xferbuf.

◆ peerblk_retrieval_close()

void peerblk_retrieval_close ( struct peerdist_block * peerblk,
int rc )
static

Close PeerDist retrieval protocol block download attempt.

Parameters
peerblkPeerDist block download
rcReason for close

Definition at line 1174 of file peerblk.c.

1174 {
1175 size_t buf_len;
1176 size_t vrf_len;
1177
1178 /* Restart interface */
1179 intf_restart ( &peerblk->retrieval, rc );
1180
1181 /* Fail immediately if we have an error */
1182 if ( rc != 0 )
1183 goto done;
1184
1185 /* Abort download attempt (for testing) if applicable */
1186 if ( ( rc = inject_fault ( PEERBLK_ABORT_RATE ) ) != 0 )
1187 goto done;
1188
1189 /* Parse message header */
1190 if ( ( rc = peerblk_parse_header ( peerblk ) ) != 0 )
1191 goto done;
1192
1193 /* Parse message segment and block details */
1194 if ( ( rc = peerblk_parse_block ( peerblk, &buf_len ) ) != 0 )
1195 goto done;
1196
1197 /* If the block was plaintext, then there is nothing more to do */
1198 if ( ! peerblk->cipher )
1199 goto done;
1200
1201 /* Parse message useless details */
1202 if ( ( rc = peerblk_parse_useless ( peerblk, buf_len, &vrf_len ) ) != 0)
1203 goto done;
1204
1205 /* Parse message initialisation vector details */
1206 if ( ( rc = peerblk_parse_iv ( peerblk, buf_len, vrf_len ) ) != 0 )
1207 goto done;
1208
1209 /* Fail if decryption length is not aligned to the cipher block size */
1210 if ( peerblk->cipher_remaining & ( peerblk->cipher->blocksize - 1 ) ) {
1211 DBGC ( peerblk, "PEERBLK %p %d.%d unaligned data length %zd\n",
1212 peerblk, peerblk->segment, peerblk->block,
1213 peerblk->cipher_remaining );
1214 rc = -EPROTO;
1215 goto done;
1216 }
1217
1218 /* Stop the download attempt timer: there is no point in
1219 * timing out while decrypting.
1220 */
1221 stop_timer ( &peerblk->timer );
1222
1223 /* Start decryption process */
1224 process_add ( &peerblk->process );
1225 return;
1226
1227 done:
1228 /* Complete download attempt */
1229 peerblk_done ( peerblk, rc );
1230}
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:941
static int peerblk_parse_block(struct peerdist_block *peerblk, size_t *buf_len)
Parse retrieval protocol message segment and block details.
Definition peerblk.c:837
static int peerblk_parse_header(struct peerdist_block *peerblk)
Parse retrieval protocol message header.
Definition peerblk.c:747
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:970

References peerdist_block::block, cipher_algorithm::blocksize, peerdist_block::cipher, peerdist_block::cipher_remaining, DBGC, done, EPROTO, intf_restart(), PEERBLK_ABORT_RATE, peerblk_done(), peerblk_parse_block(), peerblk_parse_header(), peerblk_parse_iv(), peerblk_parse_useless(), peerdist_block::process, process_add(), rc, peerdist_block::retrieval, peerdist_block::segment, stop_timer(), and peerdist_block::timer.

◆ peerblk_expired()

void peerblk_expired ( struct retry_timer * timer,
int over __unused )
static

Handle PeerDist retry timer expiry.

Parameters
timerRetry timer
overFailure indicator

Definition at line 1245 of file peerblk.c.

1245 {
1246 struct peerdist_block *peerblk =
1248 struct peerdisc_segment *segment = peerblk->discovery.segment;
1249 struct peerdisc_peer *head;
1250 unsigned long now = peerblk_timestamp();
1251 struct peerdist_retrieval *retrieval;
1252 const char *location;
1253 int rc;
1254
1255 /* Profile discovery timeout, if applicable */
1256 if ( ( peerblk->peer == NULL ) && ( timer->timeout != 0 ) ) {
1257 profile_custom ( &peerblk_discovery_timeout_profiler,
1258 ( now - peerblk->started ) );
1259 DBGC ( peerblk, "PEERBLK %p %d.%d discovery timed out after "
1260 "%ld ticks\n", peerblk, peerblk->segment,
1261 peerblk->block, timer->timeout );
1262 }
1263
1264 /* Profile download timeout, if applicable */
1265 if ( ( peerblk->peer != NULL ) && ( timer->timeout != 0 ) ) {
1266 profile_custom ( &peerblk_attempt_timeout_profiler,
1267 ( now - peerblk->attempted ) );
1268 DBGC ( peerblk, "PEERBLK %p %d.%d timed out after %ld ticks\n",
1269 peerblk, peerblk->segment, peerblk->block,
1270 timer->timeout );
1271 }
1272
1273 /* Abort any current download attempt */
1274 peerblk_reset ( peerblk, -ETIMEDOUT );
1275
1276 /* Record attempt start time */
1277 peerblk->attempted = now;
1278
1279 /* If we have exceeded our maximum number of attempt cycles
1280 * (each cycle comprising a retrieval protocol download from
1281 * each peer in the list followed by a raw download from the
1282 * origin server), then abort the overall download.
1283 */
1284 head = list_entry ( &segment->peers, struct peerdisc_peer, list );
1285 if ( ( peerblk->peer == head ) &&
1286 ( ++peerblk->cycles >= PEERBLK_MAX_ATTEMPT_CYCLES ) ) {
1287 rc = peerblk->rc;
1288 assert ( rc != 0 );
1289 goto err;
1290 }
1291
1292 /* If we have not yet made any download attempts, then move to
1293 * the start of the peer list.
1294 */
1295 if ( peerblk->peer == NULL )
1296 peerblk->peer = head;
1297
1298 /* Attempt retrieval protocol download from next usable peer */
1299 list_for_each_entry_continue ( peerblk->peer, &segment->peers, list ) {
1300
1301 /* Attempt retrieval protocol download from this peer */
1302 retrieval = peerblk->peer->retrieval;
1303 location = peerblk->peer->location;
1304 if ( ( rc = peerblk_retrieval_open ( peerblk, retrieval,
1305 location ) ) != 0 ) {
1306 /* Non-fatal: continue to try next peer */
1307 continue;
1308 }
1309
1310 /* Peer download started */
1311 return;
1312 }
1313
1314 /* Add to raw download queue */
1315 peerblk_enqueue ( peerblk, &peerblk_raw_queue );
1316
1317 return;
1318
1319 err:
1320 peerblk_close ( peerblk, rc );
1321}
#define list_for_each_entry_continue(pos, head, member)
Iterate over entries in a list, starting after current position.
Definition list.h:474
static void peerblk_enqueue(struct peerdist_block *peerblk, struct peerdist_block_queue *queue)
Add block to download queue.
Definition peerblk.c:518
static int peerblk_retrieval_open(struct peerdist_block *peerblk, struct peerdist_retrieval *retrieval, const char *location)
Open PeerDist retrieval protocol block download attempt.
Definition peerblk.c:587
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
struct peerdist_retrieval * retrieval
Retrieval protocol.
Definition peerdisc.h:76
char location[0]
Peer location.
Definition peerdisc.h:78
unsigned int cycles
Number of full attempt cycles completed.
Definition peerblk.h:122
A retrieval protocol mechanism.
Definition pccrr.h:356
A timer.
Definition timer.h:29

References __unused, assert, peerdist_block::attempted, peerdist_block::block, container_of, peerdist_block::cycles, DBGC, peerdist_block::discovery, ETIMEDOUT, head, list_entry, list_for_each_entry_continue, peerdisc_peer::location, NULL, peerdist_block::peer, peerblk_close(), peerblk_enqueue(), PEERBLK_MAX_ATTEMPT_CYCLES, peerblk_raw_queue, peerblk_reset(), peerblk_retrieval_open(), peerblk_timestamp(), profile_custom(), peerdist_block::rc, rc, peerdisc_peer::retrieval, peerdisc_client::segment, peerdist_block::segment, segment, and peerdist_block::started.

Referenced by peerblk_open().

◆ peerblk_discovered()

void peerblk_discovered ( struct peerdisc_client * discovery)
static

Handle PeerDist peer discovery.

Parameters
discoveryPeerDist discovery client

Definition at line 1328 of file peerblk.c.

1328 {
1329 struct peerdist_block *peerblk =
1331 unsigned long now = peerblk_timestamp();
1332
1333 /* Do nothing unless we are still waiting for the initial
1334 * discovery timeout.
1335 */
1336 if ( ( peerblk->peer != NULL ) || ( peerblk->timer.timeout == 0 ) )
1337 return;
1338
1339 /* Schedule an immediate retry */
1340 start_timer_nodelay ( &peerblk->timer );
1341
1342 /* Profile discovery success */
1343 profile_custom ( &peerblk_discovery_success_profiler,
1344 ( now - peerblk->started ) );
1345}
unsigned long timeout
Timeout value (in ticks).
Definition retry.h:28

References container_of, peerdist_block::discovery, NULL, peerdist_block::peer, peerblk_timestamp(), profile_custom(), start_timer_nodelay(), peerdist_block::started, retry_timer::timeout, and peerdist_block::timer.

◆ peerblk_open()

int peerblk_open ( struct interface * xfer,
struct uri * uri,
struct peerdist_info_block * block )

Open PeerDist block download.

Parameters
xferData transfer interface
uriOriginal URI
infoContent information block
Return values
rcReturn status code

Definition at line 1401 of file peerblk.c.

1402 {
1403 const struct peerdist_info_segment *segment = block->segment;
1404 const struct peerdist_info *info = segment->info;
1405 struct digest_algorithm *digest = info->digest;
1406 struct peerdist_block *peerblk;
1407 unsigned long timeout;
1408 size_t digestsize;
1409 int rc;
1410
1411 /* Allocate and initialise structure */
1412 peerblk = zalloc ( sizeof ( *peerblk ) + digest->ctxsize );
1413 if ( ! peerblk ) {
1414 rc = -ENOMEM;
1415 goto err_alloc;
1416 }
1417 ref_init ( &peerblk->refcnt, peerblk_free );
1418 intf_init ( &peerblk->xfer, &peerblk_xfer_desc, &peerblk->refcnt );
1419 intf_init ( &peerblk->raw, &peerblk_raw_desc, &peerblk->refcnt );
1421 &peerblk->refcnt );
1422 peerblk->uri = uri_get ( uri );
1423 memcpy ( &peerblk->range, &block->range, sizeof ( peerblk->range ) );
1424 memcpy ( &peerblk->trim, &block->trim, sizeof ( peerblk->trim ) );
1425 peerblk->offset = ( block->trim.start - info->trim.start );
1426 peerblk->digest = info->digest;
1427 peerblk->digestsize = digestsize = info->digestsize;
1428 peerblk->digestctx = ( ( ( void * ) peerblk ) + sizeof ( *peerblk ) );
1429 peerblk->segment = segment->index;
1430 memcpy ( peerblk->id, segment->id, sizeof ( peerblk->id ) );
1431 memcpy ( peerblk->secret, segment->secret, sizeof ( peerblk->secret ) );
1432 peerblk->block = block->index;
1433 memcpy ( peerblk->hash, block->hash, sizeof ( peerblk->hash ) );
1434 xferbuf_malloc_init ( &peerblk->buffer );
1436 &peerblk->refcnt );
1438 INIT_LIST_HEAD ( &peerblk->queued );
1439 timer_init ( &peerblk->timer, peerblk_expired, &peerblk->refcnt );
1440 DBGC2 ( peerblk, "PEERBLK %p %d.%d id %02x%02x%02x%02x%02x..."
1441 "%02x%02x%02x [%08zx,%08zx)", peerblk, peerblk->segment,
1442 peerblk->block, peerblk->id[0], peerblk->id[1], peerblk->id[2],
1443 peerblk->id[3], peerblk->id[4], peerblk->id[ digestsize - 3 ],
1444 peerblk->id[ digestsize - 2 ], peerblk->id[ digestsize - 1 ],
1445 peerblk->range.start, peerblk->range.end );
1446 if ( ( peerblk->trim.start != peerblk->range.start ) ||
1447 ( peerblk->trim.end != peerblk->range.end ) ) {
1448 DBGC2 ( peerblk, " covers [%08zx,%08zx)",
1449 peerblk->trim.start, peerblk->trim.end );
1450 }
1451 DBGC2 ( peerblk, "\n" );
1452
1453 /* Open discovery */
1454 if ( ( rc = peerdisc_open ( &peerblk->discovery, peerblk->id,
1455 peerblk->digestsize ) ) != 0 )
1456 goto err_open_discovery;
1457
1458 /* Schedule a retry attempt either immediately (if we already
1459 * have some peers) or after the discovery timeout.
1460 */
1461 timeout = ( list_empty ( &peerblk->discovery.segment->peers ) ?
1463 start_timer_fixed ( &peerblk->timer, timeout );
1464
1465 /* Record start time */
1466 peerblk->started = peerblk_timestamp();
1467
1468 /* Attach to parent interface, mortalise self, and return */
1469 intf_plug_plug ( xfer, &peerblk->xfer );
1470 ref_put ( &peerblk->refcnt );
1471 return 0;
1472
1473 err_open_discovery:
1474 peerblk_close ( peerblk, rc );
1475 err_alloc:
1476 return rc;
1477}
u32 info
Definition ar9003_mac.h:0
void timeout(int)
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:718
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
static struct peerdisc_client_operations peerblk_discovery_operations
PeerDist block download discovery operations.
Definition peerblk.c:1389
static struct interface_descriptor peerblk_xfer_desc
PeerDist block download data transfer interface descriptor.
Definition peerblk.c:1360
static struct process_descriptor peerblk_process_desc
PeerDist block download decryption process descriptor.
Definition peerblk.c:1385
static struct interface_descriptor peerblk_retrieval_desc
PeerDist block download retrieval protocol interface descriptor.
Definition peerblk.c:1380
static struct interface_descriptor peerblk_raw_desc
PeerDist block download raw data interface descriptor.
Definition peerblk.c:1370
static void peerblk_expired(struct retry_timer *timer, int over __unused)
Handle PeerDist retry timer expiry.
Definition peerblk.c:1245
static void peerblk_free(struct refcnt *refcnt)
Free PeerDist block download.
Definition peerblk.c:153
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
Definition peerdisc.c:580
unsigned int peerdisc_timeout_secs
Recommended discovery timeout (in seconds).
Definition peerdisc.c:76
static void peerdisc_init(struct peerdisc_client *peerdisc, struct peerdisc_client_operations *op)
Initialise PeerDist discovery.
Definition peerdisc.h:107
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 ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
size_t ctxsize
Context size.
Definition crypto.h:23
struct list_head peers
List of discovered peers.
Definition peerdisc.h:64
struct refcnt refcnt
Reference count.
Definition peerblk.h:49
A content information segment.
Definition pccrc.h:347
Content information.
Definition pccrc.h:317
A Uniform Resource Identifier.
Definition uri.h:65
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition uri.h:195
static void xferbuf_malloc_init(struct xfer_buffer *xferbuf)
Initialise malloc()-based data transfer buffer.
Definition xferbuf.h:66

References block, peerdist_block::block, peerdist_block::buffer, digest_algorithm::ctxsize, DBGC2, peerdist_block::digest, peerdist_block::digestctx, digestsize, peerdist_block::digestsize, peerdist_block::discovery, peerdist_range::end, ENOMEM, peerdist_block::hash, peerdist_block::id, info, INIT_LIST_HEAD, intf_init(), intf_plug_plug(), list_empty, memcpy(), peerdist_block::offset, peerblk_close(), peerblk_discovery_operations, peerblk_expired(), peerblk_free(), peerblk_process_desc, peerblk_raw_desc, peerblk_retrieval_desc, peerblk_timestamp(), peerblk_xfer_desc, peerdisc_init(), peerdisc_open(), peerdisc_timeout_secs, peerdisc_segment::peers, peerdist_block::process, process_init_stopped(), peerdist_block::queued, peerdist_block::range, peerdist_block::raw, rc, ref_init, ref_put, peerdist_block::refcnt, peerdist_block::retrieval, peerdist_block::secret, peerdisc_client::segment, peerdist_block::segment, segment, peerdist_range::start, start_timer_fixed(), peerdist_block::started, TICKS_PER_SEC, timeout(), peerdist_block::timer, peerdist_block::trim, peerdist_block::uri, uri_get(), peerdist_block::xfer, xferbuf_malloc_init(), and zalloc().

Referenced by peermux_step().

Variable Documentation

◆ __profiler

struct profiler peerblk_discovery_timeout_profiler __profiler
static
Initial value:
=
{ .name = "peerblk.download" }

PeerDist block download profiler.

PeerDist block download discovery timeout profiler.

PeerDist block download discovery success profiler.

PeerDist block download attempt timeout profiler.

PeerDist block download attempt failure profiler.

PeerDist block download attempt success profiler.

Definition at line 108 of file peerblk.c.

108 { .name = "peerblk.download" };

◆ peerblk_queue_desc

struct process_descriptor peerblk_queue_desc
static
Initial value:
=
static void peerblk_step(struct peerdist_block_queue *queue)
PeerDist block download queue process.
Definition peerblk.c:481
#define PROC_DESC_ONCE(object_type, process, _step)
Define a process descriptor for a process that runs only once.
Definition process.h:98
A process.
Definition process.h:18

PeerDist block download queue process descriptor.

Definition at line 561 of file peerblk.c.

◆ peerblk_raw_queue

struct peerdist_block_queue peerblk_raw_queue
static
Initial value:
= {
}
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition list.h:31
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
#define PEERBLK_RAW_MAX
PeerDist maximum number of concurrent raw block downloads.
Definition peerblk.c:70
#define PROC_INIT(_process, _desc)
Initialise a static process.
Definition process.h:132

Raw block download queue.

Definition at line 565 of file peerblk.c.

565 {
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};

Referenced by peerblk_expired().

◆ peerblk_xfer_operations

struct interface_operation peerblk_xfer_operations[]
static
Initial value:
= {
}
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33

PeerDist block download data transfer interface operations.

Definition at line 1355 of file peerblk.c.

1355 {
1357};

◆ peerblk_xfer_desc

struct interface_descriptor peerblk_xfer_desc
static
Initial value:
=
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static struct interface_operation peerblk_xfer_operations[]
PeerDist block download data transfer interface operations.
Definition peerblk.c:1355

PeerDist block download data transfer interface descriptor.

Definition at line 1360 of file peerblk.c.

Referenced by peerblk_open().

◆ peerblk_raw_operations

struct interface_operation peerblk_raw_operations[]
static
Initial value:
= {
}
static void peerblk_raw_close(struct peerdist_block *peerblk, int rc)
Close PeerDist raw block download attempt.
Definition peerblk.c:451
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

PeerDist block download raw data interface operations.

Definition at line 1364 of file peerblk.c.

1364 {
1367};

◆ peerblk_raw_desc

struct interface_descriptor peerblk_raw_desc
static
Initial value:
=
__be32 raw[7]
Definition CIB_PRM.h:0
static struct interface_operation peerblk_raw_operations[]
PeerDist block download raw data interface operations.
Definition peerblk.c:1364

PeerDist block download raw data interface descriptor.

Definition at line 1370 of file peerblk.c.

Referenced by peerblk_open().

◆ peerblk_retrieval_operations

struct interface_operation peerblk_retrieval_operations[]
static
Initial value:
= {
}
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:634
static void peerblk_retrieval_close(struct peerdist_block *peerblk, int rc)
Close PeerDist retrieval protocol block download attempt.
Definition peerblk.c:1174

PeerDist block download retrieval protocol interface operations.

Definition at line 1374 of file peerblk.c.

◆ peerblk_retrieval_desc

struct interface_descriptor peerblk_retrieval_desc
static
Initial value:
=
INTF_DESC ( struct peerdist_block, retrieval,
static struct interface_operation peerblk_retrieval_operations[]
PeerDist block download retrieval protocol interface operations.
Definition peerblk.c:1374

PeerDist block download retrieval protocol interface descriptor.

Definition at line 1380 of file peerblk.c.

Referenced by peerblk_open().

◆ peerblk_process_desc

struct process_descriptor peerblk_process_desc
static
Initial value:
=
static void peerblk_decrypt(struct peerdist_block *peerblk)
Decrypt one chunk of PeerDist retrieval protocol data.
Definition peerblk.c:1076
#define PROC_DESC(object_type, process, _step)
Define a process descriptor.
Definition process.h:83

PeerDist block download decryption process descriptor.

Definition at line 1385 of file peerblk.c.

Referenced by peerblk_open().

◆ peerblk_discovery_operations

struct peerdisc_client_operations peerblk_discovery_operations
static
Initial value:
= {
.discovered = peerblk_discovered,
}
static void peerblk_discovered(struct peerdisc_client *discovery)
Handle PeerDist peer discovery.
Definition peerblk.c:1328

PeerDist block download discovery operations.

Definition at line 1389 of file peerblk.c.

1389 {
1390 .discovered = peerblk_discovered,
1391};

Referenced by peerblk_open().