You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

peerdist.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdio.h>
  25. #include <ipxe/http.h>
  26. #include <ipxe/settings.h>
  27. #include <ipxe/peermux.h>
  28. /** @file
  29. *
  30. * Peer Content Caching and Retrieval (PeerDist) protocol
  31. *
  32. * This is quite possibly the ugliest protocol I have ever had the
  33. * misfortune to encounter, and I've encountered multicast TFTP.
  34. */
  35. /** PeerDist is globally enabled */
  36. static long peerdist_enabled = 1;
  37. /**
  38. * Check whether or not to support PeerDist encoding for this request
  39. *
  40. * @v http HTTP transaction
  41. * @ret supported PeerDist encoding is supported for this request
  42. */
  43. static int http_peerdist_supported ( struct http_transaction *http ) {
  44. /* Allow PeerDist to be globally enabled/disabled */
  45. if ( ! peerdist_enabled )
  46. return 0;
  47. /* Support PeerDist encoding only if we can directly access an
  48. * underlying data transfer buffer. Direct access is required
  49. * in order to support decryption of data received via the
  50. * retrieval protocol (which provides the AES initialisation
  51. * vector only after all of the encrypted data has been
  52. * received).
  53. *
  54. * This test simultaneously ensures that we do not attempt to
  55. * use PeerDist encoding on a request which is itself a
  56. * PeerDist individual block download, since the individual
  57. * block downloads do not themselves provide direct access to
  58. * an underlying data transfer buffer.
  59. */
  60. return ( xfer_buffer ( &http->xfer ) != NULL );
  61. }
  62. /**
  63. * Format HTTP "X-P2P-PeerDist" header
  64. *
  65. * @v http HTTP transaction
  66. * @v buf Buffer
  67. * @v len Length of buffer
  68. * @ret len Length of header value, or negative error
  69. */
  70. static int http_format_p2p_peerdist ( struct http_transaction *http,
  71. char *buf, size_t len ) {
  72. int supported = http_peerdist_supported ( http );
  73. int missing;
  74. /* PeerDist wants us to inform the server whenever we make a
  75. * request for data that was missing from local peers
  76. * (presumably for statistical purposes only). We use the
  77. * heuristic of assuming that the combination of "this request
  78. * may not itself use PeerDist content encoding" and "this is
  79. * a range request" probably indicates that we are making a
  80. * PeerDist block raw range request for missing data.
  81. */
  82. missing = ( http->request.range.len && ( ! supported ) );
  83. /* Omit header if PeerDist encoding is not supported and we
  84. * are not reporting a missing data request.
  85. */
  86. if ( ! ( supported || missing ) )
  87. return 0;
  88. /* Construct header */
  89. return snprintf ( buf, len, "Version=1.1%s",
  90. ( missing ? ", MissingDataRequest=true" : "" ) );
  91. }
  92. /** HTTP "X-P2P-PeerDist" header */
  93. struct http_request_header http_request_p2p_peerdist __http_request_header = {
  94. .name = "X-P2P-PeerDist",
  95. .format = http_format_p2p_peerdist,
  96. };
  97. /**
  98. * Format HTTP "X-P2P-PeerDistEx" header
  99. *
  100. * @v http HTTP transaction
  101. * @v buf Buffer
  102. * @v len Length of buffer
  103. * @ret len Length of header value, or negative error
  104. */
  105. static int http_format_p2p_peerdistex ( struct http_transaction *http,
  106. char *buf, size_t len ) {
  107. int supported = http_peerdist_supported ( http );
  108. /* Omit header if PeerDist encoding is not supported */
  109. if ( ! supported )
  110. return 0;
  111. /* Construct header */
  112. return snprintf ( buf, len, ( "MinContentInformation=1.0, "
  113. "MaxContentInformation=2.0" ) );
  114. }
  115. /** HTTP "X-P2P-PeerDist" header */
  116. struct http_request_header http_request_p2p_peerdistex __http_request_header = {
  117. .name = "X-P2P-PeerDistEx",
  118. .format = http_format_p2p_peerdistex,
  119. };
  120. /**
  121. * Initialise PeerDist content encoding
  122. *
  123. * @v http HTTP transaction
  124. * @ret rc Return status code
  125. */
  126. static int http_peerdist_init ( struct http_transaction *http ) {
  127. return peermux_filter ( &http->content, &http->transfer, http->uri );
  128. }
  129. /** PeerDist HTTP content encoding */
  130. struct http_content_encoding peerdist_encoding __http_content_encoding = {
  131. .name = "peerdist",
  132. .supported = http_peerdist_supported,
  133. .init = http_peerdist_init,
  134. };
  135. /** PeerDist enabled setting */
  136. const struct setting peerdist_setting __setting ( SETTING_MISC, peerdist ) = {
  137. .name = "peerdist",
  138. .description = "PeerDist enabled",
  139. .type = &setting_type_int8,
  140. };
  141. /**
  142. * Apply PeerDist settings
  143. *
  144. * @ret rc Return status code
  145. */
  146. static int apply_peerdist_settings ( void ) {
  147. /* Fetch global PeerDist enabled setting */
  148. if ( fetch_int_setting ( NULL, &peerdist_setting,
  149. &peerdist_enabled ) < 0 ) {
  150. peerdist_enabled = 1;
  151. }
  152. DBGC ( &peerdist_enabled, "PEERDIST is %s\n",
  153. ( peerdist_enabled ? "enabled" : "disabled" ) );
  154. return 0;
  155. }
  156. /** PeerDist settings applicator */
  157. struct settings_applicator peerdist_applicator __settings_applicator = {
  158. .apply = apply_peerdist_settings,
  159. };