DATA 01, bin_32, buffer
1K of data.
- ACK 02, bin_32
- ACKTS 08, bin_32, timestamp_32
+ ACK 02, bin_32, timestamp_32
+ HAVE 03, bin_32
Confirms successfull delivery of data. Used for
congestion control, as well.
- HINT 03, bin_32
+ HINT 08, bin_32
Practical value of "hints" is to avoid overlap, mostly.
Hints might be lost in the network or ignored.
Peer might send out data without a hint.
#ifndef SWIFT_H
#define SWIFT_H
-#ifdef _MSC_VER
-#include "compat/stdint.h"
-#else
-#include <stdint.h>
-#endif
#include <deque>
#include <vector>
#include <algorithm>
namespace swift {
#define NOW Datagram::now
-
+
/** tintbin is basically a pair<tint,bin64_t> plus some nice operators.
- Most frequently used in different queues (acknowledgements, requests,
+ Most frequently used in different queues (acknowledgements, requests,
etc). */
struct tintbin {
tint time;
tintbin() : time(TINT_NEVER), bin(bin64_t::NONE) {}
tintbin(tint time_, bin64_t bin_) : time(time_), bin(bin_) {}
tintbin(bin64_t bin_) : time(NOW), bin(bin_) {}
- bool operator < (const tintbin& b) const
+ bool operator < (const tintbin& b) const
{ return time > b.time; }
bool operator == (const tintbin& b) const
{ return time==b.time && bin==b.bin; }
SWIFT_HANDSHAKE = 0,
SWIFT_DATA = 1,
SWIFT_ACK = 2,
- SWIFT_TS = 8,
- SWIFT_HINT = 3,
+ SWIFT_HAVE = 3,
SWIFT_HASH = 4,
SWIFT_PEX_ADD = 5,
SWIFT_PEX_RM = 6,
SWIFT_SIGNED_HASH = 7,
- SWIFT_MSGTYPE_SENT = 8,
+ SWIFT_HINT = 8,
SWIFT_MSGTYPE_RCVD = 9,
SWIFT_MESSAGE_COUNT = 10
} messageid_t;
class PiecePicker;
class CongestionController;
class PeerSelector;
+ typedef void (*ProgressCallback) (int transfer, bin64_t bin);
/** A class representing single file transfer. */
public:
- /** A constructor. Open/submit/retrieve a file.
- * @param file_name the name of the file
+ /** A constructor. Open/submit/retrieve a file.
+ * @param file_name the name of the file
* @param root_hash the root hash of the file; zero hash if the file
is newly submitted */
FileTransfer(const char *file_name, const Sha1Hash& root_hash=Sha1Hash::ZERO);
/** Channels working for this transfer. */
binqueue hs_in_;
int hs_in_offset_;
- std::deque<Address> pex_in_;
+ std::deque<Address> pex_in_;
/** Messages we are accepting. */
uint64_t cap_out_;
-
+
tint init_time_;
+ #define SWFT_MAX_TRANSFER_CB 8
+ ProgressCallback callbacks[SWFT_MAX_TRANSFER_CB];
+ uint8_t cb_agg[SWFT_MAX_TRANSFER_CB];
+ int cb_installed;
+
public:
void OnDataIn (bin64_t pos);
void OnPexIn (const Address& addr);
friend uint64_t SeqComplete (int fdes);
friend int Open (const char* filename, const Sha1Hash& hash) ;
friend void Close (int fd) ;
+ friend void AddProgressCallback (int transfer,ProgressCallback cb,uint8_t agg);
+ friend void RemoveProgressCallback (int transfer,ProgressCallback cb);
+ friend void ExternallyRetrieved (int transfer,bin64_t piece);
};
public:
virtual void Randomize (uint64_t twist) = 0;
/** The piece picking method itself.
- * @param offered the daata acknowledged by the peer
+ * @param offered the daata acknowledged by the peer
* @param max_width maximum number of packets to ask for
* @param expires (not used currently) when to consider request expired
* @return the bin number to request */
virtual bin64_t Pick (binmap_t& offered, uint64_t max_width, tint expires) = 0;
+ virtual void LimitRange (bin64_t range) = 0;
+ virtual ~PiecePicker() {}
};
being transferred between two peers. As we don't need buffers and
lots of other TCP stuff, sizeof(Channel+members) must be below 1K.
Normally, API users do not deal with this class. */
- class Channel {
+ class Channel {
public:
- Channel (FileTransfer* file, int socket=-1, Address peer=Address());
+ Channel (FileTransfer* file, int socket=INVALID_SOCKET, Address peer=Address());
~Channel();
-
+
typedef enum {
KEEP_ALIVE_CONTROL,
PING_PONG_CONTROL,
SLOW_START_CONTROL,
AIMD_CONTROL,
- LEDBAT_CONTROL
+ LEDBAT_CONTROL,
+ CLOSE_CONTROL
} send_control_t;
-
+
static const char* SEND_CONTROL_MODES[];
- static Channel*
- RecvDatagram (int socket);
+ static void RecvDatagram (SOCKET socket);
static void Loop (tint till);
void Recv (Datagram& dgram);
void Send ();
+ void Close ();
void OnAck (Datagram& dgram);
- void OnTs (Datagram& dgram);
+ void OnHave (Datagram& dgram);
bin64_t OnData (Datagram& dgram);
void OnHint (Datagram& dgram);
void OnHash (Datagram& dgram);
void AddHandshake (Datagram& dgram);
bin64_t AddData (Datagram& dgram);
void AddAck (Datagram& dgram);
- void AddTs (Datagram& dgram);
+ void AddHave (Datagram& dgram);
void AddHint (Datagram& dgram);
void AddUncleHashes (Datagram& dgram, bin64_t pos);
void AddPeakHashes (Datagram& dgram);
tint SlowStartNextSendTime ();
tint AimdNextSendTime ();
tint LedbatNextSendTime ();
-
+
static int MAX_REORDERING;
static tint TIMEOUT;
static tint MIN_DEV;
static float LEDBAT_GAIN;
static tint LEDBAT_DELAY_BIN;
static bool SELF_CONN_OK;
-
+ static tint MAX_POSSIBLE_RTT;
+ static FILE* debug_file;
+
const std::string id_string () const;
/** A channel is "established" if had already sent and received packets. */
bool is_established () { return peer_channel_id_ && own_id_mentioned_; }
HashTree& file () { return transfer_->file(); }
const Address& peer() const { return peer_; }
tint ack_timeout () {
- return rtt_avg_ + std::max(dev_avg_,MIN_DEV)*4;
+ tint dev = dev_avg_ < MIN_DEV ? MIN_DEV : dev_avg_;
+ tint tmo = rtt_avg_ + dev * 4;
+ return tmo < 30*TINT_SEC ? tmo : 30*TINT_SEC;
}
uint32_t id () const { return id_; }
-
+
static int DecodeID(int scrambled);
static int EncodeID(int unscrambled);
static Channel* channel(int i) {
return i<channels.size()?channels[i]:NULL;
}
static void CloseTransfer (FileTransfer* trans);
- static SOCKET default_socket() { return sockets[0]; }
protected:
/** Channel id: index in the channel array. */
bin64_t data_in_dbl_;
/** The history of data sent and still unacknowledged. */
tbqueue data_out_;
+ /** Timeouted data (potentially to be retransmitted). */
+ tbqueue data_out_tmo_;
bin64_t data_out_cap_;
/** Index in the history array. */
- binmap_t ack_out_;
+ binmap_t have_out_;
/** Transmit schedule: in most cases filled with the peer's hints */
tbqueue hint_in_;
/** Hints sent (to detect and reschedule ignored hints). */
tint last_data_in_time_;
tint last_loss_time_;
tint next_send_time_;
- tint peer_send_time_;
/** Congestion window; TODO: int, bytes. */
float cwnd_;
/** Data sending interval. */
}
/** Get a request for one packet from the queue of peer's requests. */
bin64_t DequeueHint();
- void CleanDataOut (bin64_t acks_pos=bin64_t::NONE);
+ bin64_t ImposeHint();
+ void TimeoutDataOut ();
void CleanStaleHintOut();
void CleanHintOut(bin64_t pos);
void Reschedule();
static PeerSelector* peer_selector;
- static SOCKET sockets[8];
- static int socket_count;
static tint last_tick;
- static tbheap send_queue;
+ static tbheap send_queue;
static Address tracker;
static std::vector<Channel*> channels;
int Listen (Address addr);
/** Run send/receive loop for the specified amount of time. */
void Loop (tint till);
+ bool Listen3rdPartySocket (sckrwecb_t);
/** Stop listening to a port. */
void Shutdown (int sock_des=-1);
/** Returns the number of bytes that are complete sequentially, starting from the
beginning, till the first not-yet-retrieved packet. */
uint64_t SeqComplete (int fdes);
+ /***/
+ int Find (Sha1Hash hash);
+ void AddProgressCallback (int transfer,ProgressCallback cb,uint8_t agg);
+ void RemoveProgressCallback (int transfer,ProgressCallback cb);
+ void ExternallyRetrieved (int transfer,bin64_t piece);
//uint32_t Width (const tbinvec& v);
} // namespace end
+#ifndef SWIFT_MUTE
+#define dprintf(...) { if (Channel::debug_file) fprintf(Channel::debug_file,__VA_ARGS__); }
+#else
+#define dprintf(...) {}
+#endif
+#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#endif