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 struct uripeerblk_retrieval_uri (const char *location)
 Construct PeerDist retrieval protocol URI.
static int peerblk_retrieval_open (struct peerdist_block *peerblk, 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:322
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
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:219
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:74

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:598
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:505
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: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
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:506
uint8_t head
Head number.
Definition int13.h:23
#define EIO
Input/output error.
Definition errno.h:434
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
Definition crypto.h:230
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:101
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:82
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:522
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
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
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:136

References peerdist_block::block, DBGC, DBGC2, peerdist_range::end, ETIMEDOUT, http_get, 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:224
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:53
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_uri()

struct uri * peerblk_retrieval_uri ( const char * location)
static

Construct PeerDist retrieval protocol URI.

Parameters
locationPeer location
Return values
uriRetrieval URI, or NULL on error

Definition at line 585 of file peerblk.c.

585 {
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}
#define PEERDIST_MAGIC_PATH
Magic retrieval URI path.
Definition pccrr.h:18
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
struct uri * parse_uri(const char *uri_string)
Parse URI.
Definition uri.c:297
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383

References parse_uri(), PEERDIST_MAGIC_PATH, snprintf(), and strlen().

Referenced by peerblk_retrieval_open().

◆ peerblk_retrieval_open()

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

Open PeerDist retrieval protocol block download attempt.

Parameters
peerblkPeerDist block download
locationPeer location
Return values
rcReturn status code

Definition at line 604 of file peerblk.c.

605 {
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 ) );
619 req.getblks.hdr.type = htonl ( PEERDIST_MSG_GETBLKS_TYPE );
620 req.getblks.hdr.len = htonl ( sizeof ( req ) );
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}
__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
u32 version
Driver version.
Definition ath9k_hw.c:1985
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define ENOMEM
Not enough space.
Definition errno.h:535
struct http_method http_post
HTTP POST method.
Definition httpcore.c:149
u16 algorithm
Authentication algorithm (Open System or Shared Key)
Definition ieee80211.h:1
#define htonl(value)
Definition byteswap.h:134
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
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
if(natsemi->flags &NATSEMI_64BIT) return 1
uint32_t first
First block in range.
Definition pccrr.h:1
#define peerdist_msg_getblks_t(digestsize, count, vrf_len)
Retrieval protocol block fetch request.
Definition pccrr.h:266
#define PEERDIST_MSG_GETBLKS_VERSION
Retrieval protocol block fetch request version.
Definition pccrr.h:275
@ PEERDIST_MSG_AES_128_CBC
AES-128 in CBC mode.
Definition pccrr.h:172
#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
#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT
PeerDist retrieval protocol block download attempt initial progress timeout.
Definition peerblk.c:88
static struct uri * peerblk_retrieval_uri(const char *location)
Construct PeerDist retrieval protocol URI.
Definition peerblk.c:585
#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
HTTP request content descriptor.
Definition http.h:144
A Uniform Resource Identifier.
Definition uri.h:65

References peerdist_block::block, http_request_content::data, DBGC, DBGC2, digestsize, peerdist_block::digestsize, peerdist_block::end, ENOMEM, ETIMEDOUT, htonl, http_open(), http_post, peerdist_block::id, intf_restart(), http_request_content::len, memcpy(), memset(), msg(), NULL, offsetof, PEERBLK_ANNUL_RATE, peerblk_msg_blk_t, PEERBLK_RETRIEVAL_OPEN_TIMEOUT, peerblk_retrieval_uri(), PEERDIST_MSG_AES_128_CBC, peerdist_msg_getblks_t, PEERDIST_MSG_GETBLKS_TYPE, PEERDIST_MSG_GETBLKS_VERSION, peerdist_block::rc, rc, peerdist_block::retrieval, rsp, peerdist_block::segment, peerdist_block::start, start_timer_fixed(), strerror(), peerdist_block::timer, typeof(), and uri_put().

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 677 of file peerblk.c.

679 {
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}
#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:113

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 790 of file peerblk.c.

790 {
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}
struct cipher_algorithm aes_cbc_algorithm
#define EPROTO
Protocol error.
Definition errno.h:625
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ERANGE
Result too large.
Definition errno.h:640
#define ntohl(value)
Definition byteswap.h:135
#define __attribute__(x)
Definition compiler.h:10
static int cipher_setkey(struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen)
Definition crypto.h:235
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
#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_PLAINTEXT
No encryption.
Definition pccrr.h:170
@ PEERDIST_MSG_AES_256_CBC
AES-256 in CBC mode.
Definition pccrr.h:176
A cipher algorithm.
Definition crypto.h:51
const char * name
Algorithm name.
Definition crypto.h:53
size_t ctxsize
Context size.
Definition crypto.h:55
uint8_t secret[PEERDIST_DIGEST_MAX_SIZE]
Segment secret.
Definition peerblk.h:87
Retrieval protocol message header.
Definition pccrr.h:152
Retrieval protocol transport response header.
Definition pccrr.h:180
size_t len
Size of data.
Definition xferbuf.h:23
void * data
Data.
Definition xferbuf.h:21

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 880 of file peerblk.c.

881 {
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}
#define ENOENT
No such file or directory.
Definition errno.h:515
#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
uint8_t id[PEERDIST_DIGEST_MAX_SIZE]
Segment identifier.
Definition peerblk.h:85
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 984 of file peerblk.c.

985 {
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}

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 1013 of file peerblk.c.

1014 {
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}
static void cipher_setiv(struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen)
Definition crypto.h:241
uint32_t blksize
Cipher block size.
Definition pccrr.h:1
size_t blocksize
Block size.
Definition crypto.h:61

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, EPROTO, ERANGE, len, xfer_buffer::len, msg(), ntohl, peerblk_msg_blk_t, and peerdist_block::segment.

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 1052 of file peerblk.c.

1053 {
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}
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:147

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 1085 of file peerblk.c.

1086 {
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}

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 1119 of file peerblk.c.

1119 {
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}
#define cipher_decrypt(cipher, ctx, src, dst, len)
Definition crypto.h:261
static int peerblk_decrypt_read(struct peerdist_block *peerblk, void *data, size_t len)
Read from decryption buffers.
Definition peerblk.c:1052
#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:1085
A data transfer buffer.
Definition xferbuf.h:19
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
Definition xferbuf.c:306

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, 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 1209 of file peerblk.c.

1209 {
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}
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 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_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

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 1280 of file peerblk.c.

1280 {
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}
#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, const char *location)
Open PeerDist retrieval protocol block download attempt.
Definition peerblk.c:604
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
char location[0]
Peer location.
Definition peerdisc.h:76
unsigned int cycles
Number of full attempt cycles completed.
Definition peerblk.h:122
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, peerdisc_peer::list, 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_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 1361 of file peerblk.c.

1361 {
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}
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 1434 of file peerblk.c.

1435 {
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}
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:662
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
static struct process_descriptor peerblk_process_desc
PeerDist block download decryption process descriptor.
Definition peerblk.c:1418
static struct interface_descriptor peerblk_retrieval_desc
PeerDist block download retrieval protocol interface descriptor.
Definition peerblk.c:1413
static struct interface_descriptor peerblk_raw_desc
PeerDist block download raw data interface descriptor.
Definition peerblk.c:1403
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
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
Definition peerdisc.c:560
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
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
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:54

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.

109 { .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 1388 of file peerblk.c.

1388 {
1390};

◆ 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:1388

PeerDist block download data transfer interface descriptor.

Definition at line 1393 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 1397 of file peerblk.c.

1397 {
1400};

◆ peerblk_raw_desc

struct interface_descriptor peerblk_raw_desc
static
Initial value:
=
static struct interface_operation peerblk_raw_operations[]
PeerDist block download raw data interface operations.
Definition peerblk.c:1397

PeerDist block download raw data interface descriptor.

Definition at line 1403 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:677
static void peerblk_retrieval_close(struct peerdist_block *peerblk, int rc)
Close PeerDist retrieval protocol block download attempt.
Definition peerblk.c:1209

PeerDist block download retrieval protocol interface operations.

Definition at line 1407 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:1407

PeerDist block download retrieval protocol interface descriptor.

Definition at line 1413 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:1119
#define PROC_DESC(object_type, process, _step)
Define a process descriptor.
Definition process.h:83

PeerDist block download decryption process descriptor.

Definition at line 1418 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:1361

PeerDist block download discovery operations.

Definition at line 1422 of file peerblk.c.

1422 {
1423 .discovered = peerblk_discovered,
1424};

Referenced by peerblk_open().