1 /*
2 
3 Copyright (c) 2006-2018, Arvid Norberg
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #ifndef TORRENT_EXTENSIONS_HPP_INCLUDED
34 #define TORRENT_EXTENSIONS_HPP_INCLUDED
35 
36 #include "libtorrent/units.hpp"
37 #include "libtorrent/flags.hpp"
38 #include "libtorrent/peer_info.hpp" // for peer_source_flags_t
39 #include "libtorrent/torrent_status.hpp" // for torrent_status::state_t
40 
41 // OVERVIEW
42 //
43 // libtorrent has a plugin interface for implementing extensions to the protocol.
44 // These can be general extensions for transferring metadata or peer exchange
45 // extensions, or it could be used to provide a way to customize the protocol
46 // to fit a particular (closed) network.
47 //
48 // In short, the plugin interface makes it possible to:
49 //
50 // * register extension messages (sent in the extension handshake), see
51 //   extensions_.
52 // * add data and parse data from the extension handshake.
53 // * send extension messages and standard bittorrent messages.
54 // * override or block the handling of standard bittorrent messages.
55 // * save and restore state via the session state
56 // * see all alerts that are posted
57 //
58 // .. _extensions: extension_protocol.html
59 //
60 // a word of caution
61 // -----------------
62 //
63 // Writing your own plugin is a very easy way to introduce serious bugs such as
64 // dead locks and race conditions. Since a plugin has access to internal
65 // structures it is also quite easy to sabotage libtorrent's operation.
66 //
67 // All the callbacks are always called from the libtorrent network thread. In
68 // case portions of your plugin are called from other threads, typically the main
69 // thread, you cannot use any of the member functions on the internal structures
70 // in libtorrent, since those require being called from the libtorrent network
71 // thread . Furthermore, you also need to synchronize your own shared data
72 // within the plugin, to make sure it is not accessed at the same time from the
73 // libtorrent thread (through a callback). If you need to send out a message
74 // from another thread, it is advised to use an internal queue, and do the
75 // actual sending in ``tick()``.
76 //
77 // Since the plugin interface gives you easy access to internal structures, it
78 // is not supported as a stable API. Plugins should be considered specific to a
79 // specific version of libtorrent. Although, in practice the internals mostly
80 // don't change that dramatically.
81 //
82 //
83 // plugin-interface
84 // ================
85 //
86 // The plugin interface consists of three base classes that the plugin may
87 // implement. These are called plugin, torrent_plugin and peer_plugin.
88 // They are found in the ``<libtorrent/extensions.hpp>`` header.
89 //
90 // These plugins are instantiated for each session, torrent and possibly each peer,
91 // respectively.
92 //
93 // For plugins that only need per torrent state, it is enough to only implement
94 // ``torrent_plugin`` and pass a constructor function or function object to
95 // ``session::add_extension()`` or ``torrent_handle::add_extension()`` (if the
96 // torrent has already been started and you want to hook in the extension at
97 // run-time).
98 //
99 // The signature of the function is:
100 //
101 // .. code:: c++
102 //
103 // 	std::shared_ptr<torrent_plugin> (*)(torrent_handle const&, void*);
104 //
105 // The second argument is the userdata passed to ``session::add_torrent()`` or
106 // ``torrent_handle::add_extension()``.
107 //
108 // The function should return a ``std::shared_ptr<torrent_plugin>`` which
109 // may or may not be 0. If it is a nullptr, the extension is simply ignored
110 // for this torrent. If it is a valid pointer (to a class inheriting
111 // ``torrent_plugin``), it will be associated with this torrent and callbacks
112 // will be made on torrent events.
113 //
114 // For more elaborate plugins which require session wide state, you would
115 // implement ``plugin``, construct an object (in a ``std::shared_ptr``) and pass
116 // it in to ``session::add_extension()``.
117 //
118 // custom alerts
119 // =============
120 //
121 // Since plugins are running within internal libtorrent threads, one convenient
122 // way to communicate with the client is to post custom alerts.
123 //
124 // The expected interface of any alert, apart from deriving from the alert
125 // base class, looks like this:
126 //
127 // .. parsed-literal::
128 //
129 // 	static const int alert_type = *<unique alert ID>*;
130 // 	virtual int type() const { return alert_type; }
131 //
132 // 	virtual std::string message() const;
133 //
134 // 	static const alert_category_t static_category = *<bitmask of alert::category_t flags>*;
135 // 	virtual alert_category_t category() const { return static_category; }
136 //
137 // 	virtual char const* what() const { return *<string literal of the name of this alert>*; }
138 //
139 // The ``alert_type`` is used for the type-checking in ``alert_cast``. It must
140 // not collide with any other alert. The built-in alerts in libtorrent will
141 // not use alert type IDs greater than ``user_alert_id``. When defining your
142 // own alert, make sure it's greater than this constant.
143 //
144 // ``type()`` is the run-time equivalence of the ``alert_type``.
145 //
146 // The ``message()`` virtual function is expected to construct a useful
147 // string representation of the alert and the event or data it represents.
148 // Something convenient to put in a log file for instance.
149 //
150 // ``clone()`` is used internally to copy alerts. The suggested implementation
151 // of simply allocating a new instance as a copy of ``*this`` is all that's
152 // expected.
153 //
154 // The static category is required for checking whether or not the category
155 // for a specific alert is enabled or not, without instantiating the alert.
156 // The ``category`` virtual function is the run-time equivalence.
157 //
158 // The ``what()`` virtual function may simply be a string literal of the class
159 // name of your alert.
160 //
161 // For more information, see the `alert section`_.
162 //
163 // .. _`alert section`: reference-Alerts.html
164 
165 #include <vector>
166 
167 #include "libtorrent/config.hpp"
168 #include "libtorrent/fwd.hpp"
169 #include "libtorrent/span.hpp"
170 #include "libtorrent/sha1_hash.hpp"
171 #include "libtorrent/string_view.hpp"
172 #include "libtorrent/socket.hpp"
173 #include "libtorrent/error_code.hpp"
174 
175 namespace libtorrent {
176 
177 #ifndef TORRENT_DISABLE_EXTENSIONS
178 
179 	// these are flags that can be returned by implemented_features()
180 	// indicating which callbacks this plugin is interested in
181 	using feature_flags_t = flags::bitfield_flag<std::uint8_t, struct feature_flags_tag>;
182 
183 	// this is the base class for a session plugin. One primary feature
184 	// is that it is notified of all torrents that are added to the session,
185 	// and can add its own torrent_plugins.
186 	struct TORRENT_EXPORT plugin
187 	{
188 		// hidden
~pluginlibtorrent::plugin189 		virtual ~plugin() {}
190 
191 #if TORRENT_ABI_VERSION == 1
192 		using feature_flags_t = libtorrent::feature_flags_t;
193 #endif
194 
195 		// include this bit if your plugin needs to alter the order of the
196 		// optimistic unchoke of peers. i.e. have the on_optimistic_unchoke()
197 		// callback be called.
198 		static constexpr feature_flags_t optimistic_unchoke_feature = 1_bit;
199 
200 		// include this bit if your plugin needs to have on_tick() called
201 		static constexpr feature_flags_t tick_feature = 2_bit;
202 
203 		// include this bit if your plugin needs to have on_dht_request()
204 		// called
205 		static constexpr feature_flags_t dht_request_feature = 3_bit;
206 
207 		// include this bit if your plugin needs to have on_alert()
208 		// called
209 		static constexpr feature_flags_t alert_feature = 4_bit;
210 
211 		// This function is expected to return a bitmask indicating which features
212 		// this plugin implements. Some callbacks on this object may not be called
213 		// unless the corresponding feature flag is returned here. Note that
214 		// callbacks may still be called even if the corresponding feature is not
215 		// specified in the return value here. See feature_flags_t for possible
216 		// flags to return.
implemented_featureslibtorrent::plugin217 		virtual feature_flags_t implemented_features() { return {}; }
218 
219 		// this is called by the session every time a new torrent is added.
220 		// The ``torrent*`` points to the internal torrent object created
221 		// for the new torrent. The ``void*`` is the userdata pointer as
222 		// passed in via add_torrent_params.
223 		//
224 		// If the plugin returns a torrent_plugin instance, it will be added
225 		// to the new torrent. Otherwise, return an empty shared_ptr to a
226 		// torrent_plugin (the default).
new_torrentlibtorrent::plugin227 		virtual std::shared_ptr<torrent_plugin> new_torrent(torrent_handle const&, void*)
228 		{ return std::shared_ptr<torrent_plugin>(); }
229 
230 		// called when plugin is added to a session
addedlibtorrent::plugin231 		virtual void added(session_handle const&) {}
232 
233 		// called when a dht request is received.
234 		// If your plugin expects this to be called, make sure to include the flag
235 		// ``dht_request_feature`` in the return value from implemented_features().
on_dht_requestlibtorrent::plugin236 		virtual bool on_dht_request(string_view /* query */
237 			, udp::endpoint const& /* source */, bdecode_node const& /* message */
238 			, entry& /* response */)
239 		{ return false; }
240 
241 		// called when an alert is posted alerts that are filtered are not posted.
242 		// If your plugin expects this to be called, make sure to include the flag
243 		// ``alert_feature`` in the return value from implemented_features().
on_alertlibtorrent::plugin244 		virtual void on_alert(alert const*) {}
245 
246 		// return true if the add_torrent_params should be added
on_unknown_torrentlibtorrent::plugin247 		virtual bool on_unknown_torrent(sha1_hash const& /* info_hash */
248 			, peer_connection_handle const& /* pc */, add_torrent_params& /* p */)
249 		{ return false; }
250 
251 		// called once per second.
252 		// If your plugin expects this to be called, make sure to include the flag
253 		// ``tick_feature`` in the return value from implemented_features().
on_ticklibtorrent::plugin254 		virtual void on_tick() {}
255 
256 		// called when choosing peers to optimistically unchoke. The return value
257 		// indicates the peer's priority for unchoking. Lower return values
258 		// correspond to higher priority. Priorities above 2^63-1 are reserved.
259 		// If your plugin has no priority to assign a peer it should return 2^64-1.
260 		// If your plugin expects this to be called, make sure to include the flag
261 		// ``optimistic_unchoke_feature`` in the return value from implemented_features().
262 		// If multiple plugins implement this function the lowest return value
263 		// (i.e. the highest priority) is used.
get_unchoke_prioritylibtorrent::plugin264 		virtual uint64_t get_unchoke_priority(peer_connection_handle const& /* peer */)
265 		{ return (std::numeric_limits<uint64_t>::max)(); }
266 
267 		// called when saving settings state
save_statelibtorrent::plugin268 		virtual void save_state(entry&) {}
269 
270 		// called when loading settings state
load_statelibtorrent::plugin271 		virtual void load_state(bdecode_node const&) {}
272 	};
273 
274 	using add_peer_flags_t = flags::bitfield_flag<std::uint8_t, struct add_peer_flags_tag>;
275 
276 	// Torrent plugins are associated with a single torrent and have a number
277 	// of functions called at certain events. Many of its functions have the
278 	// ability to change or override the default libtorrent behavior.
279 	struct TORRENT_EXPORT torrent_plugin
280 	{
281 		// hidden
~torrent_pluginlibtorrent::torrent_plugin282 		virtual ~torrent_plugin() {}
283 
284 #if TORRENT_ABI_VERSION == 1
285 		using flags_t = libtorrent::add_peer_flags_t;
286 #endif
287 
288 		// This function is called each time a new peer is connected to the torrent. You
289 		// may choose to ignore this by just returning a default constructed
290 		// ``shared_ptr`` (in which case you don't need to override this member
291 		// function).
292 		//
293 		// If you need an extension to the peer connection (which most plugins do) you
294 		// are supposed to return an instance of your peer_plugin class. Which in
295 		// turn will have its hook functions called on event specific to that peer.
296 		//
297 		// The ``peer_connection_handle`` will be valid as long as the ``shared_ptr``
298 		// is being held by the torrent object. So, it is generally a good idea to not
299 		// keep a ``shared_ptr`` to your own peer_plugin. If you want to keep references
300 		// to it, use ``weak_ptr``.
301 		//
302 		// If this function throws an exception, the connection will be closed.
new_connectionlibtorrent::torrent_plugin303 		virtual std::shared_ptr<peer_plugin> new_connection(peer_connection_handle const&)
304 		{ return std::shared_ptr<peer_plugin>(); }
305 
306 		// These hooks are called when a piece passes the hash check or fails the hash
307 		// check, respectively. The ``index`` is the piece index that was downloaded.
308 		// It is possible to access the list of peers that participated in sending the
309 		// piece through the ``torrent`` and the ``piece_picker``.
on_piece_passlibtorrent::torrent_plugin310 		virtual void on_piece_pass(piece_index_t) {}
on_piece_failedlibtorrent::torrent_plugin311 		virtual void on_piece_failed(piece_index_t) {}
312 
313 		// This hook is called approximately once per second. It is a way of making it
314 		// easy for plugins to do timed events, for sending messages or whatever.
ticklibtorrent::torrent_plugin315 		virtual void tick() {}
316 
317 		// These hooks are called when the torrent is paused and resumed respectively.
318 		// The return value indicates if the event was handled. A return value of
319 		// ``true`` indicates that it was handled, and no other plugin after this one
320 		// will have this hook function called, and the standard handler will also not be
321 		// invoked. So, returning true effectively overrides the standard behavior of
322 		// pause or resume.
323 		//
324 		// Note that if you call ``pause()`` or ``resume()`` on the torrent from your
325 		// handler it will recurse back into your handler, so in order to invoke the
326 		// standard handler, you have to keep your own state on whether you want standard
327 		// behavior or overridden behavior.
on_pauselibtorrent::torrent_plugin328 		virtual bool on_pause() { return false; }
on_resumelibtorrent::torrent_plugin329 		virtual bool on_resume() { return false; }
330 
331 		// This function is called when the initial files of the torrent have been
332 		// checked. If there are no files to check, this function is called immediately.
333 		//
334 		// i.e. This function is always called when the torrent is in a state where it
335 		// can start downloading.
on_files_checkedlibtorrent::torrent_plugin336 		virtual void on_files_checked() {}
337 
338 		// called when the torrent changes state
339 		// the state is one of torrent_status::state_t
340 		// enum members
on_statelibtorrent::torrent_plugin341 		virtual void on_state(torrent_status::state_t) {}
342 
343 		// this is the first time we see this peer
344 		static constexpr add_peer_flags_t first_time = 1_bit;
345 
346 		// this peer was not added because it was
347 		// filtered by the IP filter
348 		static constexpr add_peer_flags_t filtered = 2_bit;
349 
350 		// called every time a new peer is added to the peer list.
351 		// This is before the peer is connected to. For ``flags``, see
352 		// torrent_plugin::flags_t. The ``source`` argument refers to
353 		// the source where we learned about this peer from. It's a
354 		// bitmask, because many sources may have told us about the same
355 		// peer. For peer source flags, see peer_info::peer_source_flags.
on_add_peerlibtorrent::torrent_plugin356 		virtual void on_add_peer(tcp::endpoint const&,
357 			peer_source_flags_t, add_peer_flags_t) {}
358 	};
359 
360 	// peer plugins are associated with a specific peer. A peer could be
361 	// both a regular bittorrent peer (``bt_peer_connection``) or one of the
362 	// web seed connections (``web_peer_connection`` or ``http_seed_connection``).
363 	// In order to only attach to certain peers, make your
364 	// torrent_plugin::new_connection only return a plugin for certain peer
365 	// connection types
366 	struct TORRENT_EXPORT peer_plugin
367 	{
368 		// hidden
~peer_pluginlibtorrent::peer_plugin369 		virtual ~peer_plugin() {}
370 
371 		// This function is expected to return the name of
372 		// the plugin.
typelibtorrent::peer_plugin373 		virtual string_view type() const { return {}; }
374 
375 		// can add entries to the extension handshake
376 		// this is not called for web seeds
add_handshakelibtorrent::peer_plugin377 		virtual void add_handshake(entry&) {}
378 
379 		// called when the peer is being disconnected.
on_disconnectlibtorrent::peer_plugin380 		virtual void on_disconnect(error_code const&) {}
381 
382 		// called when the peer is successfully connected. Note that
383 		// incoming connections will have been connected by the time
384 		// the peer plugin is attached to it, and won't have this hook
385 		// called.
on_connectedlibtorrent::peer_plugin386 		virtual void on_connected() {}
387 
388 		// throwing an exception from any of the handlers (except add_handshake)
389 		// closes the connection
390 
391 		// this is called when the initial bittorrent handshake is received.
392 		// Returning false means that the other end doesn't support this extension
393 		// and will remove it from the list of plugins. this is not called for web
394 		// seeds
on_handshakelibtorrent::peer_plugin395 		virtual bool on_handshake(span<char const>) { return true; }
396 
397 		// called when the extension handshake from the other end is received
398 		// if this returns false, it means that this extension isn't
399 		// supported by this peer. It will result in this peer_plugin
400 		// being removed from the peer_connection and destructed.
401 		// this is not called for web seeds
on_extension_handshakelibtorrent::peer_plugin402 		virtual bool on_extension_handshake(bdecode_node const&) { return true; }
403 
404 		// returning true from any of the message handlers
405 		// indicates that the plugin has handled the message.
406 		// it will break the plugin chain traversing and not let
407 		// anyone else handle the message, including the default
408 		// handler.
on_chokelibtorrent::peer_plugin409 		virtual bool on_choke() { return false; }
on_unchokelibtorrent::peer_plugin410 		virtual bool on_unchoke() { return false; }
on_interestedlibtorrent::peer_plugin411 		virtual bool on_interested() { return false; }
on_not_interestedlibtorrent::peer_plugin412 		virtual bool on_not_interested() { return false; }
on_havelibtorrent::peer_plugin413 		virtual bool on_have(piece_index_t) { return false; }
on_dont_havelibtorrent::peer_plugin414 		virtual bool on_dont_have(piece_index_t) { return false; }
on_bitfieldlibtorrent::peer_plugin415 		virtual bool on_bitfield(bitfield const& /*bitfield*/) { return false; }
on_have_alllibtorrent::peer_plugin416 		virtual bool on_have_all() { return false; }
on_have_nonelibtorrent::peer_plugin417 		virtual bool on_have_none() { return false; }
on_allowed_fastlibtorrent::peer_plugin418 		virtual bool on_allowed_fast(piece_index_t) { return false; }
on_requestlibtorrent::peer_plugin419 		virtual bool on_request(peer_request const&) { return false; }
420 
421 		// This function is called when the peer connection is receiving
422 		// a piece. ``buf`` points (non-owning pointer) to the data in an
423 		// internal immutable disk buffer. The length of the data is specified
424 		// in the ``length`` member of the ``piece`` parameter.
425 		// returns true to indicate that the piece is handled and the
426 		// rest of the logic should be ignored.
on_piecelibtorrent::peer_plugin427 		virtual bool on_piece(peer_request const& /*piece*/
428 			, span<char const> /*buf*/) { return false; }
429 
on_cancellibtorrent::peer_plugin430 		virtual bool on_cancel(peer_request const&) { return false; }
on_rejectlibtorrent::peer_plugin431 		virtual bool on_reject(peer_request const&) { return false; }
on_suggestlibtorrent::peer_plugin432 		virtual bool on_suggest(piece_index_t) { return false; }
433 
434 		// called after a choke message has been sent to the peer
sent_unchokelibtorrent::peer_plugin435 		virtual void sent_unchoke() {}
436 
437 		// called after piece data has been sent to the peer
438 		// this can be used for stats book keeping
sent_payloadlibtorrent::peer_plugin439 		virtual void sent_payload(int /* bytes */) {}
440 
441 		// called when libtorrent think this peer should be disconnected.
442 		// if the plugin returns false, the peer will not be disconnected.
can_disconnectlibtorrent::peer_plugin443 		virtual bool can_disconnect(error_code const& /*ec*/) { return true; }
444 
445 		// called when an extended message is received. If returning true,
446 		// the message is not processed by any other plugin and if false
447 		// is returned the next plugin in the chain will receive it to
448 		// be able to handle it. This is not called for web seeds.
449 		// thus function may be called more than once per incoming message, but
450 		// only the last of the calls will the ``body`` size equal the ``length``.
451 		// i.e. Every time another fragment of the message is received, this
452 		// function will be called, until finally the whole message has been
453 		// received. The purpose of this is to allow early disconnects for invalid
454 		// messages and for reporting progress of receiving large messages.
on_extendedlibtorrent::peer_plugin455 		virtual bool on_extended(int /*length*/, int /*msg*/,
456 			span<char const> /*body*/)
457 		{ return false; }
458 
459 		// this is not called for web seeds
on_unknown_messagelibtorrent::peer_plugin460 		virtual bool on_unknown_message(int /*length*/, int /*msg*/,
461 			span<char const> /*body*/)
462 		{ return false; }
463 
464 		// called when a piece that this peer participated in either
465 		// fails or passes the hash_check
on_piece_passlibtorrent::peer_plugin466 		virtual void on_piece_pass(piece_index_t) {}
on_piece_failedlibtorrent::peer_plugin467 		virtual void on_piece_failed(piece_index_t) {}
468 
469 		// called approximately once every second
ticklibtorrent::peer_plugin470 		virtual void tick() {}
471 
472 		// called each time a request message is to be sent. If true
473 		// is returned, the original request message won't be sent and
474 		// no other plugin will have this function called.
write_requestlibtorrent::peer_plugin475 		virtual bool write_request(peer_request const&) { return false; }
476 	};
477 #endif // TORRENT_DISABLE_EXTENSIONS
478 
479 #if !defined TORRENT_DISABLE_ENCRYPTION
480 
481 	struct TORRENT_EXPORT crypto_plugin
482 	{
483 		// hidden
~crypto_pluginlibtorrent::crypto_plugin484 		virtual ~crypto_plugin() {}
485 
486 		virtual void set_incoming_key(span<char const> key) = 0;
487 		virtual void set_outgoing_key(span<char const> key) = 0;
488 
489 		// encrypted the provided buffers and returns the number of bytes which
490 		// are now ready to be sent to the lower layer. This must be at least
491 		// as large as the number of bytes passed in and may be larger if there
492 		// is additional data to be inserted at the head of the send buffer.
493 		// The additional data is returned as the second tuple value. Any
494 		// returned buffer as well as the iovec itself, to be prepended to the
495 		// send buffer, must be owned by the crypto plugin and guaranteed to stay
496 		// alive until the crypto_plugin is destructed or this function is called
497 		// again.
498 		virtual std::tuple<int, span<span<char const>>>
499 		encrypt(span<span<char>> /*send_vec*/) = 0;
500 
501 		// decrypt the provided buffers.
502 		// returns is a tuple representing the values
503 		// (consume, produce, packet_size)
504 		//
505 		// consume is set to the number of bytes which should be trimmed from the
506 		// head of the buffers, default is 0
507 		//
508 		// produce is set to the number of bytes of payload which are now ready to
509 		// be sent to the upper layer. default is the number of bytes passed in receive_vec
510 		//
511 		// packet_size is set to the minimum number of bytes which must be read to
512 		// advance the next step of decryption. default is 0
513 		virtual std::tuple<int, int, int> decrypt(span<span<char>> /*receive_vec*/) = 0;
514 	};
515 
516 #endif // TORRENT_DISABLE_ENCRYPTION
517 }
518 
519 #endif // TORRENT_EXTENSIONS_HPP_INCLUDED
520