iPXE
Data Structures | Functions | Variables
pccrc.c File Reference

Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]. More...

#include <errno.h>
#include <assert.h>
#include <ipxe/uaccess.h>
#include <ipxe/sha256.h>
#include <ipxe/sha512.h>
#include <ipxe/hmac.h>
#include <ipxe/base16.h>
#include <ipxe/pccrc.h>

Go to the source code of this file.

Data Structures

struct  peerdist_info_v2_cursor
 A segment cursor. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static const char * peerdist_info_hash_ntoa (const struct peerdist_info *info, const void *hash)
 Transcribe hash value (for debugging)
static int peerdist_info_get (const struct peerdist_info *info, void *data, size_t offset, size_t len)
 Get raw data.
static void peerdist_info_segment_hash (struct peerdist_info_segment *segment, const void *hash, const void *secret)
 Populate segment hashes.
static int peerdist_info_v1_blocks (const struct peerdist_info *info, size_t offset)
 Get number of blocks within a block description.
static ssize_t peerdist_info_v1_block_offset (const struct peerdist_info *info, unsigned int index)
 Locate block description.
static int peerdist_info_v1 (struct peerdist_info *info)
 Populate content information.
static int peerdist_info_v1_segment (struct peerdist_info_segment *segment)
 Populate content information segment.
static int peerdist_info_v1_block (struct peerdist_info_block *block)
 Populate content information block.
static void peerdist_info_v2_cursor_init (struct peerdist_info_v2_cursor *cursor)
 Initialise segment cursor.
static int peerdist_info_v2_cursor_next (const struct peerdist_info *info, struct peerdist_info_v2_cursor *cursor)
 Update segment cursor to next segment description.
static int peerdist_info_v2_segments (const struct peerdist_info *info, size_t *len)
 Get number of segments and total length.
static int peerdist_info_v2 (struct peerdist_info *info)
 Populate content information.
static int peerdist_info_v2_segment (struct peerdist_info_segment *segment)
 Populate content information segment.
static int peerdist_info_v2_block (struct peerdist_info_block *block)
 Populate content information block.
int peerdist_info (userptr_t data, size_t len, struct peerdist_info *info)
 Populate content information.
int peerdist_info_segment (const struct peerdist_info *info, struct peerdist_info_segment *segment, unsigned int index)
 Populate content information segment.
int peerdist_info_block (const struct peerdist_info_segment *segment, struct peerdist_info_block *block, unsigned int index)
 Populate content information block.

Variables

static struct
peerdist_info_operations 
peerdist_info_v1_operations
 Content information version 1 operations.
static struct
peerdist_info_operations 
peerdist_info_v2_operations
 Content information version 2 operations.

Detailed Description

Peer Content Caching and Retrieval: Content Identification [MS-PCCRC].

Definition in file pccrc.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static const char* peerdist_info_hash_ntoa ( const struct peerdist_info info,
const void *  hash 
) [inline, static]

Transcribe hash value (for debugging)

Parameters:
infoContent information
hashHash value
Return values:
stringHash value string

Definition at line 56 of file pccrc.c.

References assert, base16_encoded_len(), digestsize, peerdist_info::digestsize, NULL, and PEERDIST_DIGEST_MAX_SIZE.

Referenced by peerdist_info_block(), and peerdist_info_segment().

                                                                               {
        static char buf[ ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* NUL */ ];
        size_t digestsize = info->digestsize;

        /* Sanity check */
        assert ( info != NULL );
        assert ( digestsize != 0 );
        assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );

        /* Transcribe hash value */
        base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
        return buf;
}
static int peerdist_info_get ( const struct peerdist_info info,
void *  data,
size_t  offset,
size_t  len 
) [static]

Get raw data.

Parameters:
infoContent information
dataData buffer
offsetStarting offset
lenLength
Return values:
rcReturn status code

Definition at line 79 of file pccrc.c.

References copy_from_user(), peerdist_raw::data, DBGC, ERANGE, peerdist_raw::len, and peerdist_info::raw.

Referenced by peerdist_info(), peerdist_info_v1(), peerdist_info_v1_block(), peerdist_info_v1_blocks(), peerdist_info_v1_segment(), peerdist_info_v2(), peerdist_info_v2_cursor_next(), and peerdist_info_v2_segment().

                                                           {

        /* Sanity check */
        if ( ( offset > info->raw.len ) ||
             ( len > ( info->raw.len - offset ) ) ) {
                DBGC ( info, "PCCRC %p data underrun at [%zx,%zx) of %zx\n",
                       info, offset, ( offset + len ), info->raw.len );
                return -ERANGE;
        }

        /* Copy data */
        copy_from_user ( data, info->raw.data, offset, len );

        return 0;
}
static void peerdist_info_segment_hash ( struct peerdist_info_segment segment,
const void *  hash,
const void *  secret 
) [static]

Populate segment hashes.

Parameters:
segmentContent information segment to fill in
hashSegment hash of data
secretSegment secret

Definition at line 103 of file pccrc.c.

References assert, ctx, digest_algorithm::ctxsize, digest, peerdist_info::digest, digestsize, peerdist_info::digestsize, peerdist_info_segment::hash, hmac_final(), hmac_init(), hmac_update(), peerdist_info_segment::id, info, peerdist_info_segment::info, magic, memcpy(), PEERDIST_SEGMENT_ID_MAGIC, and peerdist_info_segment::secret.

Referenced by peerdist_info_v1_segment(), and peerdist_info_v2_segment().

                                                                               {
        const struct peerdist_info *info = segment->info;
        struct digest_algorithm *digest = info->digest;
        uint8_t ctx[digest->ctxsize];
        size_t digestsize = info->digestsize;
        size_t secretsize = digestsize;
        static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;

        /* Sanity check */
        assert ( digestsize <= sizeof ( segment->hash ) );
        assert ( digestsize <= sizeof ( segment->secret ) );
        assert ( digestsize <= sizeof ( segment->id ) );

        /* Get segment hash of data */
        memcpy ( segment->hash, hash, digestsize );

        /* Get segment secret */
        memcpy ( segment->secret, secret, digestsize );

        /* Calculate segment identifier */
        hmac_init ( digest, ctx, segment->secret, &secretsize );
        assert ( secretsize == digestsize );
        hmac_update ( digest, ctx, segment->hash, digestsize );
        hmac_update ( digest, ctx, magic, sizeof ( magic ) );
        hmac_final ( digest, ctx, segment->secret, &secretsize, segment->id );
        assert ( secretsize == digestsize );
}
static int peerdist_info_v1_blocks ( const struct peerdist_info info,
size_t  offset 
) [static]

Get number of blocks within a block description.

Parameters:
infoContent information
offsetBlock description offset
Return values:
blocksNumber of blocks, or negative error

Definition at line 146 of file pccrc.c.

References peerdist_info_v1_block::blocks, blocks, le32_to_cpu, peerdist_info_get(), and rc.

Referenced by peerdist_info_v1_block_offset(), and peerdist_info_v1_segment().

                                                     {
        struct peerdist_info_v1_block raw;
        unsigned int blocks;
        int rc;

        /* Get block description header */
        if ( ( rc = peerdist_info_get ( info, &raw, offset,
                                        sizeof ( raw ) ) ) != 0 )
                return rc;

        /* Calculate number of blocks */
        blocks = le32_to_cpu ( raw.blocks );

        return blocks;
}
static ssize_t peerdist_info_v1_block_offset ( const struct peerdist_info info,
unsigned int  index 
) [static]

Locate block description.

Parameters:
infoContent information
indexSegment index
Return values:
offsetBlock description offset, or negative error

Definition at line 170 of file pccrc.c.

References assert, blocks, DBGC, digestsize, peerdist_info::digestsize, index, offset, peerdist_info_v1_block_t, peerdist_info_v1_blocks(), peerdist_info_v1_segment_t, rc, segments, and strerror().

Referenced by peerdist_info_v1_block(), and peerdist_info_v1_segment().

                                                                    {
        size_t digestsize = info->digestsize;
        unsigned int i;
        size_t offset;
        int blocks;
        int rc;

        /* Sanity check */
        assert ( index < info->segments );

        /* Calculate offset of first block description */
        offset = ( sizeof ( struct peerdist_info_v1 ) +
                   ( info->segments *
                     sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );

        /* Iterate over block descriptions until we find this segment */
        for ( i = 0 ; i < index ; i++ ) {

                /* Get number of blocks */
                blocks = peerdist_info_v1_blocks ( info, offset );
                if ( blocks < 0 ) {
                        rc = blocks;
                        DBGC ( info, "PCCRC %p segment %d could not get number "
                               "of blocks: %s\n", info, i, strerror ( rc ) );
                        return rc;
                }

                /* Move to next block description */
                offset += sizeof ( peerdist_info_v1_block_t ( digestsize,
                                                              blocks ) );
        }

        return offset;
}
static int peerdist_info_v1 ( struct peerdist_info info) [static]

Populate content information.

Parameters:
infoContent information to fill in
Return values:
rcReturn status code

Definition at line 212 of file pccrc.c.

References assert, cpu_to_le16, cpu_to_le32, DBGC, DBGC2, peerdist_info::digest, digest_algorithm::digestsize, peerdist_info::digestsize, peerdist_range::end, ENOTSUP, peerdist_info_v1::first, peerdist_info_v1::hash, peerdist_info_segment::index, peerdist_info_v1::last, le32_to_cpu, digest_algorithm::name, NULL, peerdist_info_get(), PEERDIST_INFO_V1, PEERDIST_INFO_V1_HASH_SHA256, PEERDIST_INFO_V1_HASH_SHA384, PEERDIST_INFO_V1_HASH_SHA512, peerdist_info::range, peerdist_info_segment::range, peerdist_info_version::raw, rc, peerdist_info_v1::segments, peerdist_info::segments, sha256_algorithm, sha384_algorithm, sha512_algorithm, peerdist_range::start, strerror(), peerdist_info::trim, and peerdist_info_v1::version.

                                                           {
        struct peerdist_info_v1 raw;
        struct peerdist_info_segment first;
        struct peerdist_info_segment last;
        size_t first_skip;
        size_t last_skip;
        size_t last_read;
        int rc;

        /* Get raw header */
        if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
                DBGC ( info, "PCCRC %p could not get V1 content information: "
                       "%s\n", info, strerror ( rc ) );
                return rc;
        }
        assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );

        /* Determine hash algorithm */
        switch ( raw.hash ) {
        case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA256 ) :
                info->digest = &sha256_algorithm;
                break;
        case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA384 ) :
                info->digest = &sha384_algorithm;
                break;
        case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA512 ) :
                info->digest = &sha512_algorithm;
                break;
        default:
                DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
                       info, le32_to_cpu ( raw.hash ) );
                return -ENOTSUP;
        }
        info->digestsize = info->digest->digestsize;
        assert ( info->digest != NULL );
        DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
                info, info->digest->name, ( info->digestsize * 8 ) );

        /* Calculate number of segments */
        info->segments = le32_to_cpu ( raw.segments );

        /* Get first segment */
        if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
                return rc;

        /* Calculate range start offset */
        info->range.start = first.range.start;

        /* Calculate trimmed range start offset */
        first_skip = le32_to_cpu ( raw.first );
        info->trim.start = ( first.range.start + first_skip );

        /* Get last segment */
        if ( ( rc = peerdist_info_segment ( info, &last,
                                            ( info->segments - 1 ) ) ) != 0 )
                return rc;

        /* Calculate range end offset */
        info->range.end = last.range.end;

        /* Calculate trimmed range end offset */
        if ( raw.last ) {
                /* Explicit length to include from last segment is given */
                last_read = le32_to_cpu ( raw.last );
                last_skip = ( last.index ? 0 : first_skip );
                info->trim.end = ( last.range.start + last_skip + last_read );
        } else {
                /* No explicit length given: range extends to end of segment */
                info->trim.end = last.range.end;
        }

        return 0;
}
static int peerdist_info_v1_segment ( struct peerdist_info_segment segment) [static]

Populate content information segment.

Parameters:
segmentContent information segment to fill in
Return values:
rcReturn status code

Definition at line 292 of file pccrc.c.

References assert, blocks, DBGC, digestsize, peerdist_info::digestsize, peerdist_info_segment::index, info, peerdist_info_segment::info, le32_to_cpu, le64_to_cpu, peerdist_info_get(), peerdist_info_segment_hash(), peerdist_info_v1_block_offset(), peerdist_info_v1_blocks(), peerdist_info_v1_segment_t, raw, rc, peerdist_info::segments, and strerror().

                                                                              {
        const struct peerdist_info *info = segment->info;
        size_t digestsize = info->digestsize;
        peerdist_info_v1_segment_t ( digestsize ) raw;
        ssize_t raw_offset;
        int blocks;
        int rc;

        /* Sanity checks */
        assert ( segment->index < info->segments );

        /* Get raw description */
        raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
                       ( segment->index * sizeof ( raw ) ) );
        if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
                                        sizeof ( raw ) ) ) != 0 ) {
                DBGC ( info, "PCCRC %p segment %d could not get segment "
                       "description: %s\n", info, segment->index,
                       strerror ( rc ) );
                return rc;
        }

        /* Calculate start offset of this segment */
        segment->range.start = le64_to_cpu ( raw.segment.offset );

        /* Calculate end offset of this segment */
        segment->range.end = ( segment->range.start +
                               le32_to_cpu ( raw.segment.len ) );

        /* Calculate block size of this segment */
        segment->blksize = le32_to_cpu ( raw.segment.blksize );

        /* Locate block description for this segment */
        raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
        if ( raw_offset < 0 ) {
                rc = raw_offset;
                return rc;
        }

        /* Get number of blocks */
        blocks = peerdist_info_v1_blocks ( info, raw_offset );
        if ( blocks < 0 ) {
                rc = blocks;
                DBGC ( info, "PCCRC %p segment %d could not get number of "
                       "blocks: %s\n", info, segment->index, strerror ( rc ) );
                return rc;
        }
        segment->blocks = blocks;

        /* Calculate segment hashes */
        peerdist_info_segment_hash ( segment, raw.hash, raw.secret );

        return 0;
}
static int peerdist_info_v1_block ( struct peerdist_info_block block) [static]

Populate content information block.

Parameters:
blockContent information block to fill in
Return values:
rcReturn status code

Definition at line 353 of file pccrc.c.

References assert, peerdist_info_segment::blksize, peerdist_info_segment::blocks, DBGC, digestsize, peerdist_info::digestsize, peerdist_range::end, hash, peerdist_info_block::hash, peerdist_info_segment::index, peerdist_info_block::index, info, peerdist_info_segment::info, offsetof, peerdist_info_get(), peerdist_info_v1_block_offset(), peerdist_info_v1_block_t, peerdist_info_segment::range, peerdist_info_block::range, raw, rc, segment, peerdist_info_block::segment, peerdist_range::start, and strerror().

                                                                        {
        const struct peerdist_info_segment *segment = block->segment;
        const struct peerdist_info *info = segment->info;
        size_t digestsize = info->digestsize;
        peerdist_info_v1_block_t ( digestsize, segment->blocks ) raw;
        ssize_t raw_offset;
        int rc;

        /* Sanity checks */
        assert ( block->index < segment->blocks );

        /* Calculate start offset of this block */
        block->range.start = ( segment->range.start +
                               ( block->index * segment->blksize ) );

        /* Calculate end offset of this block */
        block->range.end = ( block->range.start + segment->blksize );
        if ( block->range.end > segment->range.end )
                block->range.end = segment->range.end;

        /* Locate block description */
        raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
        if ( raw_offset < 0 ) {
                rc = raw_offset;
                return rc;
        }

        /* Get block hash */
        raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
        if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
                                        digestsize ) ) != 0 ) {
                DBGC ( info, "PCCRC %p segment %d block %d could not get "
                       "hash: %s\n", info, segment->index, block->index,
                       strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void peerdist_info_v2_cursor_init ( struct peerdist_info_v2_cursor cursor) [inline, static]

Initialise segment cursor.

Parameters:
cursorSegment cursor

Definition at line 423 of file pccrc.c.

References peerdist_info_v2_cursor::len, peerdist_info_v2_cursor::offset, and peerdist_info_v2_cursor::remaining.

Referenced by peerdist_info_v2_segment(), and peerdist_info_v2_segments().

                                                                        {

        /* Initialise cursor */
        cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
                           sizeof ( struct peerdist_info_v2_chunk ) );
        cursor->remaining = 0;
        cursor->len = 0;
}
static int peerdist_info_v2_cursor_next ( const struct peerdist_info info,
struct peerdist_info_v2_cursor cursor 
) [static]

Update segment cursor to next segment description.

Parameters:
infoContent information
offsetCurrent offset
remainingNumber of segments remaining within this chunk
Return values:
rcReturn status code

Definition at line 441 of file pccrc.c.

References be32_to_cpu, digestsize, peerdist_info::digestsize, peerdist_info_v2_chunk::len, peerdist_info_v2_cursor::len, peerdist_info_v2_cursor::offset, peerdist_info_get(), peerdist_info_v2_segment_t, raw, rc, and peerdist_info_v2_cursor::remaining.

Referenced by peerdist_info_v2_segment(), and peerdist_info_v2_segments().

                                                                        {
        size_t digestsize = info->digestsize;
        peerdist_info_v2_segment_t ( digestsize ) raw;
        struct peerdist_info_v2_chunk chunk;
        int rc;

        /* Get chunk description if applicable */
        if ( ! cursor->remaining ) {

                /* Get chunk description */
                if ( ( rc = peerdist_info_get ( info, &chunk,
                                                ( cursor->offset -
                                                  sizeof ( chunk ) ),
                                                sizeof ( chunk ) ) ) != 0 )
                        return rc;

                /* Update number of segments remaining */
                cursor->remaining = ( be32_to_cpu ( chunk.len ) /
                                      sizeof ( raw ) );
        }

        /* Get segment description header */
        if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
                                        sizeof ( raw.segment ) ) ) != 0 )
                return rc;

        /* Update cursor */
        cursor->offset += sizeof ( raw );
        cursor->remaining--;
        if ( ! cursor->remaining )
                cursor->offset += sizeof ( chunk );
        cursor->len += be32_to_cpu ( raw.segment.len );

        return 0;
}
static int peerdist_info_v2_segments ( const struct peerdist_info info,
size_t len 
) [static]

Get number of segments and total length.

Parameters:
infoContent information
lenLength to fill in
Return values:
rcNumber of segments, or negative error

Definition at line 485 of file pccrc.c.

References DBGC, peerdist_raw::len, peerdist_info_v2_cursor::len, peerdist_info_v2_cursor::offset, peerdist_info_v2_cursor_init(), peerdist_info_v2_cursor_next(), peerdist_info::raw, rc, segments, and strerror().

Referenced by peerdist_info_v2().

                                                     {
        struct peerdist_info_v2_cursor cursor;
        unsigned int segments;
        int rc;

        /* Iterate over all segments */
        for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
              cursor.offset < info->raw.len ; segments++ ) {

                /* Update segment cursor */
                if ( ( rc = peerdist_info_v2_cursor_next ( info,
                                                           &cursor ) ) != 0 ) {
                        DBGC ( info, "PCCRC %p segment %d could not update "
                               "segment cursor: %s\n",
                               info, segments, strerror ( rc ) );
                        return rc;
                }
        }

        /* Record accumulated length */
        *len = cursor.len;

        return segments;
}
static int peerdist_info_v2 ( struct peerdist_info info) [static]

Populate content information.

Parameters:
infoContent information to fill in
Return values:
rcReturn status code

Definition at line 517 of file pccrc.c.

References assert, be32_to_cpu, be64_to_cpu, cpu_to_le16, DBGC, DBGC2, peerdist_info::digest, peerdist_info::digestsize, peerdist_range::end, ENOTSUP, peerdist_info_v2::first, peerdist_info_v2::hash, peerdist_info_v2::len, len, digest_algorithm::name, NULL, peerdist_info_v2::offset, peerdist_info_get(), PEERDIST_INFO_V2, PEERDIST_INFO_V2_HASH_SHA512_TRUNC, peerdist_info_v2_segments(), peerdist_info::range, peerdist_info_version::raw, rc, segments, peerdist_info::segments, sha512_algorithm, peerdist_range::start, strerror(), peerdist_info::trim, and peerdist_info_v2::version.

                                                           {
        struct peerdist_info_v2 raw;
        size_t len = 0;
        int segments;
        int rc;

        /* Get raw header */
        if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
                DBGC ( info, "PCCRC %p could not get V2 content information: "
                       "%s\n", info, strerror ( rc ) );
                return rc;
        }
        assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );

        /* Determine hash algorithm */
        switch ( raw.hash ) {
        case PEERDIST_INFO_V2_HASH_SHA512_TRUNC :
                info->digest = &sha512_algorithm;
                info->digestsize = ( 256 / 8 );
                break;
        default:
                DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
                       info, raw.hash );
                return -ENOTSUP;
        }
        assert ( info->digest != NULL );
        DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
                info, info->digest->name, ( info->digestsize * 8 ) );

        /* Calculate number of segments and total length */
        segments = peerdist_info_v2_segments ( info, &len );
        if ( segments < 0 ) {
                rc = segments;
                DBGC ( info, "PCCRC %p could not get segment count and length: "
                       "%s\n", info, strerror ( rc ) );
                return rc;
        }
        info->segments = segments;

        /* Calculate range start offset */
        info->range.start = be64_to_cpu ( raw.offset );

        /* Calculate trimmed range start offset */
        info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );

        /* Calculate range end offset */
        info->range.end = ( info->range.start + len );

        /* Calculate trimmed range end offset */
        info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
                           info->range.end );

        return 0;
}
static int peerdist_info_v2_segment ( struct peerdist_info_segment segment) [static]

Populate content information segment.

Parameters:
segmentContent information segment to fill in
Return values:
rcReturn status code

Definition at line 578 of file pccrc.c.

References assert, be32_to_cpu, peerdist_info_segment::blksize, peerdist_info_segment::blocks, DBGC, digestsize, peerdist_info::digestsize, peerdist_range::end, index, peerdist_info_segment::index, info, peerdist_info_segment::info, len, peerdist_info_v2_cursor::len, peerdist_info_v2_cursor::offset, peerdist_info_get(), peerdist_info_segment_hash(), peerdist_info_v2_cursor_init(), peerdist_info_v2_cursor_next(), peerdist_info_v2_segment_t, peerdist_info::range, peerdist_info_segment::range, raw, rc, peerdist_info::segments, peerdist_range::start, and strerror().

                                                                              {
        const struct peerdist_info *info = segment->info;
        size_t digestsize = info->digestsize;
        peerdist_info_v2_segment_t ( digestsize ) raw;
        struct peerdist_info_v2_cursor cursor;
        unsigned int index;
        size_t len;
        int rc;

        /* Sanity checks */
        assert ( segment->index < info->segments );

        /* Iterate over all segments before the target segment */
        for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
              index < segment->index ; index++ ) {

                /* Update segment cursor */
                if ( ( rc = peerdist_info_v2_cursor_next ( info,
                                                           &cursor ) ) != 0 ) {
                        DBGC ( info, "PCCRC %p segment %d could not update "
                               "segment cursor: %s\n",
                               info, index, strerror ( rc ) );
                        return rc;
                }
        }

        /* Get raw description */
        if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
                                        sizeof ( raw ) ) ) != 0 ) {
                DBGC ( info, "PCCRC %p segment %d could not get segment "
                       "description: %s\n",
                       info, segment->index, strerror ( rc ) );
                return rc;
        }

        /* Calculate start offset of this segment */
        segment->range.start = ( info->range.start + cursor.len );

        /* Calculate end offset of this segment */
        len = be32_to_cpu ( raw.segment.len );
        segment->range.end = ( segment->range.start + len );

        /* Model as a segment containing a single block */
        segment->blocks = 1;
        segment->blksize = len;

        /* Calculate segment hashes */
        peerdist_info_segment_hash ( segment, raw.hash, raw.secret );

        return 0;
}
static int peerdist_info_v2_block ( struct peerdist_info_block block) [static]

Populate content information block.

Parameters:
blockContent information block to fill in
Return values:
rcReturn status code

Definition at line 636 of file pccrc.c.

References assert, peerdist_info_segment::blocks, digestsize, peerdist_info::digestsize, peerdist_info_segment::hash, peerdist_info_block::hash, peerdist_info_block::index, info, peerdist_info_segment::info, memcpy(), peerdist_info_segment::range, peerdist_info_block::range, segment, and peerdist_info_block::segment.

                                                                        {
        const struct peerdist_info_segment *segment = block->segment;
        const struct peerdist_info *info = segment->info;
        size_t digestsize = info->digestsize;

        /* Sanity checks */
        assert ( block->index < segment->blocks );

        /* Model as a block covering the whole segment */
        memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
        memcpy ( block->hash, segment->hash, digestsize );

        return 0;
}
int peerdist_info ( userptr_t  data,
size_t  len,
struct peerdist_info info 
)

Populate content information.

Parameters:
dataRaw data
lenLength of raw data
infoContent information to fill in
Return values:
rcReturn status code

Definition at line 673 of file pccrc.c.

References assert, cpu_to_le16, data, peerdist_raw::data, DBGC, DBGC2, peerdist_range::end, ENOTSUP, peerdist_info_operations::info, len, peerdist_raw::len, peerdist_info_version::major, memset(), peerdist_info_version::minor, NULL, peerdist_info::op, peerdist_info_get(), PEERDIST_INFO_V1, peerdist_info_v1_operations, PEERDIST_INFO_V2, peerdist_info_v2_operations, peerdist_info::range, peerdist_info_version::raw, peerdist_info::raw, rc, peerdist_info::segments, peerdist_range::start, strerror(), and peerdist_info::trim.

                                                                             {
        union peerdist_info_version version;
        int rc;

        /* Initialise structure */
        memset ( info, 0, sizeof ( *info ) );
        info->raw.data = data;
        info->raw.len = len;

        /* Get version */
        if ( ( rc = peerdist_info_get ( info, &version, 0,
                                        sizeof ( version ) ) ) != 0 ) {
                DBGC ( info, "PCCRC %p could not get version: %s\n",
                       info, strerror ( rc ) );
                return rc;
        }
        DBGC2 ( info, "PCCRC %p version %d.%d\n",
                info, version.major, version.minor );

        /* Determine version */
        switch ( version.raw ) {
        case cpu_to_le16 ( PEERDIST_INFO_V1 ) :
                info->op = &peerdist_info_v1_operations;
                break;
        case cpu_to_le16 ( PEERDIST_INFO_V2 ) :
                info->op = &peerdist_info_v2_operations;
                break;
        default:
                DBGC ( info, "PCCRC %p unsupported version %d.%d\n",
                       info, version.major, version.minor );
                return -ENOTSUP;
        }
        assert ( info->op != NULL );
        assert ( info->op->info != NULL );

        /* Populate content information */
        if ( ( rc = info->op->info ( info ) ) != 0 )
                return rc;

        DBGC2 ( info, "PCCRC %p range [%08zx,%08zx) covers [%08zx,%08zx) with "
                "%d segments\n", info, info->range.start, info->range.end,
                info->trim.start, info->trim.end, info->segments );
        return 0;
}
int peerdist_info_segment ( const struct peerdist_info info,
struct peerdist_info_segment segment,
unsigned int  index 
)

Populate content information segment.

Parameters:
infoContent information
segmentContent information segment to fill in
indexSegment index
Return values:
rcReturn status code

Definition at line 726 of file pccrc.c.

References assert, peerdist_info_segment::blocks, DBGC, DBGC2, peerdist_range::end, ERANGE, peerdist_info_segment::hash, peerdist_info_segment::id, index, peerdist_info_segment::index, info, peerdist_info_segment::info, memset(), NULL, peerdist_info::op, peerdist_info_hash_ntoa(), peerdist_info_segment::range, rc, peerdist_info_segment::secret, peerdist_info_operations::segment, peerdist_info::segments, and peerdist_range::start.

                                                 {
        int rc;

        /* Sanity checks */
        assert ( info != NULL );
        assert ( info->op != NULL );
        assert ( info->op->segment != NULL );
        if ( index >= info->segments ) {
                DBGC ( info, "PCCRC %p segment %d of [0,%d) out of range\n",
                       info, index, info->segments );
                return -ERANGE;
        }

        /* Initialise structure */
        memset ( segment, 0, sizeof ( *segment ) );
        segment->info = info;
        segment->index = index;

        /* Populate content information segment */
        if ( ( rc = info->op->segment ( segment ) ) != 0 )
                return rc;

        DBGC2 ( info, "PCCRC %p segment %d range [%08zx,%08zx) with %d "
                "blocks\n", info, segment->index, segment->range.start,
                segment->range.end, segment->blocks );
        DBGC2 ( info, "PCCRC %p segment %d digest %s\n", info, segment->index,
                peerdist_info_hash_ntoa ( info, segment->hash ) );
        DBGC2 ( info, "PCCRC %p segment %d secret %s\n", info, segment->index,
                peerdist_info_hash_ntoa ( info, segment->secret ) );
        DBGC2 ( info, "PCCRC %p segment %d identf %s\n", info, segment->index,
                peerdist_info_hash_ntoa ( info, segment->id ) );
        return 0;
}
int peerdist_info_block ( const struct peerdist_info_segment segment,
struct peerdist_info_block block,
unsigned int  index 
)

Populate content information block.

Parameters:
segmentContent information segment
blockContent information block to fill in
indexBlock index
Return values:
rcReturn status code

Definition at line 770 of file pccrc.c.

References assert, peerdist_info_operations::block, peerdist_info_segment::blocks, DBGC, DBGC2, end, peerdist_range::end, ERANGE, peerdist_info_block::hash, index, peerdist_info_segment::index, peerdist_info_block::index, info, peerdist_info_segment::info, memset(), NULL, peerdist_info::op, peerdist_info_hash_ntoa(), peerdist_info_block::range, rc, segment, peerdist_info_block::segment, start, peerdist_range::start, peerdist_info::trim, and peerdist_info_block::trim.

                                               {
        const struct peerdist_info *info = segment->info;
        size_t start;
        size_t end;
        int rc;

        /* Sanity checks */
        assert ( segment != NULL );
        assert ( info != NULL );
        assert ( info->op != NULL );
        assert ( info->op->block != NULL );
        if ( index >= segment->blocks ) {
                DBGC ( info, "PCCRC %p segment %d block %d of [0,%d) out of "
                       "range\n", info, segment->index, index, segment->blocks);
                return -ERANGE;
        }

        /* Initialise structure */
        memset ( block, 0, sizeof ( *block ) );
        block->segment = segment;
        block->index = index;

        /* Populate content information block */
        if ( ( rc = info->op->block ( block ) ) != 0 )
                return rc;

        /* Calculate trimmed range */
        start = block->range.start;
        if ( start < info->trim.start )
                start = info->trim.start;
        end = block->range.end;
        if ( end > info->trim.end )
                end = info->trim.end;
        if ( end < start )
                end = start;
        block->trim.start = start;
        block->trim.end = end;

        DBGC2 ( info, "PCCRC %p segment %d block %d hash %s\n",
                info, segment->index, block->index,
                peerdist_info_hash_ntoa ( info, block->hash ) );
        DBGC2 ( info, "PCCRC %p segment %d block %d range [%08zx,%08zx) covers "
                "[%08zx,%08zx)\n", info, segment->index, block->index,
                block->range.start, block->range.end, block->trim.start,
                block->trim.end );
        return 0;
}

Variable Documentation

Initial value:

Content information version 1 operations.

Definition at line 394 of file pccrc.c.

Referenced by peerdist_info().

Initial value:

Content information version 2 operations.

Definition at line 652 of file pccrc.c.

Referenced by peerdist_info().