iPXE
peerdist.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdio.h>
00027 #include <ipxe/http.h>
00028 #include <ipxe/peermux.h>
00029 
00030 /** @file
00031  *
00032  * Peer Content Caching and Retrieval (PeerDist) protocol
00033  *
00034  * This is quite possibly the ugliest protocol I have ever had the
00035  * misfortune to encounter, and I've encountered multicast TFTP.
00036  */
00037 
00038 /**
00039  * Check whether or not to support PeerDist encoding for this request
00040  *
00041  * @v http              HTTP transaction
00042  * @ret supported       PeerDist encoding is supported for this request
00043  */
00044 static int http_peerdist_supported ( struct http_transaction *http ) {
00045 
00046         /* Support PeerDist encoding only if we can directly access an
00047          * underlying data transfer buffer.  Direct access is required
00048          * in order to support decryption of data received via the
00049          * retrieval protocol (which provides the AES initialisation
00050          * vector only after all of the encrypted data has been
00051          * received).
00052          *
00053          * This test simultaneously ensures that we do not attempt to
00054          * use PeerDist encoding on a request which is itself a
00055          * PeerDist individual block download, since the individual
00056          * block downloads do not themselves provide direct access to
00057          * an underlying data transfer buffer.
00058          */
00059         return ( xfer_buffer ( &http->xfer ) != NULL );
00060 }
00061 
00062 /**
00063  * Format HTTP "X-P2P-PeerDist" header
00064  *
00065  * @v http              HTTP transaction
00066  * @v buf               Buffer
00067  * @v len               Length of buffer
00068  * @ret len             Length of header value, or negative error
00069  */
00070 static int http_format_p2p_peerdist ( struct http_transaction *http,
00071                                       char *buf, size_t len ) {
00072         int supported = http_peerdist_supported ( http );
00073         int missing;
00074 
00075         /* PeerDist wants us to inform the server whenever we make a
00076          * request for data that was missing from local peers
00077          * (presumably for statistical purposes only).  We use the
00078          * heuristic of assuming that the combination of "this request
00079          * may not itself use PeerDist content encoding" and "this is
00080          * a range request" probably indicates that we are making a
00081          * PeerDist block raw range request for missing data.
00082          */
00083         missing = ( http->request.range.len && ( ! supported ) );
00084 
00085         /* Omit header if PeerDist encoding is not supported and we
00086          * are not reporting a missing data request.
00087          */
00088         if ( ! ( supported || missing ) )
00089                 return 0;
00090 
00091         /* Construct header */
00092         return snprintf ( buf, len, "Version=1.1%s",
00093                           ( missing ? ", MissingDataRequest=true" : "" ) );
00094 }
00095 
00096 /** HTTP "X-P2P-PeerDist" header */
00097 struct http_request_header http_request_p2p_peerdist __http_request_header = {
00098         .name = "X-P2P-PeerDist",
00099         .format = http_format_p2p_peerdist,
00100 };
00101 
00102 /**
00103  * Format HTTP "X-P2P-PeerDistEx" header
00104  *
00105  * @v http              HTTP transaction
00106  * @v buf               Buffer
00107  * @v len               Length of buffer
00108  * @ret len             Length of header value, or negative error
00109  */
00110 static int http_format_p2p_peerdistex ( struct http_transaction *http,
00111                                         char *buf, size_t len ) {
00112         int supported = http_peerdist_supported ( http );
00113 
00114         /* Omit header if PeerDist encoding is not supported */
00115         if ( ! supported )
00116                 return 0;
00117 
00118         /* Construct header */
00119         return snprintf ( buf, len, ( "MinContentInformation=1.0, "
00120                                       "MaxContentInformation=2.0" ) );
00121 }
00122 
00123 /** HTTP "X-P2P-PeerDist" header */
00124 struct http_request_header http_request_p2p_peerdistex __http_request_header = {
00125         .name = "X-P2P-PeerDistEx",
00126         .format = http_format_p2p_peerdistex,
00127 };
00128 
00129 /**
00130  * Initialise PeerDist content encoding
00131  *
00132  * @v http              HTTP transaction
00133  * @ret rc              Return status code
00134  */
00135 static int http_peerdist_init ( struct http_transaction *http ) {
00136 
00137         return peermux_filter ( &http->content, &http->transfer, http->uri );
00138 }
00139 
00140 /** PeerDist HTTP content encoding */
00141 struct http_content_encoding peerdist_encoding __http_content_encoding = {
00142         .name = "peerdist",
00143         .supported = http_peerdist_supported,
00144         .init = http_peerdist_init,
00145 };