iPXE
Functions | Variables
peermux.c File Reference

Peer Content Caching and Retrieval (PeerDist) protocol multiplexer. More...

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ipxe/uri.h>
#include <ipxe/xferbuf.h>
#include <ipxe/job.h>
#include <ipxe/peerblk.h>
#include <ipxe/peermux.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void peermux_free (struct refcnt *refcnt)
 Free PeerDist download multiplexer.
static void peermux_close (struct peerdist_multiplexer *peermux, int rc)
 Close PeerDist download multiplexer.
static int peermux_progress (struct peerdist_multiplexer *peermux, struct job_progress *progress)
 Report progress of PeerDist download.
static int peermux_info_deliver (struct peerdist_multiplexer *peermux, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive content information.
static void peermux_info_close (struct peerdist_multiplexer *peermux, int rc)
 Close content information interface.
static void peermux_step (struct peerdist_multiplexer *peermux)
 Initiate multiplexed block download.
static int peermux_block_deliver (struct peerdist_multiplexed_block *peermblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive data from multiplexed block download.
static struct xfer_bufferpeermux_block_buffer (struct peerdist_multiplexed_block *peermblk)
 Get multiplexed block download underlying data transfer buffer.
static void peermux_block_stat (struct peerdist_multiplexed_block *peermblk, struct peerdisc_peer *peer, struct list_head *peers)
 Record peer discovery statistics.
static void peermux_block_close (struct peerdist_multiplexed_block *peermblk, int rc)
 Close multiplexed block download.
int peermux_filter (struct interface *xfer, struct interface *info, struct uri *uri)
 Add PeerDist content-encoding filter.

Variables

static struct interface_operation peermux_xfer_operations []
 Data transfer interface operations.
static struct interface_descriptor peermux_xfer_desc
 Data transfer interface descriptor.
static struct interface_operation peermux_info_operations []
 Content information interface operations.
static struct interface_descriptor peermux_info_desc
 Content information interface descriptor.
static struct interface_operation peermux_block_operations []
 Block download data transfer interface operations.
static struct interface_descriptor peermux_block_desc
 Block download data transfer interface descriptor.
static struct process_descriptor peermux_process_desc
 Block download initiation process descriptor.

Detailed Description

Peer Content Caching and Retrieval (PeerDist) protocol multiplexer.

Definition in file peermux.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void peermux_free ( struct refcnt refcnt) [static]

Free PeerDist download multiplexer.

Parameters:
refcntReference count

Definition at line 46 of file peermux.c.

References peerdist_multiplexer::buffer, container_of, free, peerdist_multiplexer::uri, uri_put(), and xferbuf_free().

Referenced by peermux_filter().

                                                   {
        struct peerdist_multiplexer *peermux =
                container_of ( refcnt, struct peerdist_multiplexer, refcnt );

        uri_put ( peermux->uri );
        xferbuf_free ( &peermux->buffer );
        free ( peermux );
}
static void peermux_close ( struct peerdist_multiplexer peermux,
int  rc 
) [static]

Close PeerDist download multiplexer.

Parameters:
peermuxPeerDist download multiplexer
rcReason for close

Definition at line 61 of file peermux.c.

References peerdist_multiplexer::block, peerdist_multiplexer::info, intf_nullify(), intf_shutdown(), PEERMUX_MAX_BLOCKS, peerdist_multiplexer::process, process_del(), peerdist_multiplexed_block::xfer, and peerdist_multiplexer::xfer.

Referenced by peermux_block_close(), peermux_info_close(), peermux_info_deliver(), and peermux_step().

                                                                           {
        unsigned int i;

        /* Stop block download initiation process */
        process_del ( &peermux->process );

        /* Shut down all block downloads */
        for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ )
                intf_shutdown ( &peermux->block[i].xfer, rc );

        /* Shut down all other interfaces (which may be connected to
         * the same object).
         */
        intf_nullify ( &peermux->info ); /* avoid potential loops */
        intf_shutdown ( &peermux->xfer, rc );
        intf_shutdown ( &peermux->info, rc );
}
static int peermux_progress ( struct peerdist_multiplexer peermux,
struct job_progress progress 
) [static]

Report progress of PeerDist download.

Parameters:
peermuxPeerDist download multiplexer
progressProgress report to fill in
Return values:
ongoing_rcOngoing job status code (if known)

Definition at line 86 of file peermux.c.

References peerdist_statistics::local, job_progress::message, peerdist_statistics::peers, snprintf(), peerdist_multiplexer::stats, and peerdist_statistics::total.

                                                              {
        struct peerdist_statistics *stats = &peermux->stats;
        unsigned int percentage;

        /* Construct PeerDist status message */
        if ( stats->total ) {
                percentage = ( ( 100 * stats->local ) / stats->total );
                snprintf ( progress->message, sizeof ( progress->message ),
                           "%3d%% from %d peers", percentage, stats->peers );
        }

        return 0;
}
static int peermux_info_deliver ( struct peerdist_multiplexer peermux,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Receive content information.

Parameters:
peermuxPeerDist download multiplexer
iobufI/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 109 of file peermux.c.

References peerdist_multiplexer::buffer, peermux_close(), rc, and xferbuf_deliver().

                                                               {
        int rc;

        /* Add data to buffer */
        if ( ( rc = xferbuf_deliver ( &peermux->buffer, iobuf, meta ) ) != 0 )
                goto err;

        return 0;

 err:
        peermux_close ( peermux, rc );
        return rc;
}
static void peermux_info_close ( struct peerdist_multiplexer peermux,
int  rc 
) [static]

Close content information interface.

Parameters:
peermuxPeerDist download multiplexer
rcReason for close

Definition at line 131 of file peermux.c.

References peerdist_multiplexer::buffer, peerdist_multiplexer::cache, peerdist_raw::data, DBGC, peerdist_range::end, peerdist_info_cache::info, peerdist_multiplexer::info, info, intf_shutdown(), xfer_buffer::len, len, peermux_close(), peerdist_multiplexer::process, process_add(), peerdist_info::raw, peerdist_range::start, strerror(), peerdist_info::trim, peerdist_multiplexer::xfer, and xfer_seek().

                                                                               {
        struct peerdist_info *info = &peermux->cache.info;
        size_t len;

        /* Terminate download on error */
        if ( rc != 0 )
                goto err;

        /* Successfully closing the content information interface
         * indicates that the content information has been fully
         * received, and initiates the actual PeerDist download.
         */

        /* Shut down content information interface */
        intf_shutdown ( &peermux->info, rc );

        /* Parse content information */
        if ( ( rc = peerdist_info ( info->raw.data, peermux->buffer.len,
                                    info ) ) != 0 ) {
                DBGC ( peermux, "PEERMUX %p could not parse content info: %s\n",
                       peermux, strerror ( rc ) );
                goto err;
        }

        /* Notify recipient of total download size */
        len = ( info->trim.end - info->trim.start );
        if ( ( rc = xfer_seek ( &peermux->xfer, len ) ) != 0 ) {
                DBGC ( peermux, "PEERMUX %p could not presize buffer: %s\n",
                       peermux, strerror ( rc ) );
                goto err;
        }
        xfer_seek ( &peermux->xfer, 0 );

        /* Start block download process */
        process_add ( &peermux->process );

        return;

 err:
        peermux_close ( peermux, rc );
}
static void peermux_step ( struct peerdist_multiplexer peermux) [static]

Initiate multiplexed block download.

Parameters:
peermuxPeerDist download multiplexer

Definition at line 178 of file peermux.c.

References peerdist_info_cache::block, block, peerdist_info_segment::blocks, peerdist_multiplexer::busy, peerdist_multiplexer::cache, DBGC, peerdist_range::end, peerdist_multiplexer::idle, peerdist_info_segment::index, peerdist_info_block::index, peerdist_info_cache::info, info, peerdist_info_segment::info, peerdist_multiplexed_block::list, list_add_tail, list_del, list_empty, list_first_entry, peerblk_open(), peermux_close(), peerdist_multiplexer::process, process_del(), rc, peerdist_info_cache::segment, segment, peerdist_info::segments, peerdist_range::start, strerror(), peerdist_info_block::trim, peerdist_multiplexer::uri, and peerdist_multiplexed_block::xfer.

                                                                  {
        struct peerdist_info *info = &peermux->cache.info;
        struct peerdist_info_segment *segment = &peermux->cache.segment;
        struct peerdist_info_block *block = &peermux->cache.block;
        struct peerdist_multiplexed_block *peermblk;
        unsigned int next_segment;
        unsigned int next_block;
        int rc;

        /* Stop initiation process if all block downloads are busy */
        peermblk = list_first_entry ( &peermux->idle,
                                      struct peerdist_multiplexed_block, list );
        if ( ! peermblk ) {
                process_del ( &peermux->process );
                return;
        }

        /* Increment block index */
        next_block = ( block->index + 1 );

        /* Move to first/next segment, if applicable */
        if ( next_block >= segment->blocks ) {

                /* Reset block index */
                next_block = 0;

                /* Calculate segment index */
                next_segment = ( segment->info ? ( segment->index + 1 ) : 0 );

                /* If we have finished all segments and have no
                 * remaining block downloads, then we are finished.
                 */
                if ( next_segment >= info->segments ) {
                        process_del ( &peermux->process );
                        if ( list_empty ( &peermux->busy ) )
                                peermux_close ( peermux, 0 );
                        return;
                }

                /* Get content information segment */
                if ( ( rc = peerdist_info_segment ( info, segment,
                                                    next_segment ) ) != 0 ) {
                        DBGC ( peermux, "PEERMUX %p could not get segment %d "
                               "information: %s\n", peermux, next_segment,
                               strerror ( rc ) );
                        goto err;
                }
        }

        /* Get content information block */
        if ( ( rc = peerdist_info_block ( segment, block, next_block ) ) != 0 ){
                DBGC ( peermux, "PEERMUX %p could not get segment %d block "
                       "%d information: %s\n", peermux, segment->index,
                       next_block, strerror ( rc ) );
                goto err;
        }

        /* Ignore block if it lies entirely outside the trimmed range */
        if ( block->trim.start == block->trim.end ) {
                DBGC ( peermux, "PEERMUX %p skipping segment %d block %d\n",
                       peermux, segment->index, block->index );
                return;
        }

        /* Start downloading this block */
        if ( ( rc = peerblk_open ( &peermblk->xfer, peermux->uri,
                                   block ) ) != 0 ) {
                DBGC ( peermux, "PEERMUX %p could not start download for "
                       "segment %d block %d: %s\n", peermux, segment->index,
                       block->index, strerror ( rc ) );
                goto err;
        }

        /* Move to list of busy block downloads */
        list_del ( &peermblk->list );
        list_add_tail ( &peermblk->list, &peermux->busy );

        return;

 err:
        peermux_close ( peermux, rc );
}
static int peermux_block_deliver ( struct peerdist_multiplexed_block peermblk,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Receive data from multiplexed block download.

Parameters:
peermblkPeerDist multiplexed block download
iobufI/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 269 of file peermux.c.

References assert, xfer_metadata::flags, iob_disown, peerdist_multiplexed_block::peermux, peerdist_multiplexer::xfer, xfer_deliver(), and XFER_FL_ABS_OFFSET.

                                                                {
        struct peerdist_multiplexer *peermux = peermblk->peermux;

        /* Sanity check: all block downloads must use absolute
         * positions for all deliveries, since they run concurrently.
         */
        assert ( meta->flags & XFER_FL_ABS_OFFSET );

        /* We can't use a simple passthrough interface descriptor,
         * since there are multiple block download interfaces.
         */
        return xfer_deliver ( &peermux->xfer, iob_disown ( iobuf ), meta );
}
static struct xfer_buffer* peermux_block_buffer ( struct peerdist_multiplexed_block peermblk) [static, read]

Get multiplexed block download underlying data transfer buffer.

Parameters:
peermblkPeerDist multiplexed download block
Return values:
xferbufData transfer buffer, or NULL on error

Definition at line 292 of file peermux.c.

References peerdist_multiplexed_block::peermux, peerdist_multiplexer::xfer, and xfer_buffer().

                                                                     {
        struct peerdist_multiplexer *peermux = peermblk->peermux;

        /* We can't use a simple passthrough interface descriptor,
         * since there are multiple block download interfaces.
         */
        return xfer_buffer ( &peermux->xfer );
}
static void peermux_block_stat ( struct peerdist_multiplexed_block peermblk,
struct peerdisc_peer peer,
struct list_head peers 
) [static]

Record peer discovery statistics.

Parameters:
peermblkPeerDist multiplexed block download
peerSelected peer (or NULL)
peersList of available peers

Definition at line 308 of file peermux.c.

References count, DBGC2, peerdisc_peer::list, list_for_each_entry, peerdist_statistics::local, peerdist_multiplexed_block::peermux, peerdist_statistics::peers, peerdist_multiplexer::stats, and peerdist_statistics::total.

                                                           {
        struct peerdist_multiplexer *peermux = peermblk->peermux;
        struct peerdist_statistics *stats = &peermux->stats;
        struct peerdisc_peer *tmp;
        unsigned int count = 0;

        /* Record maximum number of available peers */
        list_for_each_entry ( tmp, peers, list )
                count++;
        if ( count > stats->peers )
                stats->peers = count;

        /* Update block counts */
        if ( peer )
                stats->local++;
        stats->total++;
        DBGC2 ( peermux, "PEERMUX %p downloaded %d/%d from %d peers\n",
                peermux, stats->local, stats->total, stats->peers );
}
static void peermux_block_close ( struct peerdist_multiplexed_block peermblk,
int  rc 
) [static]

Close multiplexed block download.

Parameters:
peermblkPeerDist multiplexed block download
rcReason for close

Definition at line 336 of file peermux.c.

References peerdist_multiplexer::idle, intf_restart(), peerdist_multiplexed_block::list, list_add_tail, list_del, peerdist_multiplexed_block::peermux, peermux_close(), peerdist_multiplexer::process, process_add(), and peerdist_multiplexed_block::xfer.

                                           {
        struct peerdist_multiplexer *peermux = peermblk->peermux;

        /* Move to list of idle downloads */
        list_del ( &peermblk->list );
        list_add_tail ( &peermblk->list, &peermux->idle );

        /* If any error occurred, terminate the whole multiplexer */
        if ( rc != 0 ) {
                peermux_close ( peermux, rc );
                return;
        }

        /* Restart data transfer interface */
        intf_restart ( &peermblk->xfer, rc );

        /* Restart block download initiation process */
        process_add ( &peermux->process );
}
int peermux_filter ( struct interface xfer,
struct interface info,
struct uri uri 
)

Add PeerDist content-encoding filter.

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

Definition at line 411 of file peermux.c.

References peerdist_multiplexer::block, peerdist_multiplexer::buffer, peerdist_multiplexer::busy, peerdist_multiplexer::cache, peerdist_raw::data, ENOMEM, peerdist_multiplexer::idle, peerdist_info_cache::info, peerdist_multiplexer::info, INIT_LIST_HEAD, intf_init(), intf_plug_plug(), peerdist_multiplexed_block::list, list_add_tail, peerdist_multiplexed_block::peermux, peermux_free(), PEERMUX_MAX_BLOCKS, peerdist_multiplexer::process, process_init_stopped(), peerdist_info::raw, ref_init, ref_put, peerdist_multiplexer::refcnt, peerdist_multiplexer::uri, uri_get(), peerdist_multiplexed_block::xfer, peerdist_multiplexer::xfer, and zalloc().

Referenced by http_peerdist_init().

                                       {
        struct peerdist_multiplexer *peermux;
        struct peerdist_multiplexed_block *peermblk;
        unsigned int i;

        /* Allocate and initialise structure */
        peermux = zalloc ( sizeof ( *peermux ) );
        if ( ! peermux )
                return -ENOMEM;
        ref_init ( &peermux->refcnt, peermux_free );
        intf_init ( &peermux->xfer, &peermux_xfer_desc, &peermux->refcnt );
        intf_init ( &peermux->info, &peermux_info_desc, &peermux->refcnt );
        peermux->uri = uri_get ( uri );
        xferbuf_umalloc_init ( &peermux->buffer,
                               &peermux->cache.info.raw.data );
        process_init_stopped ( &peermux->process, &peermux_process_desc,
                               &peermux->refcnt );
        INIT_LIST_HEAD ( &peermux->busy );
        INIT_LIST_HEAD ( &peermux->idle );
        for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ ) {
                peermblk = &peermux->block[i];
                peermblk->peermux = peermux;
                list_add_tail ( &peermblk->list, &peermux->idle );
                intf_init ( &peermblk->xfer, &peermux_block_desc,
                            &peermux->refcnt );
        }

        /* Attach to parent interfaces, mortalise self, and return */
        intf_plug_plug ( &peermux->xfer, xfer );
        intf_plug_plug ( &peermux->info, info );
        ref_put ( &peermux->refcnt );
        return 0;
}

Variable Documentation

Initial value:

Data transfer interface operations.

Definition at line 358 of file peermux.c.

Initial value:

Data transfer interface descriptor.

Definition at line 365 of file peermux.c.

Initial value:

Content information interface operations.

Definition at line 370 of file peermux.c.

Initial value:

Content information interface descriptor.

Definition at line 378 of file peermux.c.

Initial value:

Block download data transfer interface operations.

Definition at line 383 of file peermux.c.

Initial value:

Block download data transfer interface descriptor.

Definition at line 395 of file peermux.c.

Initial value:

Block download initiation process descriptor.

Definition at line 400 of file peermux.c.