mirror of
https://github.com/transmission/transmission
synced 2024-12-25 01:03:01 +00:00
879a2afcbd
The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli. Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.
274 lines
9.2 KiB
C
274 lines
9.2 KiB
C
/*
|
|
* This file Copyright (C) Mnemosyne LLC
|
|
*
|
|
* This file is licensed by the GPL version 2. Works owned by the
|
|
* Transmission project are granted a special exemption to clause 2(b)
|
|
* so that the bulk of its code can remain under the MIT license.
|
|
* This exemption does not extend to derived works not owned by
|
|
* the Transmission project.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#ifndef __TRANSMISSION__
|
|
#error only libtransmission should #include this header.
|
|
#endif
|
|
|
|
#ifndef TR_BANDWIDTH_H
|
|
#define TR_BANDWIDTH_H
|
|
|
|
#include "transmission.h"
|
|
#include "ptrarray.h"
|
|
#include "utils.h" /* tr_new(), tr_free() */
|
|
|
|
struct tr_peerIo;
|
|
|
|
/**
|
|
* @addtogroup networked_io Networked IO
|
|
* @{
|
|
*/
|
|
|
|
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
|
|
* it's included in the header for inlining and composition. */
|
|
enum
|
|
{
|
|
HISTORY_MSEC = 2000u,
|
|
INTERVAL_MSEC = HISTORY_MSEC,
|
|
GRANULARITY_MSEC = 200,
|
|
HISTORY_SIZE = ( INTERVAL_MSEC / GRANULARITY_MSEC ),
|
|
MAGIC_NUMBER = 43143
|
|
};
|
|
|
|
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
|
|
* it's included in the header for inlining and composition. */
|
|
struct bratecontrol
|
|
{
|
|
int newest;
|
|
struct { uint64_t date, size; } transfers[HISTORY_SIZE];
|
|
};
|
|
|
|
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
|
|
* it's included in the header for inlining and composition. */
|
|
struct tr_band
|
|
{
|
|
tr_bool isLimited;
|
|
tr_bool honorParentLimits;
|
|
unsigned int bytesLeft;
|
|
unsigned int desiredSpeed_Bps;
|
|
struct bratecontrol raw;
|
|
struct bratecontrol piece;
|
|
};
|
|
|
|
/**
|
|
* Bandwidth is an object for measuring and constraining bandwidth speeds.
|
|
*
|
|
* Bandwidth objects can be "stacked" so that a peer can be made to obey
|
|
* multiple constraints (for example, obeying the global speed limit and a
|
|
* per-torrent speed limit).
|
|
*
|
|
* HIERARCHY
|
|
*
|
|
* Transmission's bandwidth hierarchy is a tree.
|
|
* At the top is the global bandwidth object owned by tr_session.
|
|
* Its children are per-torrent bandwidth objects owned by tr_torrent.
|
|
* Underneath those are per-peer bandwidth objects owned by tr_peer.
|
|
*
|
|
* tr_session also owns a tr_handshake's bandwidths, so that the handshake
|
|
* I/O can be counted in the global raw totals. When the handshake is done,
|
|
* the bandwidth's ownership passes to a tr_peer.
|
|
*
|
|
* MEASURING
|
|
*
|
|
* When you ask a bandwidth object for its speed, it gives the speed of the
|
|
* subtree underneath it as well. So you can get Transmission's overall
|
|
* speed by quering tr_session's bandwidth, per-torrent speeds by asking
|
|
* tr_torrent's bandwidth, and per-peer speeds by asking tr_peer's bandwidth.
|
|
*
|
|
* CONSTRAINING
|
|
*
|
|
* Call tr_bandwidthAllocate() periodically. tr_bandwidth knows its current
|
|
* speed and will decide how many bytes to make available over the
|
|
* user-specified period to reach the user-specified desired speed.
|
|
* If appropriate, it notifies its peer-ios that new bandwidth is available.
|
|
*
|
|
* tr_bandwidthAllocate() operates on the tr_bandwidth subtree, so usually
|
|
* you'll only need to invoke it for the top-level tr_session bandwidth.
|
|
*
|
|
* The peer-ios all have a pointer to their associated tr_bandwidth object,
|
|
* and call tr_bandwidthClamp() before performing I/O to see how much
|
|
* bandwidth they can safely use.
|
|
*/
|
|
typedef struct tr_bandwidth
|
|
{
|
|
/* these are PRIVATE IMPLEMENTATION details that should not be touched.
|
|
* it's included in the header for inlining and composition. */
|
|
|
|
struct tr_band band[2];
|
|
struct tr_bandwidth * parent;
|
|
tr_priority_t priority;
|
|
int magicNumber;
|
|
tr_session * session;
|
|
tr_ptrArray children; /* struct tr_bandwidth */
|
|
struct tr_peerIo * peer;
|
|
}
|
|
tr_bandwidth;
|
|
|
|
|
|
/**
|
|
***
|
|
**/
|
|
|
|
tr_bandwidth* tr_bandwidthConstruct( tr_bandwidth * bandwidth,
|
|
tr_session * session,
|
|
tr_bandwidth * parent );
|
|
|
|
/** @brief create a new tr_bandwidth object */
|
|
static inline tr_bandwidth* tr_bandwidthNew( tr_session * session, tr_bandwidth * parent )
|
|
{
|
|
return tr_bandwidthConstruct( tr_new0( tr_bandwidth, 1 ), session, parent );
|
|
}
|
|
|
|
tr_bandwidth* tr_bandwidthDestruct( tr_bandwidth * bandwidth );
|
|
|
|
/** @brief free a tr_bandwidth object */
|
|
static inline void tr_bandwidthFree( tr_bandwidth * bandwidth )
|
|
{
|
|
tr_free( tr_bandwidthDestruct( bandwidth ) );
|
|
}
|
|
|
|
/** @brief test to see if the pointer refers to a live bandwidth object */
|
|
static inline tr_bool tr_isBandwidth( const tr_bandwidth * b )
|
|
{
|
|
return ( b != NULL ) && ( b->magicNumber == MAGIC_NUMBER );
|
|
}
|
|
|
|
/******
|
|
*******
|
|
******/
|
|
|
|
/**
|
|
* @brief Set the desired speed for this bandwidth subtree.
|
|
* @see tr_bandwidthAllocate
|
|
* @see tr_bandwidthGetDesiredSpeed
|
|
*/
|
|
static inline tr_bool tr_bandwidthSetDesiredSpeed_Bps( tr_bandwidth * bandwidth,
|
|
tr_direction dir,
|
|
unsigned int desiredSpeed )
|
|
{
|
|
unsigned int * value = &bandwidth->band[dir].desiredSpeed_Bps;
|
|
const tr_bool didChange = desiredSpeed != *value;
|
|
*value = desiredSpeed;
|
|
return didChange;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the desired speed for the bandwidth subtree.
|
|
* @see tr_bandwidthSetDesiredSpeed
|
|
*/
|
|
static inline double
|
|
tr_bandwidthGetDesiredSpeed_Bps( const tr_bandwidth * bandwidth, tr_direction dir )
|
|
{
|
|
return bandwidth->band[dir].desiredSpeed_Bps;
|
|
}
|
|
|
|
/**
|
|
* @brief Set whether or not this bandwidth should throttle its peer-io's speeds
|
|
*/
|
|
static inline tr_bool tr_bandwidthSetLimited( tr_bandwidth * bandwidth,
|
|
tr_direction dir,
|
|
tr_bool isLimited )
|
|
{
|
|
tr_bool * value = &bandwidth->band[dir].isLimited;
|
|
const tr_bool didChange = isLimited != *value;
|
|
*value = isLimited;
|
|
return didChange;
|
|
}
|
|
|
|
/**
|
|
* @return nonzero if this bandwidth throttles its peer-ios speeds
|
|
*/
|
|
static inline tr_bool tr_bandwidthIsLimited( const tr_bandwidth * bandwidth,
|
|
tr_direction dir )
|
|
{
|
|
return bandwidth->band[dir].isLimited;
|
|
}
|
|
|
|
/**
|
|
* @brief allocate the next period_msec's worth of bandwidth for the peer-ios to consume
|
|
*/
|
|
void tr_bandwidthAllocate ( tr_bandwidth * bandwidth,
|
|
tr_direction direction,
|
|
unsigned int period_msec );
|
|
|
|
/**
|
|
* @brief clamps byteCount down to a number that this bandwidth will allow to be consumed
|
|
*/
|
|
unsigned int tr_bandwidthClamp ( const tr_bandwidth * bandwidth,
|
|
tr_direction direction,
|
|
unsigned int byteCount );
|
|
|
|
/******
|
|
*******
|
|
******/
|
|
|
|
/** @brief Get the raw total of bytes read or sent by this bandwidth subtree. */
|
|
unsigned int tr_bandwidthGetRawSpeed_Bps( const tr_bandwidth * bandwidth,
|
|
const uint64_t now,
|
|
const tr_direction direction );
|
|
|
|
/** @brief Get the number of piece data bytes read or sent by this bandwidth subtree. */
|
|
unsigned int tr_bandwidthGetPieceSpeed_Bps( const tr_bandwidth * bandwidth,
|
|
const uint64_t now,
|
|
const tr_direction direction );
|
|
|
|
/**
|
|
* @brief Notify the bandwidth object that some of its allocated bandwidth has been consumed.
|
|
* This is is usually invoked by the peer-io after a read or write.
|
|
*/
|
|
void tr_bandwidthUsed ( tr_bandwidth * bandwidth,
|
|
tr_direction direction,
|
|
size_t byteCount,
|
|
tr_bool isPieceData,
|
|
uint64_t now );
|
|
|
|
/******
|
|
*******
|
|
******/
|
|
|
|
void tr_bandwidthSetParent ( tr_bandwidth * bandwidth,
|
|
tr_bandwidth * parent );
|
|
|
|
/**
|
|
* Almost all the time we do want to honor a parents' bandwidth cap, so that
|
|
* (for example) a peer is constrained by a per-torrent cap and the global cap.
|
|
* But when we set a torrent's speed mode to TR_SPEEDLIMIT_UNLIMITED, then
|
|
* in that particular case we want to ignore the global speed limit...
|
|
*/
|
|
static inline tr_bool tr_bandwidthHonorParentLimits ( tr_bandwidth * bandwidth,
|
|
tr_direction direction,
|
|
tr_bool isEnabled )
|
|
{
|
|
tr_bool * value = &bandwidth->band[direction].honorParentLimits;
|
|
const tr_bool didChange = isEnabled != *value;
|
|
*value = isEnabled;
|
|
return didChange;
|
|
}
|
|
|
|
static inline tr_bool tr_bandwidthAreParentLimitsHonored( tr_bandwidth * bandwidth,
|
|
tr_direction direction )
|
|
{
|
|
assert( tr_isBandwidth( bandwidth ) );
|
|
assert( tr_isDirection( direction ) );
|
|
|
|
return bandwidth->band[direction].honorParentLimits;
|
|
}
|
|
|
|
/******
|
|
*******
|
|
******/
|
|
|
|
void tr_bandwidthSetPeer( tr_bandwidth * bandwidth,
|
|
struct tr_peerIo * peerIo );
|
|
|
|
/* @} */
|
|
#endif
|