merge encryption branch to trunk (xcode project is still out of date)
This commit is contained in:
parent
4932e8eb0e
commit
76da1185ca
|
@ -0,0 +1,175 @@
|
|||
######################################################
|
||||
### ----- Message Stream Encryption protocol ----- ###
|
||||
### specification by Ludde/uau/The_8472/Parg/Nolar ###
|
||||
######################################################
|
||||
|
||||
The following protocol describes a transparent wrapper for bidirectional
|
||||
data streams (e.g. TCP transports) that prevents passive eavesdroping
|
||||
and thus protocol or content identification.
|
||||
|
||||
It is also designed to provide limited protection against active MITM attacks
|
||||
and portscanning by requiring a weak shared secret to complete the handshake.
|
||||
You should note that the major design goal was payload and protocol obfuscation,
|
||||
not peer authentication and data integrity verification. Thus it does not offer
|
||||
protection against adversaries which already know the necessary data to establish
|
||||
connections (that is IP/Port/Shared Secret/Payload protocol).
|
||||
|
||||
To minimize the load on systems that employ this protocol fast cryptographic
|
||||
methods have been chosen over maximum-security algorithms.
|
||||
|
||||
|
||||
----------------
|
||||
- Declarations -
|
||||
----------------
|
||||
|
||||
The entire handshake is in big-endian.
|
||||
The crypto handshake is transparent to the next upper protocol,
|
||||
thus the payload endianness doesn't matter.
|
||||
|
||||
|
||||
A is the initiator of the underlying transport (e.g. a TCP connection)
|
||||
B is the receiver
|
||||
|
||||
##### DH Parameters
|
||||
|
||||
Prime P is a 768 bit safe prime, "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563"
|
||||
Generator G is "2"
|
||||
|
||||
Xa and Xb are a variable size random integers.
|
||||
They are the private key for each side and have to be discarded after
|
||||
the DH handshake is done. Minimum length is 128 bit. Anything beyond 180 bit
|
||||
is not believed to add any further security and only increases the necessary
|
||||
calculation time. You should use a length of 160bits whenever possible, lower
|
||||
values may be used when CPU time is scarce.
|
||||
|
||||
Pubkey of A: Ya = (G^Xa) mod P
|
||||
Pubkey of B: Yb = (G^Xb) mod P
|
||||
|
||||
DH secret: S = (Ya^Xb) mod P = (Yb^Xa) mod P
|
||||
|
||||
P, S, Ya and Yb are 768bits long
|
||||
|
||||
##### Constants/Variables
|
||||
|
||||
|
||||
PadA, PadB: Random data with a random length of 0 to 512 bytes each
|
||||
|
||||
PadC, PadD: Arbitrary data with a length of 0 to 512 bytes, can be
|
||||
used to extend the crypto handshake in future versions.
|
||||
Current implementations may choose to set them to 0-length.
|
||||
For padding-only usage in the current version they should be zeroed.
|
||||
|
||||
|
||||
VC is a verification constant that is used to verify whether the other
|
||||
side knows S and SKEY and thus defeats replay attacks of the SKEY hash.
|
||||
As of this version VC is a String of 8 bytes set to 0x00.
|
||||
|
||||
|
||||
crypto_provide and crypto_select are a 32bit bitfields.
|
||||
As of now 0x01 means plaintext, 0x02 means RC4. (see Functions)
|
||||
The remaining bits are reserved for future use.
|
||||
|
||||
The initiating peer A should provide all methods he supports in the bitfield,
|
||||
but he may choose only to provide higher encryption levels e.g. if plaintext
|
||||
isn't sufficient for it's security needs.
|
||||
The responding peer B should set a bit corresponding to the single method
|
||||
which he selected from the provided ones.
|
||||
|
||||
Bits with an unknown meaning in crypto_provide and crypto_select
|
||||
should be ignored as they might be used in future versions.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SKEY = Stream Identifier/Shared secret used to drop connections early if we
|
||||
don't have a matching stream. It's additionally used to harden the protocol
|
||||
against MITM attacks and portscanning.
|
||||
Protocols w/o unique stream properties may use a constant.
|
||||
Note: For BitTorrent, the SKEY should be the torrent info hash.
|
||||
|
||||
|
||||
IA = initial payload data from A
|
||||
may be 0-sized if you want to wait for the encryption negotation.
|
||||
|
||||
Peer A may buffer up to 65535 bytes before or during the DH handshake to append
|
||||
it to the 3rd step. IA is considered as atomic and thus an implementation may
|
||||
not expect that anything is handed to the upper layer before IA is completely
|
||||
transmitted. Thus there must be no blocking operations within IA.
|
||||
|
||||
Note, Example for Bittorrent:
|
||||
After \19Bittorrent protocol + the BT handshake a block occurs since A waits
|
||||
for B to send his handshake before A continues to send his bitfield,
|
||||
thus IA can only include the prefix + the bt handshake but not the bitfield
|
||||
|
||||
|
||||
###### Functions
|
||||
|
||||
len(X) specifies the length of X in 2 bytes.
|
||||
Thus the maximum length that can be specified is 65535 bytes, this is
|
||||
important for the IA block.
|
||||
|
||||
|
||||
ENCRYPT() is RC4, that uses one of the following keys to send data:
|
||||
"HASH('keyA', S, SKEY)" if you're A
|
||||
"HASH('keyB', S, SKEY)" if you're B
|
||||
The first 1024 bytes of the RC4 output are discarded.
|
||||
consecutive calls to ENCRYPT() by one side continue the encryption
|
||||
stream (no reinitialization, no keychange). They are only used to distinguish
|
||||
semantically seperate content.
|
||||
|
||||
|
||||
ENCRYPT2() is the negotiated crypto method.
|
||||
Current options are:
|
||||
0x01 Plaintext. After the specified length (see IA/IB) each side sends unencrypted payload
|
||||
0x02 RC4-128. The ENCRYPT() RC4 encoding is continued (no reinitialization, no keychange)
|
||||
|
||||
|
||||
HASH() is SHA1 binary output (20 bytes)
|
||||
|
||||
|
||||
###### The handshake "packet" format
|
||||
|
||||
|
||||
The handshake is seperated into 5 blocking steps.
|
||||
|
||||
1 A->B: Diffie Hellman Ya, PadA
|
||||
2 B->A: Diffie Hellman Yb, PadB
|
||||
3 A->B: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
|
||||
4 B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
|
||||
5 A->B: ENCRYPT2(Payload Stream)
|
||||
|
||||
|
||||
Since the length of PadA and PadB are unknown
|
||||
B will be able to resynchronize on HASH('req1', S)
|
||||
A will be able to resynchronize on ENCRYPT(VC)
|
||||
|
||||
|
||||
##### Optional early termination conditions
|
||||
(should verified before the indicated step is started).
|
||||
|
||||
If a fail-fast behavior is prefered the following conditions can be used to
|
||||
disconnect the peer immediately. If less recognizable patterns are preferred
|
||||
a peer may wait and disconnect at a later point. If any of these conditions
|
||||
are met the handshake can be considered as invalid.
|
||||
|
||||
2 (termination by B)
|
||||
if A sent less than 96 Bytes within 30 seconds
|
||||
if A sent more than 608 bytes
|
||||
|
||||
3 (termination by A)
|
||||
if B sent less than 96 Bytes within 30 seconds
|
||||
if B sent more than 608 bytes
|
||||
|
||||
4 (termination by B)
|
||||
if A didn't send the correct S hash within 628 bytes after the connection start (synchronisation point)
|
||||
if A didn't send a supported SKEY hash after the S hash
|
||||
if VC can't be decoded correctly after the SKEY hash
|
||||
if none of the crypto_provide options are supported or the bitfield is zeroed
|
||||
from here on it's up to the next protocol layer to terminate the connection
|
||||
|
||||
5 (termination by A)
|
||||
if VC can't be decoded correctly within 616 bytes after the connection start (synchronisation point)
|
||||
if the selected crypto method wasn't provided
|
||||
from here on it's up to the next protocol layer to terminate the connection
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
This file is here because I can never remember these commands...
|
||||
|
||||
svn propset svn:keywords 'Date Rev Author Id' filename
|
||||
|
||||
find . -type f \! -path \*.svn\* | xargs grep '\$Id\$'
|
|
@ -0,0 +1,53 @@
|
|||
/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
|
||||
|
||||
#ifdef __SUNPRO_C
|
||||
#pragma align 4 (my_pixbuf)
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
static const guint8 lock_icon[] __attribute__ ((__aligned__ (4))) =
|
||||
#else
|
||||
static const guint8 lock_icon[] =
|
||||
#endif
|
||||
{ ""
|
||||
/* Pixbuf magic (0x47646b50) */
|
||||
"GdkP"
|
||||
/* length: header (24) + pixel_data (643) */
|
||||
"\0\0\2\233"
|
||||
/* pixdata_type (0x2010002) */
|
||||
"\2\1\0\2"
|
||||
/* rowstride (64) */
|
||||
"\0\0\0@"
|
||||
/* width (16) */
|
||||
"\0\0\0\20"
|
||||
/* height (16) */
|
||||
"\0\0\0\20"
|
||||
/* pixel_data: */
|
||||
"\225\0\0\0\0\2\0\0\0i\0\0\0\273\202\0\0\0\306\3\0\0\0\301\0\0\0;\0\0"
|
||||
"\0\1\207\0\0\0\0\4\0\0\0\20\36\36\36\224zzz\373\322\322\322\377\202\333"
|
||||
"\333\333\377\4\274\274\274\376rrr\361\10\10\10\206\0\0\0\3\206\0\0\0"
|
||||
"\0\4\23\23\23~\204\204\204\374\276\276\276\367888\362\202\34\34\34\371"
|
||||
"\4MMM\374\261\261\261\377\204\204\204\366\0\0\0o\206\0\0\0\0\3---\353"
|
||||
"\302\302\302\375\11\11\11\336\204\0\0\0\0\3...\374\252\252\252\376\0"
|
||||
"\0\0\275\206\0\0\0\0\3+++\374\300\300\300\374\0\0\0\334\204\0\0\0\0\3"
|
||||
"\26\26\26\372\301\300\300\377\0\0\0\340\205\0\0\0\0\5\0\0\0`\23\21\16"
|
||||
"\370\233\227\224\377\40\35\34\377\13\13\7\377\202\4\3\2\377\7\5\4\3\377"
|
||||
"/)!\377\250\243\236\377\32\23\13\377\0\0\0`\0\0\0\0\0\0\0\1\202\0\0\0"
|
||||
"\0\3\0\0\0\377\245\221v\377\340\304\240\377\202\337\304\243\377\203\332"
|
||||
"\276\232\377\6\326\272\224\377\315\246v\377\201Z+\377\0\0\0\377\0\0\0"
|
||||
"\0\0\0\0\4\202\0\0\0\0\5\0\0\0\377\342\305\241\377\330\265\214\377\312"
|
||||
"\237h\377\254\207X\377\202\247\202R\377\7\247\202S\377\243{K\377\274"
|
||||
"\210I\377\254q.\377\0\0\0\377\0\0\0\0\0\0\0\5\202\0\0\0\0\5\0\0\0\377"
|
||||
"\343\306\242\377\325\256~\377\260\215_\377\325\262\204\377\202\317\253"
|
||||
"|\377\5\317\254{\377\313\244q\377\274\207F\377\252o+\377\0\0\0\377\204"
|
||||
"\0\0\0\0\5\0\0\0\377\341\304\240\377\320\246t\377\307\233d\377\252\204"
|
||||
"U\377\203\244~N\377\4\240wD\377\272\204B\377\254q.\377\0\0\0\377\204"
|
||||
"\0\0\0\0\5\0\0\0\377\341\302\234\377\316\244p\377\255\215d\377\322\262"
|
||||
"\211\377\202\315\254\203\377\5\316\255\203\377\314\247{\377\270\200>"
|
||||
"\377\255s2\377\0\0\0\377\204\0\0\0\0\5\0\0\0\377\340\302\236\377\324"
|
||||
"\254y\377\315\246n\377\257\215^\377\202\253\207X\377\5\253\210X\377\250"
|
||||
"\201L\377\274\207F\377\264~>\377\0\0\0\377\204\0\0\0\0\3\0\0\0\377\320"
|
||||
"\250t\377\306\226]\377\202\276\215P\377\202\272\211K\377\5\275\214N\377"
|
||||
"\274\212L\377\272\206G\377\244q6\377\0\0\0\377\204\0\0\0\0\1\0\0\0`\212"
|
||||
"\0\0\0\377\1\0\0\0w\222\0\0\0\0"};
|
||||
|
||||
|
12
gtk/main.c
12
gtk/main.c
|
@ -166,8 +166,6 @@ boolwindclosed(GtkWidget *widget, gpointer gdata);
|
|||
static GList *
|
||||
getselection( struct cbdata * cbdata );
|
||||
|
||||
static void
|
||||
safepipe(void);
|
||||
static void
|
||||
setupsighandlers(void);
|
||||
static void
|
||||
|
@ -228,7 +226,6 @@ main( int argc, char ** argv )
|
|||
GList * argfiles;
|
||||
gboolean didinit, didlock, sendquit, startpaused;
|
||||
|
||||
safepipe(); /* ignore SIGPIPE */
|
||||
argfiles = readargs( argc, argv, &sendquit, &startpaused );
|
||||
didinit = cf_init( tr_getPrefsDirectory(), NULL );
|
||||
didlock = FALSE;
|
||||
|
@ -1106,15 +1103,6 @@ doAction ( const char * action_name, gpointer user_data )
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
safepipe(void) {
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
setupsighandlers(void) {
|
||||
int sigs[] = {SIGHUP, SIGINT, SIGQUIT, SIGTERM};
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "actions.h"
|
||||
#include "tr_torrent.h"
|
||||
#include "dot-icons.h"
|
||||
#include "lock-icon.h"
|
||||
#include "hig.h"
|
||||
#include "torrent-inspector.h"
|
||||
#include "util.h"
|
||||
|
@ -236,6 +237,7 @@ enum
|
|||
PEER_COL_CLIENT,
|
||||
PEER_COL_PROGRESS,
|
||||
PEER_COL_IS_CONNECTED,
|
||||
PEER_COL_IS_ENCRYPTED,
|
||||
PEER_COL_IS_DOWNLOADING,
|
||||
PEER_COL_DOWNLOAD_RATE,
|
||||
PEER_COL_IS_UPLOADING,
|
||||
|
@ -250,6 +252,7 @@ static const char* peer_column_names[N_PEER_COLS] =
|
|||
N_("Client"),
|
||||
N_("Progress"),
|
||||
" ",
|
||||
" ",
|
||||
N_("Downloading"),
|
||||
N_("DL Rate"),
|
||||
N_("Uploading"),
|
||||
|
@ -283,6 +286,7 @@ peer_row_set (GtkTreeStore * store,
|
|||
PEER_COL_ADDRESS, peer->addr,
|
||||
PEER_COL_PORT, peer->port,
|
||||
PEER_COL_CLIENT, client,
|
||||
PEER_COL_IS_ENCRYPTED, peer->isEncrypted,
|
||||
PEER_COL_PROGRESS, (int)(100.0*peer->progress + 0.5),
|
||||
PEER_COL_IS_CONNECTED, peer->isConnected,
|
||||
PEER_COL_IS_DOWNLOADING, peer->isDownloading,
|
||||
|
@ -314,6 +318,7 @@ peer_model_new (tr_torrent_t * tor)
|
|||
G_TYPE_STRING, /* client */
|
||||
G_TYPE_INT, /* progress [0..100] */
|
||||
G_TYPE_BOOLEAN, /* isConnected */
|
||||
G_TYPE_BOOLEAN, /* isEncrypted */
|
||||
G_TYPE_BOOLEAN, /* isDownloading */
|
||||
G_TYPE_FLOAT, /* downloadFromRate */
|
||||
G_TYPE_BOOLEAN, /* isUploading */
|
||||
|
@ -347,6 +352,24 @@ render_connection (GtkTreeViewColumn * column UNUSED,
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
render_encrypted (GtkTreeViewColumn * column UNUSED,
|
||||
GtkCellRenderer * renderer,
|
||||
GtkTreeModel * tree_model,
|
||||
GtkTreeIter * iter,
|
||||
gpointer data UNUSED)
|
||||
{
|
||||
static GdkPixbuf * lock = NULL;
|
||||
gboolean is_encrypted = FALSE;
|
||||
gtk_tree_model_get (tree_model, iter, PEER_COL_IS_ENCRYPTED, &is_encrypted,
|
||||
-1);
|
||||
if (!lock) lock = gdk_pixbuf_new_from_inline (-1, lock_icon, FALSE, NULL);
|
||||
g_object_set (renderer, "xalign", (gfloat)0.0,
|
||||
"yalign", (gfloat)0.5,
|
||||
"pixbuf", (is_encrypted ? lock : NULL),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
render_ul_rate (GtkTreeViewColumn * column UNUSED,
|
||||
GtkCellRenderer * renderer,
|
||||
|
@ -494,6 +517,7 @@ static GtkWidget* peer_page_new ( TrTorrent * gtor )
|
|||
|
||||
/* TODO: make this configurable? */
|
||||
int view_columns[] = { PEER_COL_IS_CONNECTED,
|
||||
PEER_COL_IS_ENCRYPTED,
|
||||
PEER_COL_ADDRESS,
|
||||
PEER_COL_CLIENT,
|
||||
PEER_COL_PROGRESS,
|
||||
|
@ -538,6 +562,16 @@ static GtkWidget* peer_page_new ( TrTorrent * gtor )
|
|||
_("Progress"), r, "value", PEER_COL_PROGRESS, NULL);
|
||||
break;
|
||||
|
||||
case PEER_COL_IS_ENCRYPTED:
|
||||
resizable = FALSE;
|
||||
r = gtk_cell_renderer_pixbuf_new ();
|
||||
c = gtk_tree_view_column_new_with_attributes (t, r, NULL);
|
||||
gtk_tree_view_column_set_sizing (c, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||
gtk_tree_view_column_set_fixed_width (c, 32);
|
||||
gtk_tree_view_column_set_cell_data_func (c, r, render_encrypted,
|
||||
NULL, NULL);
|
||||
break;
|
||||
|
||||
case PEER_COL_IS_CONNECTED:
|
||||
resizable = FALSE;
|
||||
r = gtk_cell_renderer_pixbuf_new ();
|
||||
|
|
|
@ -9,12 +9,13 @@ EXTRA_DIST = version.h.in
|
|||
libtransmission_a_SOURCES = \
|
||||
basename.c \
|
||||
bencode.c \
|
||||
choking.c \
|
||||
clients.c \
|
||||
completion.c \
|
||||
crypto.c \
|
||||
dirname.c \
|
||||
fastresume.c \
|
||||
fdlimit.c \
|
||||
handshake.c \
|
||||
http.c \
|
||||
inout.c \
|
||||
ipcparse.c \
|
||||
|
@ -23,16 +24,16 @@ libtransmission_a_SOURCES = \
|
|||
metainfo.c \
|
||||
natpmp.c \
|
||||
net.c \
|
||||
peer.c \
|
||||
peer-io.c \
|
||||
peer-mgr.c \
|
||||
peer-msgs.c \
|
||||
platform.c \
|
||||
ptrarray.c \
|
||||
publish.c \
|
||||
ratecontrol.c \
|
||||
sha1.c \
|
||||
shared.c \
|
||||
strlcat.c \
|
||||
strlcpy.c \
|
||||
timer.c \
|
||||
torrent.c \
|
||||
tracker.c \
|
||||
transmission.c \
|
||||
|
@ -45,11 +46,12 @@ noinst_HEADERS = \
|
|||
bencode.h \
|
||||
bsdqueue.h \
|
||||
bsdtree.h \
|
||||
choking.h \
|
||||
clients.h \
|
||||
crypto.h \
|
||||
completion.h \
|
||||
fastresume.h \
|
||||
fdlimit.h \
|
||||
handshake.h \
|
||||
http.h \
|
||||
inout.h \
|
||||
internal.h \
|
||||
|
@ -59,20 +61,15 @@ noinst_HEADERS = \
|
|||
metainfo.h \
|
||||
natpmp.h \
|
||||
net.h \
|
||||
peeraz.h \
|
||||
peerext.h \
|
||||
peer.h \
|
||||
peermessages.h \
|
||||
peerparse.h \
|
||||
peertree.h \
|
||||
peerutils.h \
|
||||
peer-io.h \
|
||||
peer-mgr.h \
|
||||
peer-mgr-private.h \
|
||||
peer-msgs.h \
|
||||
platform.h \
|
||||
ptrarray.h \
|
||||
publish.h \
|
||||
ratecontrol.h \
|
||||
sha1.h \
|
||||
shared.h \
|
||||
timer.h \
|
||||
tracker.h \
|
||||
transmission.h \
|
||||
trcompat.h \
|
||||
|
|
|
@ -364,7 +364,7 @@ benc_val_t * tr_bencListAdd( benc_val_t * list )
|
|||
{
|
||||
benc_val_t * item;
|
||||
|
||||
assert( TYPE_LIST == list->type );
|
||||
assert( tr_bencIsList( list ) );
|
||||
assert( list->val.l.count < list->val.l.alloc );
|
||||
|
||||
item = &list->val.l.vals[list->val.l.count];
|
||||
|
@ -378,7 +378,7 @@ benc_val_t * tr_bencDictAdd( benc_val_t * dict, const char * key )
|
|||
{
|
||||
benc_val_t * keyval, * itemval;
|
||||
|
||||
assert( TYPE_DICT == dict->type );
|
||||
assert( tr_bencIsDict( dict ) );
|
||||
assert( dict->val.l.count + 2 <= dict->val.l.alloc );
|
||||
|
||||
keyval = dict->val.l.vals + dict->val.l.count++;
|
||||
|
@ -479,3 +479,31 @@ int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
int
|
||||
tr_bencIsStr ( const benc_val_t * val )
|
||||
{
|
||||
return val!=NULL && val->type==TYPE_STR;
|
||||
}
|
||||
|
||||
int
|
||||
tr_bencIsInt ( const benc_val_t * val )
|
||||
{
|
||||
return val!=NULL && val->type==TYPE_INT;
|
||||
}
|
||||
|
||||
int
|
||||
tr_bencIsList( const benc_val_t * val )
|
||||
{
|
||||
return val!=NULL && val->type==TYPE_LIST;
|
||||
}
|
||||
|
||||
int
|
||||
tr_bencIsDict( const benc_val_t * val )
|
||||
{
|
||||
return val!=NULL && val->type==TYPE_DICT;
|
||||
}
|
||||
|
|
|
@ -90,4 +90,9 @@ char * tr_bencSaveMalloc( benc_val_t * val, int * len );
|
|||
int tr_bencSave( benc_val_t * val, char ** buf,
|
||||
int * used, int * max );
|
||||
|
||||
int tr_bencIsStr ( const benc_val_t * val );
|
||||
int tr_bencIsInt ( const benc_val_t * val );
|
||||
int tr_bencIsList ( const benc_val_t * val );
|
||||
int tr_bencIsDict ( const benc_val_t * val );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,323 +0,0 @@
|
|||
/******************************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2006 Transmission authors and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "choking.h"
|
||||
#include "peer.h"
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef HAVE_LRINTF
|
||||
# define lrintf(a) ((int)(0.5+(a)))
|
||||
#endif
|
||||
|
||||
struct tr_choking_s
|
||||
{
|
||||
tr_lock_t * lock;
|
||||
tr_handle_t * h;
|
||||
int slots;
|
||||
};
|
||||
|
||||
tr_choking_t * tr_chokingInit( tr_handle_t * h )
|
||||
{
|
||||
tr_choking_t * c;
|
||||
|
||||
c = tr_new0( tr_choking_t, 1 );
|
||||
c->h = h;
|
||||
c->slots = 4242;
|
||||
c->lock = tr_lockNew( );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void tr_chokingSetLimit( tr_choking_t * c, int limit )
|
||||
{
|
||||
tr_lockLock( c->lock );
|
||||
if( limit < 0 )
|
||||
c->slots = 4242;
|
||||
else
|
||||
/* Reckon a number of slots from the upload limit. There is no
|
||||
official right way to do this, the formula below e.g. gives:
|
||||
10 KB/s -> 4 * 2.50 KB/s
|
||||
20 KB/s -> 6 * 3.33 KB/s
|
||||
50 KB/s -> 10 * 5.00 KB/s
|
||||
100 KB/s -> 14 * 7.14 KB/s */
|
||||
c->slots = lrintf( sqrt( 2 * limit ) );
|
||||
tr_lockUnlock( c->lock );
|
||||
}
|
||||
|
||||
#define sortPeersAscending(a,ac,z,zc,n,nc) sortPeers(a,ac,z,zc,n,nc,0)
|
||||
#define sortPeersDescending(a,ac,z,zc,n,nc) sortPeers(a,ac,z,zc,n,nc,1)
|
||||
static void sortPeers( tr_peer_t ** all, int allCount,
|
||||
tr_peer_t ** zero, int * zeroCount,
|
||||
tr_peer_t ** nonZero, int * nonZeroCount,
|
||||
int order )
|
||||
{
|
||||
int i, shuffle;
|
||||
|
||||
/* Seperate uploaders from non-uploaders */
|
||||
*zeroCount = 0;
|
||||
*nonZeroCount = 0;
|
||||
for( i = 0; i < allCount; i++ )
|
||||
{
|
||||
if( tr_peerDownloadRate( all[i] ) < 0.1 )
|
||||
zero[(*zeroCount)++] = all[i];
|
||||
else
|
||||
nonZero[(*nonZeroCount)++] = all[i];
|
||||
}
|
||||
|
||||
/* Randomly shuffle non-uploaders, so they are treated equally */
|
||||
if( *zeroCount && ( shuffle = tr_rand( *zeroCount ) ) )
|
||||
{
|
||||
tr_peer_t ** bak = tr_new( tr_peer_t*, shuffle );;
|
||||
memcpy( bak, zero, shuffle * sizeof( tr_peer_t * ) );
|
||||
memmove( zero, &zero[shuffle],
|
||||
( *zeroCount - shuffle ) * sizeof( tr_peer_t * ) );
|
||||
memcpy( &zero[*zeroCount - shuffle], bak,
|
||||
shuffle * sizeof( tr_peer_t * ) );
|
||||
tr_free( bak );
|
||||
}
|
||||
|
||||
/* Sort uploaders by download rate */
|
||||
for( i = *nonZeroCount - 1; i > 0; i-- )
|
||||
{
|
||||
float rate1, rate2;
|
||||
tr_peer_t * tmp;
|
||||
int j, sorted;
|
||||
|
||||
sorted = 1;
|
||||
for( j = 0; j < i; j++ )
|
||||
{
|
||||
rate1 = tr_peerDownloadRate( nonZero[j] );
|
||||
rate2 = tr_peerDownloadRate( nonZero[j+1] );
|
||||
if( order ? ( rate1 < rate2 ) : ( rate1 > rate2 ) )
|
||||
{
|
||||
tmp = nonZero[j];
|
||||
nonZero[j] = nonZero[j+1];
|
||||
nonZero[j+1] = tmp;
|
||||
sorted = 0;
|
||||
}
|
||||
}
|
||||
if( sorted )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tr_chokingPulse( tr_choking_t * c )
|
||||
{
|
||||
int peersTotalCount, unchoked, mustOptimistic = 1;
|
||||
tr_peer_t ** canChoke, ** canUnchoke;
|
||||
tr_peer_t ** canChokeZero, ** canUnchokeZero;
|
||||
tr_peer_t ** canChokeNonZero, ** canUnchokeNonZero;
|
||||
int canChokeCount, canUnchokeCount;
|
||||
int canChokeZeroCount, canUnchokeZeroCount;
|
||||
int canChokeNonZeroCount, canUnchokeNonZeroCount;
|
||||
tr_torrent_t * tor;
|
||||
uint64_t now = tr_date();
|
||||
|
||||
tr_lockLock( c->lock );
|
||||
|
||||
/* Lock all torrents and get the total number of peers */
|
||||
peersTotalCount = 0;
|
||||
for( tor = c->h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_torrentWriterLock( tor );
|
||||
peersTotalCount += tor->peerCount;
|
||||
}
|
||||
|
||||
canChoke = tr_new( tr_peer_t*, peersTotalCount );
|
||||
canUnchoke = tr_new( tr_peer_t*, peersTotalCount );
|
||||
canChokeCount = 0;
|
||||
canUnchokeCount = 0;
|
||||
unchoked = 0;
|
||||
|
||||
for( tor = c->h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_peer_t * peer;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < tor->peerCount; i++ )
|
||||
{
|
||||
peer = tor->peers[i];
|
||||
|
||||
if( !tr_peerIsConnected( peer ) )
|
||||
continue;
|
||||
|
||||
/* Choke peers who have lost their interest in us */
|
||||
if( !tr_peerIsInterested( peer ) )
|
||||
{
|
||||
if( !tr_peerIsChokedByUs( peer ) )
|
||||
{
|
||||
tr_peerChoke( peer );
|
||||
tr_peerSetOptimistic( peer, 0 );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build two lists of interested peers: those we may choke,
|
||||
those we may unchoke. Whatever happens, we never choke a
|
||||
peer less than 10 seconds after the time we unchoked him
|
||||
(or the other way around). */
|
||||
if( tr_peerIsChokedByUs( peer ) )
|
||||
{
|
||||
if( !tr_peerTimesChoked(peer) || tr_peerLastChoke( peer ) + 10000 < now )
|
||||
canUnchoke[canUnchokeCount++] = peer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( tr_peerIsOptimistic( peer ) )
|
||||
{
|
||||
if( tr_peerLastChoke( peer ) + 30000 < now )
|
||||
{
|
||||
/* He got his 30 seconds, now we see him like
|
||||
any other unchoked peer */
|
||||
tr_peerSetOptimistic( peer, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep him unchoked for 30 seconds */
|
||||
mustOptimistic = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unchoked++;
|
||||
if( tr_peerLastChoke( peer ) + 10000 < now )
|
||||
canChoke[canChokeCount++] = peer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canChokeZero = tr_new( tr_peer_t*, canChokeCount );
|
||||
canChokeNonZero = tr_new( tr_peer_t*, canChokeCount );
|
||||
canUnchokeZero = tr_new( tr_peer_t*, canUnchokeCount );
|
||||
canUnchokeNonZero = tr_new( tr_peer_t*, canUnchokeCount );
|
||||
|
||||
sortPeersDescending( canChoke, canChokeCount,
|
||||
canChokeZero, &canChokeZeroCount,
|
||||
canChokeNonZero, &canChokeNonZeroCount);
|
||||
sortPeersAscending( canUnchoke, canUnchokeCount,
|
||||
canUnchokeZero, &canUnchokeZeroCount,
|
||||
canUnchokeNonZero, &canUnchokeNonZeroCount);
|
||||
|
||||
tr_free( canChoke );
|
||||
tr_free( canUnchoke );
|
||||
|
||||
if( mustOptimistic )
|
||||
{
|
||||
tr_peer_t * peer;
|
||||
|
||||
/* Open an extra slot for optimistic choking */
|
||||
if( canUnchokeZeroCount )
|
||||
{
|
||||
/* TODO: prefer peers with no pieces at all */
|
||||
peer = canUnchokeZero[--canUnchokeZeroCount];
|
||||
tr_peerUnchoke( peer );
|
||||
tr_peerSetOptimistic( peer, 1 );
|
||||
}
|
||||
else if( canUnchokeNonZeroCount )
|
||||
{
|
||||
peer = canUnchokeNonZero[--canUnchokeNonZeroCount];
|
||||
tr_peerUnchoke( peer );
|
||||
tr_peerSetOptimistic( peer, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have more open slots than what we should have (the user has
|
||||
just lowered his upload limit), we need to choke some of the
|
||||
peers we are uploading to. We start with the peers who aren't
|
||||
uploading to us, then those we upload the least. */
|
||||
while( unchoked > c->slots && canChokeZeroCount > 0 )
|
||||
{
|
||||
tr_peerChoke( canChokeZero[--canChokeZeroCount] );
|
||||
unchoked--;
|
||||
}
|
||||
while( unchoked > c->slots && canChokeNonZeroCount > 0 )
|
||||
{
|
||||
tr_peerChoke( canChokeNonZero[--canChokeNonZeroCount] );
|
||||
unchoked--;
|
||||
}
|
||||
|
||||
/* If we have unused open slots, let's unchoke some people. We start
|
||||
with the peers who are uploading to us the most. */
|
||||
while( unchoked < c->slots && canUnchokeNonZeroCount > 0 )
|
||||
{
|
||||
tr_peerUnchoke( canUnchokeNonZero[--canUnchokeNonZeroCount] );
|
||||
unchoked++;
|
||||
}
|
||||
while( unchoked < c->slots && canUnchokeZeroCount > 0 )
|
||||
{
|
||||
tr_peerUnchoke( canUnchokeZero[--canUnchokeZeroCount] );
|
||||
unchoked++;
|
||||
}
|
||||
|
||||
/* Choke peers who aren't uploading if there are good peers waiting
|
||||
for an unchoke */
|
||||
while( canChokeZeroCount > 0 && canUnchokeNonZeroCount > 0 )
|
||||
{
|
||||
tr_peerChoke( canChokeZero[--canChokeZeroCount] );
|
||||
tr_peerUnchoke( canUnchokeNonZero[--canUnchokeNonZeroCount] );
|
||||
}
|
||||
|
||||
/* Choke peers who aren't uploading that much if there are choked
|
||||
peers who are uploading more */
|
||||
while( canChokeNonZeroCount > 0 && canUnchokeNonZeroCount > 0 )
|
||||
{
|
||||
if( tr_peerDownloadRate( canUnchokeNonZero[canUnchokeNonZeroCount - 1] )
|
||||
< tr_peerDownloadRate( canChokeNonZero[canChokeNonZeroCount - 1] ) )
|
||||
break;
|
||||
|
||||
tr_peerChoke( canChokeNonZero[--canChokeNonZeroCount] );
|
||||
tr_peerUnchoke( canUnchokeNonZero[--canUnchokeNonZeroCount] );
|
||||
}
|
||||
|
||||
/* Some unchoked peers still aren't uploading to us, let's give a
|
||||
chance to other non-uploaders */
|
||||
while( canChokeZeroCount > 0 && canUnchokeZeroCount > 0 )
|
||||
{
|
||||
tr_peerChoke( canChokeZero[--canChokeZeroCount] );
|
||||
tr_peerUnchoke( canUnchokeZero[--canUnchokeZeroCount] );
|
||||
}
|
||||
|
||||
tr_free( canChokeZero );
|
||||
tr_free( canChokeNonZero );
|
||||
tr_free( canUnchokeZero );
|
||||
tr_free( canUnchokeNonZero );
|
||||
|
||||
/* Unlock all torrents */
|
||||
for( tor = c->h->torrentList; tor; tor = tor->next )
|
||||
tr_torrentWriterUnlock( tor );
|
||||
|
||||
tr_lockUnlock( c->lock );
|
||||
}
|
||||
|
||||
void tr_chokingClose( tr_choking_t * c )
|
||||
{
|
||||
tr_lockFree( c->lock );
|
||||
tr_free( c );
|
||||
}
|
|
@ -44,7 +44,7 @@ static int charToInt( char character )
|
|||
return value;
|
||||
}
|
||||
|
||||
char * tr_clientForId( uint8_t * id )
|
||||
char * tr_clientForId( const uint8_t * id )
|
||||
{
|
||||
char * ret = NULL;
|
||||
|
||||
|
|
|
@ -22,4 +22,4 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
char * tr_clientForId( uint8_t * );
|
||||
char * tr_clientForId( const uint8_t * );
|
||||
|
|
|
@ -29,18 +29,15 @@
|
|||
#include "completion.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct tr_completion_s
|
||||
struct tr_completion
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
|
||||
/* true if a peer is requesting this block */
|
||||
tr_bitfield_t * blockRequested;
|
||||
tr_torrent * tor;
|
||||
|
||||
/* do we have this block? */
|
||||
tr_bitfield_t * blockBitfield;
|
||||
tr_bitfield * blockBitfield;
|
||||
|
||||
/* do we have this piece? */
|
||||
tr_bitfield_t * pieceBitfield;
|
||||
tr_bitfield * pieceBitfield;
|
||||
|
||||
/* a block is complete if and only if we have it */
|
||||
uint16_t * completeBlocks;
|
||||
|
@ -51,14 +48,13 @@ struct tr_completion_s
|
|||
uint64_t completeHave;
|
||||
};
|
||||
|
||||
tr_completion_t * tr_cpInit( tr_torrent_t * tor )
|
||||
tr_completion * tr_cpInit( tr_torrent * tor )
|
||||
{
|
||||
tr_completion_t * cp;
|
||||
tr_completion * cp;
|
||||
|
||||
cp = tr_new( tr_completion_t, 1 );
|
||||
cp = tr_new( tr_completion, 1 );
|
||||
cp->tor = tor;
|
||||
cp->blockBitfield = tr_bitfieldNew( tor->blockCount );
|
||||
cp->blockRequested = tr_bitfieldNew( tor->blockCount );
|
||||
cp->pieceBitfield = tr_bitfieldNew( tor->info.pieceCount );
|
||||
cp->completeBlocks = tr_new( uint16_t, tor->info.pieceCount );
|
||||
|
||||
|
@ -67,22 +63,20 @@ tr_completion_t * tr_cpInit( tr_torrent_t * tor )
|
|||
return cp;
|
||||
}
|
||||
|
||||
void tr_cpClose( tr_completion_t * cp )
|
||||
void tr_cpClose( tr_completion * cp )
|
||||
{
|
||||
tr_free( cp->completeBlocks );
|
||||
tr_bitfieldFree( cp->pieceBitfield );
|
||||
tr_bitfieldFree( cp->blockRequested );
|
||||
tr_bitfieldFree( cp->blockBitfield );
|
||||
tr_free( cp );
|
||||
}
|
||||
|
||||
void tr_cpReset( tr_completion_t * cp )
|
||||
void tr_cpReset( tr_completion * cp )
|
||||
{
|
||||
tr_torrent_t * tor = cp->tor;
|
||||
tr_torrent * tor = cp->tor;
|
||||
|
||||
tr_bitfieldClear( cp->pieceBitfield );
|
||||
tr_bitfieldClear( cp->blockBitfield );
|
||||
tr_bitfieldClear( cp->blockRequested );
|
||||
memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
|
||||
|
||||
cp->doneDirty = TRUE;
|
||||
|
@ -96,19 +90,19 @@ void tr_cpReset( tr_completion_t * cp )
|
|||
**/
|
||||
|
||||
static void
|
||||
tr_cpEnsureDoneValid( const tr_completion_t * ccp )
|
||||
tr_cpEnsureDoneValid( const tr_completion * ccp )
|
||||
{
|
||||
const tr_torrent_t * tor = ccp->tor;
|
||||
const tr_torrent * tor = ccp->tor;
|
||||
const tr_info_t * info = &tor->info;
|
||||
uint64_t have=0, total=0;
|
||||
int i;
|
||||
tr_completion_t * cp ;
|
||||
tr_completion * cp ;
|
||||
|
||||
if( !ccp->doneDirty )
|
||||
return;
|
||||
|
||||
/* too bad C doesn't have 'mutable' */
|
||||
cp = (tr_completion_t*) ccp;
|
||||
cp = (tr_completion*) ccp;
|
||||
cp->doneDirty = FALSE;
|
||||
|
||||
for( i=0; i<info->pieceCount; ++i ) {
|
||||
|
@ -135,24 +129,25 @@ tr_cpEnsureDoneValid( const tr_completion_t * ccp )
|
|||
}
|
||||
|
||||
void
|
||||
tr_cpInvalidateDND ( tr_completion_t * cp )
|
||||
tr_cpInvalidateDND ( tr_completion * cp )
|
||||
{
|
||||
cp->doneDirty = TRUE;
|
||||
}
|
||||
|
||||
int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
|
||||
int
|
||||
tr_cpPieceIsComplete( const tr_completion * cp, int piece )
|
||||
{
|
||||
return cp->completeBlocks[piece] >= tr_torPieceCountBlocks(cp->tor,piece);
|
||||
}
|
||||
|
||||
const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
|
||||
const tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp )
|
||||
{
|
||||
return cp->pieceBitfield;
|
||||
}
|
||||
|
||||
void tr_cpPieceAdd( tr_completion_t * cp, int piece )
|
||||
void tr_cpPieceAdd( tr_completion * cp, int piece )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const tr_torrent * tor = cp->tor;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
int i;
|
||||
|
@ -161,9 +156,9 @@ void tr_cpPieceAdd( tr_completion_t * cp, int piece )
|
|||
tr_cpBlockAdd( cp, i );
|
||||
}
|
||||
|
||||
void tr_cpPieceRem( tr_completion_t * cp, int piece )
|
||||
void tr_cpPieceRem( tr_completion * cp, int piece )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const tr_torrent * tor = cp->tor;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
int block;
|
||||
|
@ -190,26 +185,15 @@ void tr_cpPieceRem( tr_completion_t * cp, int piece )
|
|||
tr_bitfieldRem( cp->pieceBitfield, piece );
|
||||
}
|
||||
|
||||
/* Blocks */
|
||||
void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
|
||||
int tr_cpBlockIsComplete( const tr_completion * cp, int block )
|
||||
{
|
||||
tr_bitfieldAdd( cp->blockRequested, block );
|
||||
}
|
||||
|
||||
void tr_cpDownloaderRem( tr_completion_t * cp, int block )
|
||||
{
|
||||
tr_bitfieldRem( cp->blockRequested, block );
|
||||
}
|
||||
|
||||
int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
|
||||
{
|
||||
return tr_bitfieldHas( cp->blockBitfield, block );
|
||||
return tr_bitfieldHas( cp->blockBitfield, block ) ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
tr_cpBlockAdd( tr_completion_t * cp, int block )
|
||||
tr_cpBlockAdd( tr_completion * cp, int block )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const tr_torrent * tor = cp->tor;
|
||||
|
||||
if( !tr_cpBlockIsComplete( cp, block ) )
|
||||
{
|
||||
|
@ -230,7 +214,7 @@ tr_cpBlockAdd( tr_completion_t * cp, int block )
|
|||
}
|
||||
}
|
||||
|
||||
const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
|
||||
const tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp )
|
||||
{
|
||||
assert( cp != NULL );
|
||||
|
||||
|
@ -238,7 +222,7 @@ const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
|
|||
}
|
||||
|
||||
void
|
||||
tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
|
||||
tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -252,62 +236,31 @@ tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
|
|||
tr_cpBlockAdd( cp, i );
|
||||
}
|
||||
|
||||
float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
|
||||
float tr_cpPercentBlocksInPiece( const tr_completion * cp, int piece )
|
||||
{
|
||||
assert( cp != NULL );
|
||||
|
||||
return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
|
||||
}
|
||||
|
||||
int
|
||||
tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
|
||||
n = 0;
|
||||
for( i = start; i < end; ++i )
|
||||
if( !tr_cpBlockIsComplete( cp, i ) && !tr_bitfieldHas( cp->blockRequested, i ) )
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
|
||||
{
|
||||
int i;
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
|
||||
for( i = start; i < end; ++i )
|
||||
if( !tr_cpBlockIsComplete( cp, i ) && !tr_bitfieldHas( cp->blockRequested, i ) )
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
float
|
||||
tr_cpPercentComplete ( const tr_completion_t * cp )
|
||||
tr_cpPercentComplete ( const tr_completion * cp )
|
||||
{
|
||||
return (double)cp->completeHave / cp->tor->info.totalSize;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tr_cpLeftUntilComplete ( const tr_completion_t * cp )
|
||||
tr_cpLeftUntilComplete ( const tr_completion * cp )
|
||||
{
|
||||
return cp->tor->info.totalSize - cp->completeHave;
|
||||
}
|
||||
|
||||
float
|
||||
tr_cpPercentDone( const tr_completion_t * cp )
|
||||
tr_cpPercentDone( const tr_completion * cp )
|
||||
{
|
||||
tr_cpEnsureDoneValid( cp );
|
||||
|
||||
|
@ -315,7 +268,7 @@ tr_cpPercentDone( const tr_completion_t * cp )
|
|||
}
|
||||
|
||||
uint64_t
|
||||
tr_cpLeftUntilDone ( const tr_completion_t * cp )
|
||||
tr_cpLeftUntilDone ( const tr_completion * cp )
|
||||
{
|
||||
tr_cpEnsureDoneValid( cp );
|
||||
|
||||
|
@ -323,7 +276,7 @@ tr_cpLeftUntilDone ( const tr_completion_t * cp )
|
|||
}
|
||||
|
||||
cp_status_t
|
||||
tr_cpGetStatus ( const tr_completion_t * cp )
|
||||
tr_cpGetStatus ( const tr_completion * cp )
|
||||
{
|
||||
if( cp->completeHave >= cp->tor->info.totalSize )
|
||||
return TR_CP_COMPLETE;
|
||||
|
@ -337,10 +290,10 @@ tr_cpGetStatus ( const tr_completion_t * cp )
|
|||
}
|
||||
|
||||
uint64_t
|
||||
tr_cpDownloadedValid( const tr_completion_t * cp )
|
||||
tr_cpDownloadedValid( const tr_completion * cp )
|
||||
{
|
||||
uint64_t b = 0;
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const tr_torrent * tor = cp->tor;
|
||||
const tr_info_t * info = &tor->info;
|
||||
int i;
|
||||
|
||||
|
|
|
@ -27,39 +27,34 @@
|
|||
|
||||
#include "transmission.h"
|
||||
|
||||
typedef struct tr_completion_s tr_completion_t;
|
||||
typedef struct tr_completion tr_completion;
|
||||
|
||||
tr_completion_t * tr_cpInit( tr_torrent_t * );
|
||||
void tr_cpClose( tr_completion_t * );
|
||||
void tr_cpReset( tr_completion_t * );
|
||||
tr_completion * tr_cpInit( tr_torrent * );
|
||||
void tr_cpClose( tr_completion * );
|
||||
void tr_cpReset( tr_completion * );
|
||||
|
||||
/* General */
|
||||
|
||||
cp_status_t tr_cpGetStatus ( const tr_completion_t * );
|
||||
uint64_t tr_cpDownloadedValid( const tr_completion_t * );
|
||||
uint64_t tr_cpLeftUntilComplete( const tr_completion_t * );
|
||||
uint64_t tr_cpLeftUntilDone( const tr_completion_t * );
|
||||
float tr_cpPercentComplete( const tr_completion_t * );
|
||||
float tr_cpPercentDone( const tr_completion_t * );
|
||||
void tr_cpInvalidateDND ( tr_completion_t * );
|
||||
cp_status_t tr_cpGetStatus ( const tr_completion * );
|
||||
uint64_t tr_cpDownloadedValid( const tr_completion * );
|
||||
uint64_t tr_cpLeftUntilComplete( const tr_completion * );
|
||||
uint64_t tr_cpLeftUntilDone( const tr_completion * );
|
||||
float tr_cpPercentComplete( const tr_completion * );
|
||||
float tr_cpPercentDone( const tr_completion * );
|
||||
void tr_cpInvalidateDND ( tr_completion * );
|
||||
|
||||
/* Pieces */
|
||||
int tr_cpPieceIsComplete( const tr_completion_t *, int piece );
|
||||
void tr_cpPieceAdd( tr_completion_t *, int piece );
|
||||
void tr_cpPieceRem( tr_completion_t *, int piece );
|
||||
int tr_cpPieceIsComplete( const tr_completion *, int piece );
|
||||
void tr_cpPieceAdd( tr_completion *, int piece );
|
||||
void tr_cpPieceRem( tr_completion *, int piece );
|
||||
|
||||
/* Blocks */
|
||||
void tr_cpDownloaderAdd( tr_completion_t *, int block );
|
||||
void tr_cpDownloaderRem( tr_completion_t *, int block );
|
||||
int tr_cpBlockIsComplete( const tr_completion_t *, int block );
|
||||
void tr_cpBlockAdd( tr_completion_t *, int block );
|
||||
void tr_cpBlockBitfieldSet( tr_completion_t *, struct tr_bitfield_s * );
|
||||
float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece );
|
||||
/* Missing = we don't have it and we are not getting it from any peer yet */
|
||||
int tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece );
|
||||
int tr_cpMissingBlockInPiece( const tr_completion_t *, int piece );
|
||||
int tr_cpBlockIsComplete( const tr_completion *, int block );
|
||||
void tr_cpBlockAdd( tr_completion *, int block );
|
||||
void tr_cpBlockBitfieldSet( tr_completion *, struct tr_bitfield * );
|
||||
float tr_cpPercentBlocksInPiece( const tr_completion * cp, int piece );
|
||||
|
||||
const struct tr_bitfield_s * tr_cpPieceBitfield( const tr_completion_t* );
|
||||
const struct tr_bitfield_s * tr_cpBlockBitfield( const tr_completion_t * );
|
||||
const struct tr_bitfield * tr_cpPieceBitfield( const tr_completion* );
|
||||
const struct tr_bitfield * tr_cpBlockBitfield( const tr_completion * );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h> /* uint8_t */
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdarg.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <event.h>
|
||||
#include "crypto.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_sha1( uint8_t * setme,
|
||||
const void * content1,
|
||||
int content1_len,
|
||||
... )
|
||||
{
|
||||
va_list vl;
|
||||
SHA_CTX sha;
|
||||
|
||||
SHA1_Init( &sha );
|
||||
SHA1_Update( &sha, content1, content1_len );
|
||||
|
||||
va_start( vl, content1_len );
|
||||
for( ;; ) {
|
||||
const void * content = (const void*) va_arg( vl, const void* );
|
||||
const int content_len = content ? (int) va_arg( vl, int ) : -1;
|
||||
if( content==NULL || content_len<1 )
|
||||
break;
|
||||
SHA1_Update( &sha, content, content_len );
|
||||
}
|
||||
SHA1_Final( setme, &sha );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
#define KEY_LEN 96
|
||||
|
||||
#define PRIME_LEN 96
|
||||
|
||||
static const uint8_t dh_P[PRIME_LEN] =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
|
||||
0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63,
|
||||
};
|
||||
|
||||
static const uint8_t dh_G[] = { 2 };
|
||||
|
||||
struct tr_crypto
|
||||
{
|
||||
DH * dh;
|
||||
RC4_KEY dec_key;
|
||||
RC4_KEY enc_key;
|
||||
uint8_t torrentHash[SHA_DIGEST_LENGTH];
|
||||
unsigned int isIncoming : 1;
|
||||
unsigned int torrentHashIsSet : 1;
|
||||
unsigned int mySecretIsSet : 1;
|
||||
uint8_t myPublicKey[KEY_LEN];
|
||||
uint8_t mySecret[KEY_LEN];
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
tr_crypto *
|
||||
tr_cryptoNew( const uint8_t * torrentHash,
|
||||
int isIncoming )
|
||||
{
|
||||
int len, offset;
|
||||
tr_crypto * crypto;
|
||||
|
||||
crypto = tr_new0( tr_crypto, 1 );
|
||||
crypto->isIncoming = isIncoming ? 1 : 0;
|
||||
tr_cryptoSetTorrentHash( crypto, torrentHash );
|
||||
|
||||
crypto->dh = DH_new( );
|
||||
crypto->dh->p = BN_bin2bn( dh_P, sizeof(dh_P), NULL );
|
||||
crypto->dh->g = BN_bin2bn( dh_G, sizeof(dh_G), NULL );
|
||||
DH_generate_key( crypto->dh );
|
||||
|
||||
// DH can generate key sizes that are smaller than the size of
|
||||
// P with exponentially decreasing probability, in which case
|
||||
// the msb's of myPublicKey need to be zeroed appropriately.
|
||||
len = DH_size( crypto->dh );
|
||||
offset = KEY_LEN - len;
|
||||
assert( len <= KEY_LEN );
|
||||
memset( crypto->myPublicKey, 0, offset );
|
||||
BN_bn2bin( crypto->dh->pub_key, crypto->myPublicKey + offset );
|
||||
|
||||
return crypto;
|
||||
}
|
||||
|
||||
void
|
||||
tr_cryptoFree( tr_crypto * crypto )
|
||||
{
|
||||
assert( crypto != NULL );
|
||||
assert( crypto->dh != NULL );
|
||||
|
||||
DH_free( crypto->dh );
|
||||
tr_free( crypto );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
const uint8_t*
|
||||
tr_cryptoComputeSecret( tr_crypto * crypto,
|
||||
const uint8_t * peerPublicKey )
|
||||
{
|
||||
int len, offset;
|
||||
uint8_t secret[KEY_LEN];
|
||||
BIGNUM * bn = BN_bin2bn( peerPublicKey, KEY_LEN, NULL );
|
||||
assert( DH_size(crypto->dh) == KEY_LEN );
|
||||
|
||||
len = DH_compute_key( secret, bn, crypto->dh );
|
||||
assert( len <= KEY_LEN );
|
||||
offset = KEY_LEN - len;
|
||||
memset( crypto->mySecret, 0, offset );
|
||||
memcpy( crypto->mySecret + offset, secret, len );
|
||||
crypto->mySecretIsSet = 1;
|
||||
|
||||
BN_free( bn );
|
||||
|
||||
return crypto->mySecret;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
tr_cryptoGetMyPublicKey( const tr_crypto * crypto, int * setme_len )
|
||||
{
|
||||
*setme_len = KEY_LEN;
|
||||
return crypto->myPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
initRC4( tr_crypto * crypto, RC4_KEY * setme, const char * key )
|
||||
{
|
||||
SHA_CTX sha;
|
||||
uint8_t buf[SHA_DIGEST_LENGTH];
|
||||
|
||||
assert( crypto->torrentHashIsSet );
|
||||
assert( crypto->mySecretIsSet );
|
||||
|
||||
SHA1_Init( &sha );
|
||||
SHA1_Update( &sha, key, 4 );
|
||||
SHA1_Update( &sha, crypto->mySecret, KEY_LEN );
|
||||
SHA1_Update( &sha, crypto->torrentHash, SHA_DIGEST_LENGTH );
|
||||
SHA1_Final( buf, &sha );
|
||||
RC4_set_key( setme, SHA_DIGEST_LENGTH, buf );
|
||||
}
|
||||
|
||||
void
|
||||
tr_cryptoDecryptInit( tr_crypto * crypto )
|
||||
{
|
||||
unsigned char discard[1024];
|
||||
const char * txt = crypto->isIncoming ? "keyA" : "keyB";
|
||||
initRC4( crypto, &crypto->dec_key, txt );
|
||||
RC4( &crypto->dec_key, sizeof(discard), discard, discard );
|
||||
}
|
||||
|
||||
void
|
||||
tr_cryptoDecrypt( tr_crypto * crypto,
|
||||
size_t buf_len,
|
||||
const void * buf_in,
|
||||
void * buf_out )
|
||||
{
|
||||
RC4( &crypto->dec_key, buf_len,
|
||||
(const unsigned char*)buf_in,
|
||||
(unsigned char*)buf_out );
|
||||
}
|
||||
|
||||
void
|
||||
tr_cryptoEncryptInit( tr_crypto * crypto )
|
||||
{
|
||||
unsigned char discard[1024];
|
||||
const char * txt = crypto->isIncoming ? "keyB" : "keyA";
|
||||
initRC4( crypto, &crypto->enc_key, txt );
|
||||
RC4( &crypto->enc_key, sizeof(discard), discard, discard );
|
||||
}
|
||||
|
||||
void
|
||||
tr_cryptoEncrypt( tr_crypto * crypto,
|
||||
size_t buf_len,
|
||||
const void * buf_in,
|
||||
void * buf_out )
|
||||
{
|
||||
RC4( &crypto->enc_key, buf_len,
|
||||
(const unsigned char*)buf_in,
|
||||
(unsigned char*)buf_out );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_cryptoSetTorrentHash( tr_crypto * crypto,
|
||||
const uint8_t * hash )
|
||||
{
|
||||
crypto->torrentHashIsSet = hash ? 1 : 0;
|
||||
|
||||
if( hash != NULL )
|
||||
memcpy( crypto->torrentHash, hash, SHA_DIGEST_LENGTH );
|
||||
else
|
||||
memset( crypto->torrentHash, 0, SHA_DIGEST_LENGTH );
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
tr_cryptoGetTorrentHash( const tr_crypto * crypto )
|
||||
{
|
||||
assert( crypto != NULL );
|
||||
assert( crypto->torrentHashIsSet );
|
||||
|
||||
return crypto->torrentHash;
|
||||
}
|
||||
|
||||
int
|
||||
tr_cryptoHasTorrentHash( const tr_crypto * crypto )
|
||||
{
|
||||
assert( crypto != NULL );
|
||||
|
||||
return crypto->torrentHashIsSet ? 1 : 0;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_ENCRYPTION_H
|
||||
#define TR_ENCRYPTION_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct evbuffer;
|
||||
typedef struct tr_crypto tr_crypto;
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
tr_crypto* tr_cryptoNew ( const uint8_t * torrentHash,
|
||||
int isIncoming );
|
||||
|
||||
void tr_cryptoFree( tr_crypto * crypto );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void tr_cryptoSetTorrentHash( tr_crypto * crypto,
|
||||
const uint8_t * torrentHash );
|
||||
|
||||
const uint8_t* tr_cryptoGetTorrentHash( const tr_crypto * crypto );
|
||||
|
||||
int tr_cryptoHasTorrentHash( const tr_crypto * crypto );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
const uint8_t* tr_cryptoComputeSecret ( tr_crypto * crypto,
|
||||
const uint8_t * peerPublicKey );
|
||||
|
||||
const uint8_t* tr_cryptoGetMyPublicKey ( const tr_crypto * crypto,
|
||||
int * setme_len );
|
||||
|
||||
void tr_cryptoDecryptInit( tr_crypto * crypto );
|
||||
|
||||
void tr_cryptoDecrypt ( tr_crypto * crypto,
|
||||
size_t buflen,
|
||||
const void * buf_in,
|
||||
void * buf_out );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void tr_cryptoEncryptInit ( tr_crypto * crypto );
|
||||
|
||||
void tr_cryptoEncrypt ( tr_crypto * crypto,
|
||||
size_t buflen,
|
||||
const void * buf_in,
|
||||
void * buf_out );
|
||||
|
||||
void tr_sha1 ( uint8_t * setme,
|
||||
const void * content1,
|
||||
int content1_len,
|
||||
... );
|
||||
|
||||
#endif
|
|
@ -55,7 +55,7 @@
|
|||
#include "transmission.h"
|
||||
#include "completion.h"
|
||||
#include "fastresume.h"
|
||||
#include "peer.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -74,7 +74,7 @@ enum
|
|||
FR_ID_UPLOADED = 3,
|
||||
|
||||
/* IPs and ports of connectable peers */
|
||||
FR_ID_PEERS = 4,
|
||||
FR_ID_PEERS_OLD = 4,
|
||||
|
||||
/* progress data:
|
||||
* - 4 bytes * number of files: mtimes of files
|
||||
|
@ -88,9 +88,9 @@ enum
|
|||
|
||||
/* transfer speeds
|
||||
* uint32_t: dl speed rate to use when the mode is single
|
||||
* uint32_t: dl's tr_speedlimit_t
|
||||
* uint32_t: dl's tr_speedlimit
|
||||
* uint32_t: ul speed rate to use when the mode is single
|
||||
* uint32_t: ul's tr_speedlimit_t
|
||||
* uint32_t: ul's tr_speedlimit
|
||||
*/
|
||||
FR_ID_SPEED = 8,
|
||||
|
||||
|
@ -100,7 +100,10 @@ enum
|
|||
FR_ID_RUN = 9,
|
||||
|
||||
/* number of corrupt bytes downloaded */
|
||||
FR_ID_CORRUPT = 10
|
||||
FR_ID_CORRUPT = 10,
|
||||
|
||||
/* IPs and ports of connectable peers */
|
||||
FR_ID_PEERS = 11
|
||||
};
|
||||
|
||||
|
||||
|
@ -114,7 +117,7 @@ enum
|
|||
#define FR_SPEED_LEN (2 * (sizeof(uint16_t) + sizeof(uint8_t) ) )
|
||||
|
||||
static void
|
||||
fastResumeFileName( char * buf, size_t buflen, const tr_torrent_t * tor, int tag )
|
||||
fastResumeFileName( char * buf, size_t buflen, const tr_torrent * tor, int tag )
|
||||
{
|
||||
const char * cacheDir = tr_getCacheDirectory ();
|
||||
const char * hash = tor->info.hashString;
|
||||
|
@ -132,7 +135,7 @@ fastResumeFileName( char * buf, size_t buflen, const tr_torrent_t * tor, int tag
|
|||
}
|
||||
|
||||
static tr_time_t*
|
||||
getMTimes( const tr_torrent_t * tor, int * setme_n )
|
||||
getMTimes( const tr_torrent * tor, int * setme_n )
|
||||
{
|
||||
int i;
|
||||
const int n = tor->info.fileCount;
|
||||
|
@ -171,7 +174,7 @@ fastResumeWriteData( uint8_t id,
|
|||
}
|
||||
|
||||
void
|
||||
tr_fastResumeSave( const tr_torrent_t * tor )
|
||||
tr_fastResumeSave( const tr_torrent * tor )
|
||||
{
|
||||
char path[MAX_PATH_LENGTH];
|
||||
FILE * file;
|
||||
|
@ -194,7 +197,7 @@ tr_fastResumeSave( const tr_torrent_t * tor )
|
|||
tr_time_t * mtimes;
|
||||
uint8_t * buf = malloc( FR_PROGRESS_LEN( tor ) );
|
||||
uint8_t * walk = buf;
|
||||
const tr_bitfield_t * bitfield;
|
||||
const tr_bitfield * bitfield;
|
||||
|
||||
/* mtimes */
|
||||
mtimes = getMTimes( tor, &n );
|
||||
|
@ -283,23 +286,25 @@ tr_fastResumeSave( const tr_torrent_t * tor )
|
|||
}
|
||||
|
||||
/* Write download and upload totals */
|
||||
|
||||
total = tor->downloadedCur + tor->downloadedPrev;
|
||||
fastResumeWriteData( FR_ID_DOWNLOADED, &total, 8, 1, file );
|
||||
|
||||
total = tor->uploadedCur + tor->uploadedPrev;
|
||||
fastResumeWriteData( FR_ID_UPLOADED, &total, 8, 1, file );
|
||||
|
||||
total = tor->corruptCur + tor->corruptPrev;
|
||||
fastResumeWriteData( FR_ID_CORRUPT, &total, 8, 1, file );
|
||||
|
||||
if( !( TR_FLAG_PRIVATE & tor->info.flags ) )
|
||||
{
|
||||
/* Write IPs and ports of connectable peers, if any */
|
||||
int size;
|
||||
uint8_t * buf = NULL;
|
||||
if( ( size = tr_peerGetConnectable( tor, &buf ) ) > 0 )
|
||||
{
|
||||
fastResumeWriteData( FR_ID_PEERS, buf, size, 1, file );
|
||||
free( buf );
|
||||
}
|
||||
tr_pex * pex;
|
||||
const int count = tr_peerMgrGetPeers( tor->handle->peerMgr,
|
||||
tor->info.hash,
|
||||
&pex );
|
||||
if( count > 0 )
|
||||
fastResumeWriteData( FR_ID_PEERS, pex, sizeof(tr_pex), count, file );
|
||||
tr_free( pex );
|
||||
}
|
||||
|
||||
fclose( file );
|
||||
|
@ -308,7 +313,7 @@ tr_fastResumeSave( const tr_torrent_t * tor )
|
|||
}
|
||||
|
||||
static int
|
||||
loadSpeeds( tr_torrent_t * tor, FILE * file )
|
||||
loadSpeeds( tr_torrent * tor, FILE * file )
|
||||
{
|
||||
const size_t len = FR_SPEED_LEN;
|
||||
char * buf = tr_new0( char, len );
|
||||
|
@ -325,11 +330,11 @@ loadSpeeds( tr_torrent_t * tor, FILE * file )
|
|||
memcpy( &i16, walk, 2 ); walk += 2;
|
||||
tr_torrentSetSpeedLimit( tor, TR_DOWN, i16 );
|
||||
memcpy( &i8, walk, 1 ); walk += 1;
|
||||
tr_torrentSetSpeedMode( tor, TR_DOWN, (tr_speedlimit_t)i8 );
|
||||
tr_torrentSetSpeedMode( tor, TR_DOWN, (tr_speedlimit)i8 );
|
||||
memcpy( &i16, walk, 2 ); walk += 2;
|
||||
tr_torrentSetSpeedLimit( tor, TR_UP, i16 );
|
||||
memcpy( &i8, walk, 1 ); walk += 1;
|
||||
tr_torrentSetSpeedMode( tor, TR_UP, (tr_speedlimit_t)i8 );
|
||||
tr_torrentSetSpeedMode( tor, TR_UP, (tr_speedlimit)i8 );
|
||||
|
||||
tr_free( buf );
|
||||
return TR_OK;
|
||||
|
@ -337,8 +342,8 @@ loadSpeeds( tr_torrent_t * tor, FILE * file )
|
|||
|
||||
|
||||
static int
|
||||
loadPriorities( tr_torrent_t * tor,
|
||||
FILE * file )
|
||||
loadPriorities( tr_torrent * tor,
|
||||
FILE * file )
|
||||
{
|
||||
const size_t n = tor->info.fileCount;
|
||||
const size_t len = 2 * n;
|
||||
|
@ -387,9 +392,9 @@ loadPriorities( tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static int
|
||||
fastResumeLoadProgress( const tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces,
|
||||
FILE * file )
|
||||
fastResumeLoadProgress( const tr_torrent * tor,
|
||||
tr_bitfield * uncheckedPieces,
|
||||
FILE * file )
|
||||
{
|
||||
int i;
|
||||
const size_t len = FR_PROGRESS_LEN( tor );
|
||||
|
@ -409,7 +414,7 @@ fastResumeLoadProgress( const tr_torrent_t * tor,
|
|||
const tr_time_t * oldMTimes = (const tr_time_t *) walk;
|
||||
for( i=0; i<n; ++i ) {
|
||||
if ( curMTimes[i]!=oldMTimes[i] ) {
|
||||
const tr_file_t * file = &tor->info.files[i];
|
||||
const tr_file * file = &tor->info.files[i];
|
||||
tr_dbg( "File '%s' mtimes differ-- flagging pieces [%d..%d] for recheck",
|
||||
file->name, file->firstPiece, file->lastPiece);
|
||||
tr_bitfieldAddRange( uncheckedPieces,
|
||||
|
@ -422,7 +427,7 @@ fastResumeLoadProgress( const tr_torrent_t * tor,
|
|||
|
||||
/* get the completion bitfield */
|
||||
if (1) {
|
||||
tr_bitfield_t bitfield;
|
||||
tr_bitfield bitfield;
|
||||
memset( &bitfield, 0, sizeof bitfield );
|
||||
bitfield.len = FR_BLOCK_BITFIELD_LEN( tor );
|
||||
bitfield.bits = walk;
|
||||
|
@ -441,9 +446,9 @@ fastResumeLoadProgress( const tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static uint64_t
|
||||
fastResumeLoadOld( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces,
|
||||
FILE * file )
|
||||
fastResumeLoadOld( tr_torrent * tor,
|
||||
tr_bitfield * uncheckedPieces,
|
||||
FILE * file )
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
|
@ -475,8 +480,8 @@ fastResumeLoadOld( tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static uint64_t
|
||||
fastResumeLoadImpl ( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces )
|
||||
fastResumeLoadImpl ( tr_torrent * tor,
|
||||
tr_bitfield * uncheckedPieces )
|
||||
{
|
||||
char path[MAX_PATH_LENGTH];
|
||||
FILE * file;
|
||||
|
@ -636,10 +641,9 @@ fastResumeLoadImpl ( tr_torrent_t * tor,
|
|||
}
|
||||
break;
|
||||
|
||||
case FR_ID_PEERS:
|
||||
case FR_ID_PEERS_OLD:
|
||||
if( !( TR_FLAG_PRIVATE & tor->info.flags ) )
|
||||
{
|
||||
int used;
|
||||
uint8_t * buf = malloc( len );
|
||||
if( 1 != fread( buf, len, 1, file ) )
|
||||
{
|
||||
|
@ -647,13 +651,38 @@ fastResumeLoadImpl ( tr_torrent_t * tor,
|
|||
fclose( file );
|
||||
return ret;
|
||||
}
|
||||
used = tr_torrentAddCompact( tor, TR_PEER_FROM_CACHE,
|
||||
buf, len / 6 );
|
||||
tr_dbg( "found %i peers in resume file, used %i",
|
||||
len / 6, used );
|
||||
|
||||
tr_peerMgrAddPeers( tor->handle->peerMgr,
|
||||
tor->info.hash,
|
||||
TR_PEER_FROM_CACHE,
|
||||
buf, len / 6 );
|
||||
|
||||
tr_dbg( "found %i peers in resume file", len/6 );
|
||||
free( buf );
|
||||
ret |= TR_FR_PEERS;
|
||||
}
|
||||
|
||||
case FR_ID_PEERS:
|
||||
if( !( TR_FLAG_PRIVATE & tor->info.flags ) )
|
||||
{
|
||||
const int count = len / sizeof(tr_pex);
|
||||
tr_pex * pex = tr_new0( tr_pex, count );
|
||||
if( 1 != fread( pex, sizeof(tr_pex), count, file ) )
|
||||
{
|
||||
free( pex );
|
||||
fclose( file );
|
||||
return ret;
|
||||
}
|
||||
|
||||
tr_peerMgrAddPex( tor->handle->peerMgr,
|
||||
tor->info.hash,
|
||||
TR_PEER_FROM_CACHE,
|
||||
pex, count );
|
||||
|
||||
tr_dbg( "found %i peers in resume file", len/6 );
|
||||
free( pex );
|
||||
ret |= TR_FR_PEERS;
|
||||
}
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
@ -670,8 +699,8 @@ fastResumeLoadImpl ( tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
uint64_t
|
||||
tr_fastResumeLoad( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces )
|
||||
tr_fastResumeLoad( tr_torrent * tor,
|
||||
tr_bitfield * uncheckedPieces )
|
||||
{
|
||||
const uint64_t ret = fastResumeLoadImpl( tor, uncheckedPieces );
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef TR_FAST_RESUME_H
|
||||
#define TR_FAST_RESUME_H
|
||||
|
||||
void tr_fastResumeSave( const tr_torrent_t * tor );
|
||||
void tr_fastResumeSave( const tr_torrent * tor );
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ enum
|
|||
/**
|
||||
* Returns a bitwise-or'ed set of the data loaded from fastresume
|
||||
*/
|
||||
uint64_t tr_fastResumeLoad( tr_torrent_t * tor,
|
||||
struct tr_bitfield_s * uncheckedPieces );
|
||||
uint64_t tr_fastResumeLoad( tr_torrent * tor,
|
||||
struct tr_bitfield * uncheckedPieces );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,8 +63,8 @@ tr_openFile_t;
|
|||
|
||||
typedef struct tr_fd_s
|
||||
{
|
||||
tr_lock_t * lock;
|
||||
tr_cond_t * cond;
|
||||
tr_lock * lock;
|
||||
tr_cond * cond;
|
||||
|
||||
int reserved;
|
||||
|
||||
|
@ -390,17 +390,20 @@ int tr_fdSocketAccept( int b, struct in_addr * addr, tr_port_t * port )
|
|||
**********************************************************************/
|
||||
void tr_fdSocketClose( int s )
|
||||
{
|
||||
tr_lockLock( gFd->lock );
|
||||
if( s >= 0 )
|
||||
{
|
||||
tr_lockLock( gFd->lock );
|
||||
#ifdef BEOS_NETSERVER
|
||||
closesocket( s );
|
||||
closesocket( s );
|
||||
#else
|
||||
close( s );
|
||||
close( s );
|
||||
#endif
|
||||
if( SocketGetPriority( s ) )
|
||||
gFd->reserved--;
|
||||
else
|
||||
gFd->normal--;
|
||||
tr_lockUnlock( gFd->lock );
|
||||
if( SocketGetPriority( s ) )
|
||||
gFd->reserved--;
|
||||
else
|
||||
gFd->normal--;
|
||||
tr_lockUnlock( gFd->lock );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -0,0 +1,897 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h> /* UCHAR_MAX */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/types.h> /* event.h needs this */
|
||||
#include <event.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "crypto.h"
|
||||
#include "handshake.h"
|
||||
#include "peer-io.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* enable LibTransmission extension protocol */
|
||||
#define ENABLE_LTEP
|
||||
|
||||
/* enable Azureus messaging protocol */
|
||||
//#define ENABLE_AZMP
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
#define HANDSHAKE_NAME "\023BitTorrent protocol"
|
||||
|
||||
enum
|
||||
{
|
||||
/* BitTorrent Handshake Constants */
|
||||
HANDSHAKE_NAME_LEN = 20,
|
||||
HANDSHAKE_FLAGS_LEN = 8,
|
||||
HANDSHAKE_SIZE = 68,
|
||||
PEER_ID_LEN = 20,
|
||||
|
||||
/* Extension Negotiation Constants */
|
||||
HANDSHAKE_EXTPREF_LTEP_FORCE = 0x0,
|
||||
HANDSHAKE_EXTPREF_LTEP_PREFER = 0x1,
|
||||
HANDSHAKE_EXTPREF_AZMP_PREFER = 0x2,
|
||||
HANDSHAKE_EXTPREF_AZMP_FORCE = 0x3,
|
||||
|
||||
/* Encryption Constants */
|
||||
PadA_MAXLEN = 512,
|
||||
PadB_MAXLEN = 512,
|
||||
PadC_MAXLEN = 512,
|
||||
PadD_MAXLEN = 512,
|
||||
VC_LENGTH = 8,
|
||||
KEY_LEN = 96
|
||||
};
|
||||
|
||||
|
||||
#ifdef ENABLE_LTEP
|
||||
#define HANDSHAKE_HAS_EXTMSGS( bits ) ( ( (bits)[5] & 0x10 ) ? 1 : 0 )
|
||||
#define HANDSHAKE_SET_EXTMSGS( bits ) ( ( (bits)[5] |= 0x10 ) ? 1 : 0 )
|
||||
#else
|
||||
#define HANDSHAKE_HAS_EXTMSGS( bits ) ( 0 )
|
||||
#define HANDSHAKE_SET_EXTMSGS( bits ) ( (void)0 )
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AZMP
|
||||
#define HANDSHAKE_HAS_AZPROTO( bits ) ( ( (bits)[0] & 0x80 ) ? 1 : 0 )
|
||||
#define HANDSHAKE_SET_AZPROTO( bits ) ( ( (bits)[0] |= 0x80 ) ? 1 : 0 )
|
||||
#else
|
||||
#define HANDSHAKE_HAS_AZPROTO( bits ) ( 0 )
|
||||
#define HANDSHAKE_SET_AZPROTO( bits ) ( (void)0 )
|
||||
#endif
|
||||
|
||||
/* http://www.azureuswiki.com/index.php/Extension_negotiation_protocol
|
||||
these macros are to be used if both extended messaging and the
|
||||
azureus protocol is supported, they indicate which protocol is preferred */
|
||||
#define HANDSHAKE_GET_EXTPREF( reserved ) ( (reserved)[5] & 0x03 )
|
||||
#define HANDSHAKE_SET_EXTPREF( reserved, val ) ( (reserved)[5] |= 0x03 & (val) )
|
||||
|
||||
extern const char* getPeerId( void ) ;
|
||||
|
||||
struct tr_handshake
|
||||
{
|
||||
unsigned int peerSupportsEncryption : 1;
|
||||
unsigned int havePeerID : 1;
|
||||
unsigned int haveSentBitTorrentHandshake : 1;
|
||||
unsigned int shunUnencryptedPeers : 1;
|
||||
tr_peerIo * io;
|
||||
tr_crypto * crypto;
|
||||
struct tr_handle * handle;
|
||||
uint8_t myPublicKey[KEY_LEN];
|
||||
uint8_t mySecret[KEY_LEN];
|
||||
uint8_t state;
|
||||
uint16_t pad_c_len;
|
||||
uint16_t pad_d_len;
|
||||
uint16_t ia_len;
|
||||
uint32_t crypto_select;
|
||||
uint8_t myReq1[SHA_DIGEST_LENGTH];
|
||||
uint8_t peer_id[PEER_ID_LEN];
|
||||
handshakeDoneCB doneCB;
|
||||
void * doneUserData;
|
||||
};
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
enum
|
||||
{
|
||||
/* incoming */
|
||||
AWAITING_HANDSHAKE,
|
||||
AWAITING_YA,
|
||||
AWAITING_PAD_A,
|
||||
AWAITING_CRYPTO_PROVIDE,
|
||||
AWAITING_PAD_C,
|
||||
AWAITING_IA,
|
||||
|
||||
/* outgoing */
|
||||
AWAITING_YB,
|
||||
AWAITING_VC,
|
||||
AWAITING_CRYPTO_SELECT,
|
||||
AWAITING_PAD_D,
|
||||
};
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
myDebug( const char * file, int line, const tr_handshake * handshake, const char * fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
const char * addr = tr_peerIoGetAddrStr( handshake->io );
|
||||
struct evbuffer * buf = evbuffer_new( );
|
||||
evbuffer_add_printf( buf, "[%s:%d] %s (%p) ", file, line, addr, handshake );
|
||||
va_start( args, fmt );
|
||||
evbuffer_add_vprintf( buf, fmt, args );
|
||||
va_end( args );
|
||||
|
||||
fprintf( stderr, "%s\n", EVBUFFER_DATA(buf) );
|
||||
|
||||
evbuffer_free( buf );
|
||||
}
|
||||
|
||||
#define dbgmsg(handshake, fmt...) myDebug(__FILE__, __LINE__, handshake, ##fmt )
|
||||
|
||||
static const char* getStateName( short state )
|
||||
{
|
||||
const char * str = "f00!";
|
||||
switch( state ) {
|
||||
case AWAITING_HANDSHAKE: str = "awaiting handshake"; break;
|
||||
case AWAITING_YA: str = "awaiting ya"; break;
|
||||
//case SENDING_YB: str = "sending yb"; break;
|
||||
case AWAITING_PAD_A: str = "awaiting pad a"; break;
|
||||
case AWAITING_CRYPTO_PROVIDE: str = "awaiting crypto_provide"; break;
|
||||
case AWAITING_PAD_C: str = "awaiting pad c"; break;
|
||||
case AWAITING_IA: str = "awaiting ia"; break;
|
||||
//case SENDING_YA: str = "sending ya"; break;
|
||||
case AWAITING_YB: str = "awaiting yb"; break;
|
||||
//case SENDING_CRYPTO_PROVIDE: str = "sending crypto provide"; break;
|
||||
case AWAITING_VC: str = "awaiting vc"; break;
|
||||
case AWAITING_CRYPTO_SELECT: str = "awaiting crypto select"; break;
|
||||
case AWAITING_PAD_D: str = "awaiting pad d"; break;
|
||||
//case SENDING_NONE: str = "sending plaintext handshake"; break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
setState( tr_handshake * handshake, short state )
|
||||
{
|
||||
dbgmsg( handshake, "setting to state [%s]", getStateName(state) );
|
||||
handshake->state = state;
|
||||
}
|
||||
|
||||
static void
|
||||
setReadState( tr_handshake * handshake, int state )
|
||||
{
|
||||
setState( handshake, state );
|
||||
//tr_peerIoSetIOMode( handshake->io, EV_READ, EV_WRITE );
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
buildHandshakeMessage( tr_handshake * handshake,
|
||||
int extensionPreference,
|
||||
int * setme_len )
|
||||
{
|
||||
uint8_t * buf = tr_new0( uint8_t, HANDSHAKE_SIZE );
|
||||
uint8_t * walk = buf;
|
||||
const uint8_t * torrentHash = tr_cryptoGetTorrentHash( handshake->crypto );
|
||||
|
||||
memcpy( walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
|
||||
walk += HANDSHAKE_NAME_LEN;
|
||||
memset( walk, 0, HANDSHAKE_FLAGS_LEN );
|
||||
switch( extensionPreference )
|
||||
{
|
||||
case HANDSHAKE_EXTPREF_LTEP_FORCE:
|
||||
HANDSHAKE_SET_EXTMSGS( walk );
|
||||
HANDSHAKE_SET_EXTPREF( walk, extensionPreference );
|
||||
break;
|
||||
|
||||
case HANDSHAKE_EXTPREF_LTEP_PREFER:
|
||||
HANDSHAKE_SET_EXTMSGS( walk );
|
||||
HANDSHAKE_SET_AZPROTO( walk );
|
||||
HANDSHAKE_SET_EXTPREF( walk, extensionPreference );
|
||||
break;
|
||||
|
||||
case HANDSHAKE_EXTPREF_AZMP_PREFER:
|
||||
HANDSHAKE_SET_EXTMSGS( walk );
|
||||
HANDSHAKE_SET_AZPROTO( walk );
|
||||
HANDSHAKE_SET_EXTPREF( walk, extensionPreference );
|
||||
break;
|
||||
|
||||
case HANDSHAKE_EXTPREF_AZMP_FORCE:
|
||||
HANDSHAKE_SET_AZPROTO( walk );
|
||||
HANDSHAKE_SET_EXTPREF( walk, extensionPreference );
|
||||
break;
|
||||
}
|
||||
|
||||
walk += HANDSHAKE_FLAGS_LEN;
|
||||
memcpy( walk, torrentHash, SHA_DIGEST_LENGTH );
|
||||
walk += SHA_DIGEST_LENGTH;
|
||||
memcpy( walk, getPeerId(), TR_ID_LEN );
|
||||
walk += TR_ID_LEN;
|
||||
|
||||
assert( walk-buf == HANDSHAKE_SIZE );
|
||||
*setme_len = walk - buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
**** OUTGOING CONNECTIONS
|
||||
****
|
||||
***/
|
||||
|
||||
/* 1 A->B: Diffie Hellman Ya, PadA */
|
||||
static void
|
||||
sendYa( tr_handshake * handshake )
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
const uint8_t * public_key;
|
||||
struct evbuffer * outbuf = evbuffer_new( );
|
||||
uint8_t pad_a[PadA_MAXLEN];
|
||||
|
||||
/* add our public key (Ya) */
|
||||
public_key = tr_cryptoGetMyPublicKey( handshake->crypto, &len );
|
||||
assert( len == KEY_LEN );
|
||||
assert( public_key != NULL );
|
||||
evbuffer_add( outbuf, public_key, len );
|
||||
|
||||
/* add some bullshit padding */
|
||||
len = tr_rand( PadA_MAXLEN );
|
||||
for( i=0; i<len; ++i )
|
||||
pad_a[i] = tr_rand( UCHAR_MAX );
|
||||
evbuffer_add( outbuf, pad_a, len );
|
||||
|
||||
/* send it */
|
||||
setReadState( handshake, AWAITING_YB );
|
||||
tr_peerIoWriteBuf( handshake->io, outbuf );
|
||||
|
||||
/* cleanup */
|
||||
evbuffer_free( outbuf );
|
||||
}
|
||||
|
||||
static int
|
||||
readYb( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
int isEncrypted;
|
||||
const uint8_t * secret;
|
||||
uint8_t yb[KEY_LEN];
|
||||
struct evbuffer * outbuf;
|
||||
size_t needlen = HANDSHAKE_NAME_LEN;
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
isEncrypted = memcmp( EVBUFFER_DATA(inbuf), HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
|
||||
if( isEncrypted ) {
|
||||
needlen = KEY_LEN;
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
}
|
||||
|
||||
dbgmsg( handshake, "got a %s handshake", (isEncrypted ? "encrypted" : "plaintext") );
|
||||
|
||||
handshake->peerSupportsEncryption = isEncrypted;
|
||||
tr_peerIoSetEncryption( handshake->io, isEncrypted ? PEER_ENCRYPTION_RC4
|
||||
: PEER_ENCRYPTION_NONE );
|
||||
if( !isEncrypted ) {
|
||||
setState( handshake, AWAITING_HANDSHAKE );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
/* compute the secret */
|
||||
evbuffer_remove( inbuf, yb, KEY_LEN );
|
||||
secret = tr_cryptoComputeSecret( handshake->crypto, yb );
|
||||
memcpy( handshake->mySecret, secret, KEY_LEN );
|
||||
|
||||
/* now send these: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S),
|
||||
* ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA) */
|
||||
outbuf = evbuffer_new( );
|
||||
|
||||
/* HASH('req1', S) */
|
||||
{
|
||||
uint8_t req1[SHA_DIGEST_LENGTH];
|
||||
tr_sha1( req1, "req1", 4, secret, KEY_LEN, NULL );
|
||||
evbuffer_add( outbuf, req1, SHA_DIGEST_LENGTH );
|
||||
}
|
||||
|
||||
/* HASH('req2', SKEY) xor HASH('req3', S) */
|
||||
{
|
||||
int i;
|
||||
uint8_t req2[SHA_DIGEST_LENGTH];
|
||||
uint8_t req3[SHA_DIGEST_LENGTH];
|
||||
uint8_t buf[SHA_DIGEST_LENGTH];
|
||||
tr_sha1( req2, "req2", 4, tr_cryptoGetTorrentHash(handshake->crypto), SHA_DIGEST_LENGTH, NULL );
|
||||
tr_sha1( req3, "req3", 4, secret, KEY_LEN, NULL );
|
||||
for( i=0; i<SHA_DIGEST_LENGTH; ++i )
|
||||
buf[i] = req2[i] ^ req3[i];
|
||||
evbuffer_add( outbuf, buf, SHA_DIGEST_LENGTH );
|
||||
}
|
||||
|
||||
/* ENCRYPT(VC, crypto_provide, len(PadC), PadC */
|
||||
{
|
||||
uint8_t vc[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t pad[512];
|
||||
uint16_t i, len;
|
||||
uint32_t crypto_provide;
|
||||
|
||||
tr_cryptoEncryptInit( handshake->crypto );
|
||||
|
||||
/* vc */
|
||||
tr_cryptoEncrypt( handshake->crypto, VC_LENGTH, vc, vc );
|
||||
evbuffer_add( outbuf, vc, VC_LENGTH );
|
||||
|
||||
/* crypto_provide */
|
||||
crypto_provide = 0;
|
||||
crypto_provide |= (1<<0); /* encryption */
|
||||
if( !handshake->shunUnencryptedPeers ) /* plaintext */
|
||||
crypto_provide |= (1<<1);
|
||||
assert( 1<=crypto_provide && crypto_provide<=3 );
|
||||
|
||||
crypto_provide = htonl( crypto_provide );
|
||||
tr_cryptoEncrypt( handshake->crypto, sizeof(crypto_provide), &crypto_provide, &crypto_provide );
|
||||
evbuffer_add( outbuf, &crypto_provide, sizeof(crypto_provide) );
|
||||
|
||||
/* len(padc) */
|
||||
i = len = tr_rand( 512 );
|
||||
i = htons( i );
|
||||
tr_cryptoEncrypt( handshake->crypto, sizeof(i), &i, &i );
|
||||
evbuffer_add( outbuf, &i, sizeof(i) );
|
||||
|
||||
/* padc */
|
||||
for( i=0; i<len; ++i ) pad[i] = tr_rand( UCHAR_MAX );
|
||||
tr_cryptoEncrypt( handshake->crypto, len, pad, pad );
|
||||
evbuffer_add( outbuf, pad, len );
|
||||
}
|
||||
|
||||
/* ENCRYPT len(IA)), ENCRYPT(IA) */
|
||||
{
|
||||
uint16_t i;
|
||||
int msgSize;
|
||||
uint8_t * msg = buildHandshakeMessage( handshake, HANDSHAKE_EXTPREF_LTEP_PREFER, &msgSize );
|
||||
|
||||
i = htons( msgSize );
|
||||
tr_cryptoEncrypt( handshake->crypto, sizeof(uint16_t), &i, &i );
|
||||
evbuffer_add( outbuf, &i, sizeof(uint16_t) );
|
||||
|
||||
tr_cryptoEncrypt( handshake->crypto, msgSize, msg, msg );
|
||||
evbuffer_add( outbuf, msg, HANDSHAKE_SIZE );
|
||||
handshake->haveSentBitTorrentHandshake = 1;
|
||||
|
||||
tr_free( msg );
|
||||
}
|
||||
|
||||
/* send it */
|
||||
tr_cryptoDecryptInit( handshake->crypto );
|
||||
setReadState( handshake, AWAITING_VC );
|
||||
tr_peerIoWriteBuf( handshake->io, outbuf );
|
||||
|
||||
/* cleanup */
|
||||
evbuffer_free( outbuf );
|
||||
return READ_DONE;
|
||||
}
|
||||
|
||||
static int
|
||||
readVC( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
const uint8_t key[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
const int key_len = VC_LENGTH;
|
||||
uint8_t tmp[VC_LENGTH];
|
||||
|
||||
/* note: this works w/o having to `unwind' the buffer if
|
||||
* we read too much, but it is pretty brute-force.
|
||||
* it would be nice to make this cleaner. */
|
||||
for( ;; )
|
||||
{
|
||||
if( EVBUFFER_LENGTH(inbuf) < VC_LENGTH ) {
|
||||
dbgmsg( handshake, "not enough bytes... returning read_more" );
|
||||
return READ_MORE;
|
||||
}
|
||||
|
||||
memcpy( tmp, EVBUFFER_DATA(inbuf), key_len );
|
||||
tr_cryptoDecryptInit( handshake->crypto );
|
||||
tr_cryptoDecrypt( handshake->crypto, key_len, tmp, tmp );
|
||||
if( !memcmp( tmp, key, key_len ) )
|
||||
break;
|
||||
|
||||
evbuffer_drain( inbuf, 1 );
|
||||
}
|
||||
|
||||
dbgmsg( handshake, "got it!" );
|
||||
evbuffer_drain( inbuf, key_len );
|
||||
setState( handshake, AWAITING_CRYPTO_SELECT );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
static int
|
||||
readCryptoSelect( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
uint32_t crypto_select;
|
||||
uint16_t pad_d_len;
|
||||
const size_t needlen = sizeof(uint32_t) + sizeof(uint16_t);
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
tr_peerIoReadUint32( handshake->io, inbuf, &crypto_select );
|
||||
assert( crypto_select==1 || crypto_select==2 );
|
||||
handshake->crypto_select = crypto_select;
|
||||
dbgmsg( handshake, "crypto select is %d", (int)crypto_select );
|
||||
|
||||
tr_peerIoReadUint16( handshake->io, inbuf, &pad_d_len );
|
||||
dbgmsg( handshake, "pad_d_len is %d", (int)pad_d_len );
|
||||
assert( pad_d_len <= 512 );
|
||||
handshake->pad_d_len = pad_d_len;
|
||||
|
||||
setState( handshake, AWAITING_PAD_D );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
static int
|
||||
readPadD( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
const size_t needlen = handshake->pad_d_len;
|
||||
uint8_t * tmp;
|
||||
|
||||
dbgmsg( handshake, "pad d: need %d, got %d", (int)needlen, (int)EVBUFFER_LENGTH(inbuf) );
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
tmp = tr_new( uint8_t, needlen );
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, tmp, needlen );
|
||||
tr_free( tmp );
|
||||
|
||||
tr_peerIoSetEncryption( handshake->io,
|
||||
handshake->crypto_select );
|
||||
|
||||
setState( handshake, AWAITING_HANDSHAKE );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
**** INCOMING CONNECTIONS
|
||||
****
|
||||
***/
|
||||
|
||||
static void
|
||||
tr_handshakeDone( tr_handshake * handshake, int isConnected );
|
||||
|
||||
static int
|
||||
readHandshake( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
int i;
|
||||
uint8_t ltep = 0;
|
||||
uint8_t azmp = 0;
|
||||
uint8_t pstrlen;
|
||||
uint8_t * pstr;
|
||||
uint8_t reserved[HANDSHAKE_FLAGS_LEN];
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
|
||||
dbgmsg( handshake, "payload: need %d, got %d\n", (int)HANDSHAKE_SIZE, (int)EVBUFFER_LENGTH(inbuf) );
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < HANDSHAKE_SIZE )
|
||||
return READ_MORE;
|
||||
|
||||
pstrlen = EVBUFFER_DATA(inbuf)[0]; /* peek, don't read. We may be
|
||||
handing inbuf to AWAITING_YA */
|
||||
|
||||
if( pstrlen == 19 ) /* unencrypted */
|
||||
{
|
||||
tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_NONE );
|
||||
}
|
||||
else /* encrypted or corrupt */
|
||||
{
|
||||
tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_RC4 );
|
||||
|
||||
if( tr_peerIoIsIncoming( handshake->io ) )
|
||||
{
|
||||
dbgmsg( handshake, "I think peer is sending us an encrypted handshake..." );
|
||||
setState( handshake, AWAITING_YA );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
tr_cryptoDecrypt( handshake->crypto, 1, &pstrlen, &pstrlen );
|
||||
|
||||
if( pstrlen != 19 )
|
||||
{
|
||||
dbgmsg( handshake, "I think peer has sent us a corrupt handshake..." );
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
return READ_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
evbuffer_drain( inbuf, 1 );
|
||||
|
||||
/* pstr (BitTorrent) */
|
||||
pstr = tr_new( uint8_t, pstrlen+1 );
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, pstr, pstrlen );
|
||||
pstr[pstrlen] = '\0';
|
||||
if( strcmp( (char*)pstr, "BitTorrent protocol" ) ) {
|
||||
tr_free( pstr );
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
return READ_DONE;
|
||||
}
|
||||
tr_free( pstr );
|
||||
|
||||
/* reserved bytes */
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, reserved, sizeof(reserved) );
|
||||
|
||||
/* torrent hash */
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, hash, sizeof(hash) );
|
||||
if( tr_peerIoIsIncoming( handshake->io ) )
|
||||
{
|
||||
if( !tr_torrentExists( handshake->handle, hash ) )
|
||||
{
|
||||
dbgmsg( handshake, "peer is trying to connect to us for a torrent we don't have." );
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
return READ_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( !tr_peerIoHasTorrentHash( handshake->io ) );
|
||||
tr_peerIoSetTorrentHash( handshake->io, hash );
|
||||
}
|
||||
}
|
||||
else /* outgoing */
|
||||
{
|
||||
assert( tr_torrentExists( handshake->handle, hash ) );
|
||||
assert( tr_peerIoHasTorrentHash( handshake->io ) );
|
||||
if( memcmp( hash, tr_peerIoGetTorrentHash(handshake->io), SHA_DIGEST_LENGTH ) )
|
||||
{
|
||||
dbgmsg( handshake, "peer returned the wrong hash. wtf?" );
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
return READ_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* peer id */
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, handshake->peer_id, sizeof(handshake->peer_id) );
|
||||
tr_peerIoSetPeersId( handshake->io, handshake->peer_id );
|
||||
handshake->havePeerID = TRUE;
|
||||
dbgmsg( handshake, "peer-id is [%*.*s]", PEER_ID_LEN, PEER_ID_LEN, handshake->peer_id );
|
||||
if( !memcmp( handshake->peer_id, getPeerId(), PEER_ID_LEN ) ) {
|
||||
dbgmsg( handshake, "streuth! we've connected to ourselves." );
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
return READ_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
*** Extension negotiation
|
||||
**/
|
||||
|
||||
ltep = HANDSHAKE_HAS_EXTMSGS( reserved );
|
||||
azmp = HANDSHAKE_HAS_AZPROTO( reserved );
|
||||
if( ltep && azmp ) {
|
||||
switch( HANDSHAKE_GET_EXTPREF( reserved ) ) {
|
||||
case HANDSHAKE_EXTPREF_LTEP_FORCE:
|
||||
case HANDSHAKE_EXTPREF_LTEP_PREFER:
|
||||
azmp = 0;
|
||||
break;
|
||||
case HANDSHAKE_EXTPREF_AZMP_FORCE:
|
||||
case HANDSHAKE_EXTPREF_AZMP_PREFER:
|
||||
ltep = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert( !ltep || !azmp );
|
||||
if( ltep ) { i = LT_EXTENSIONS_LTEP; dbgmsg(handshake,"using ltep" ); }
|
||||
else if( azmp ) { i = LT_EXTENSIONS_AZMP; dbgmsg(handshake,"using azmp" ); }
|
||||
else { i = LT_EXTENSIONS_NONE; dbgmsg(handshake,"using no extensions" ); }
|
||||
tr_peerIoSetExtension( handshake->io, i );
|
||||
|
||||
|
||||
/**
|
||||
*** If this is an incoming message, then we need to send a response handshake
|
||||
**/
|
||||
|
||||
if( !handshake->haveSentBitTorrentHandshake )
|
||||
{
|
||||
const int ext = ltep ? HANDSHAKE_EXTPREF_LTEP_FORCE
|
||||
: HANDSHAKE_EXTPREF_AZMP_FORCE;
|
||||
int msgSize;
|
||||
uint8_t * msg = buildHandshakeMessage( handshake, ext, &msgSize );
|
||||
tr_peerIoWrite( handshake->io, msg, msgSize );
|
||||
tr_free( msg );
|
||||
handshake->haveSentBitTorrentHandshake = 1;
|
||||
}
|
||||
|
||||
/* we've completed the BT handshake... pass the work on to peer-msgs */
|
||||
tr_handshakeDone( handshake, TRUE );
|
||||
return READ_DONE;
|
||||
}
|
||||
|
||||
static int
|
||||
readYa( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
uint8_t ya[KEY_LEN];
|
||||
uint8_t *walk, outbuf[KEY_LEN + PadB_MAXLEN];
|
||||
const uint8_t *myKey, *secret;
|
||||
int len;
|
||||
|
||||
if( EVBUFFER_LENGTH( inbuf ) < KEY_LEN )
|
||||
return READ_MORE;
|
||||
|
||||
/* read the incoming peer's public key */
|
||||
evbuffer_remove( inbuf, ya, KEY_LEN );
|
||||
secret = tr_cryptoComputeSecret( handshake->crypto, ya );
|
||||
memcpy( handshake->mySecret, secret, KEY_LEN );
|
||||
tr_sha1( handshake->myReq1, "req1", 4, secret, KEY_LEN, NULL );
|
||||
|
||||
/* send our public key to the peer */
|
||||
walk = outbuf;
|
||||
myKey = tr_cryptoGetMyPublicKey( handshake->crypto, &len );
|
||||
memcpy( walk, myKey, len );
|
||||
len = tr_rand( PadB_MAXLEN );
|
||||
while( len-- )
|
||||
*walk++ = tr_rand( UCHAR_MAX );
|
||||
|
||||
setReadState( handshake, AWAITING_PAD_A );
|
||||
tr_peerIoWrite( handshake->io, outbuf, walk-outbuf );
|
||||
|
||||
return READ_DONE;
|
||||
}
|
||||
|
||||
static int
|
||||
readPadA( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
uint8_t * pch;
|
||||
|
||||
/**
|
||||
*** Resynchronizing on HASH('req1',S)
|
||||
**/
|
||||
|
||||
pch = memchr( EVBUFFER_DATA(inbuf),
|
||||
handshake->myReq1[0],
|
||||
EVBUFFER_LENGTH(inbuf) );
|
||||
if( pch == NULL ) {
|
||||
evbuffer_drain( inbuf, EVBUFFER_LENGTH(inbuf) );
|
||||
return READ_MORE;
|
||||
}
|
||||
evbuffer_drain( inbuf, pch-EVBUFFER_DATA(inbuf) );
|
||||
if( EVBUFFER_LENGTH(inbuf) < SHA_DIGEST_LENGTH )
|
||||
return READ_MORE;
|
||||
if( memcmp( EVBUFFER_DATA(inbuf), handshake->myReq1, SHA_DIGEST_LENGTH ) ) {
|
||||
evbuffer_drain( inbuf, 1 );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
setState( handshake, AWAITING_CRYPTO_PROVIDE );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
static int
|
||||
readCryptoProvide( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
/* HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC)) */
|
||||
|
||||
int i;
|
||||
uint8_t vc_in[VC_LENGTH];
|
||||
uint8_t req2[SHA_DIGEST_LENGTH];
|
||||
uint8_t req3[SHA_DIGEST_LENGTH];
|
||||
uint8_t obfuscatedTorrentHash[SHA_DIGEST_LENGTH];
|
||||
uint16_t padc_len = 0;
|
||||
uint32_t crypto_provide = 0;
|
||||
const size_t needlen = SHA_DIGEST_LENGTH + VC_LENGTH + sizeof(crypto_provide) + sizeof(padc_len);
|
||||
tr_torrent * tor = NULL;
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
/* TODO: confirm they sent HASH('req1',S) here? */
|
||||
evbuffer_drain( inbuf, SHA_DIGEST_LENGTH );
|
||||
|
||||
/* This next piece is HASH('req2', SKEY) xor HASH('req3', S) ...
|
||||
* we can get the first half of that (the obufscatedTorrentHash)
|
||||
* by building the latter and xor'ing it with what the peer sent us */
|
||||
dbgmsg( handshake, "reading obfuscated torrent hash...\n" );
|
||||
evbuffer_remove( inbuf, req2, SHA_DIGEST_LENGTH );
|
||||
tr_sha1( req3, "req3", 4, handshake->mySecret, KEY_LEN, NULL );
|
||||
for( i=0; i<SHA_DIGEST_LENGTH; ++i )
|
||||
obfuscatedTorrentHash[i] = req2[i] ^ req3[i];
|
||||
tor = tr_torrentFindFromObfuscatedHash( handshake->handle, obfuscatedTorrentHash );
|
||||
assert( tor != NULL );
|
||||
dbgmsg( handshake, "found the torrent; it's [%s]\n", tor->info.name );
|
||||
tr_peerIoSetTorrentHash( handshake->io, tor->info.hash );
|
||||
|
||||
/* next part: ENCRYPT(VC, crypto_provide, len(PadC), */
|
||||
|
||||
tr_cryptoDecryptInit( handshake->crypto );
|
||||
|
||||
tr_peerIoReadBytes( handshake->io, inbuf, vc_in, VC_LENGTH );
|
||||
|
||||
tr_peerIoReadUint32( handshake->io, inbuf, &crypto_provide );
|
||||
dbgmsg( handshake, "crypto_provide is %d\n", (int)crypto_provide );
|
||||
|
||||
tr_peerIoReadUint16( handshake->io, inbuf, &padc_len );
|
||||
dbgmsg( handshake, "padc is %d\n", (int)padc_len );
|
||||
handshake->pad_c_len = padc_len;
|
||||
setState( handshake, AWAITING_PAD_C );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
static int
|
||||
readPadC( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
uint16_t ia_len;
|
||||
const size_t needlen = handshake->pad_c_len + sizeof(uint16_t);
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
evbuffer_drain( inbuf, needlen );
|
||||
|
||||
tr_peerIoReadUint16( handshake->io, inbuf, &ia_len );
|
||||
dbgmsg( handshake, "ia_len is %d", (int)ia_len );
|
||||
handshake->ia_len = ia_len;
|
||||
setState( handshake, AWAITING_IA );
|
||||
return READ_AGAIN;
|
||||
}
|
||||
|
||||
static int
|
||||
readIA( tr_handshake * handshake, struct evbuffer * inbuf )
|
||||
{
|
||||
const size_t needlen = handshake->ia_len;
|
||||
|
||||
if( EVBUFFER_LENGTH(inbuf) < needlen )
|
||||
return READ_MORE;
|
||||
|
||||
return readHandshake( handshake, inbuf );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
****
|
||||
****
|
||||
***/
|
||||
|
||||
static ReadState
|
||||
canRead( struct bufferevent * evin, void * arg )
|
||||
{
|
||||
tr_handshake * handshake = (tr_handshake *) arg;
|
||||
struct evbuffer * inbuf = EVBUFFER_INPUT ( evin );
|
||||
ReadState ret;
|
||||
dbgmsg( handshake, "handling canRead; state is [%s]\n", getStateName(handshake->state) );
|
||||
|
||||
switch( handshake->state )
|
||||
{
|
||||
case AWAITING_HANDSHAKE: ret = readHandshake ( handshake, inbuf ); break;
|
||||
case AWAITING_YA: ret = readYa ( handshake, inbuf ); break;
|
||||
case AWAITING_PAD_A: ret = readPadA ( handshake, inbuf ); break;
|
||||
case AWAITING_CRYPTO_PROVIDE: ret = readCryptoProvide( handshake, inbuf ); break;
|
||||
case AWAITING_PAD_C: ret = readPadC ( handshake, inbuf ); break;
|
||||
case AWAITING_IA: ret = readIA ( handshake, inbuf ); break;
|
||||
|
||||
case AWAITING_YB: ret = readYb ( handshake, inbuf ); break;
|
||||
case AWAITING_VC: ret = readVC ( handshake, inbuf ); break;
|
||||
case AWAITING_CRYPTO_SELECT: ret = readCryptoSelect ( handshake, inbuf ); break;
|
||||
case AWAITING_PAD_D: ret = readPadD ( handshake, inbuf ); break;
|
||||
|
||||
default: assert( 0 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
fireDoneFunc( tr_handshake * handshake, int isConnected )
|
||||
{
|
||||
const uint8_t * peer_id = isConnected && handshake->havePeerID
|
||||
? handshake->peer_id
|
||||
: NULL;
|
||||
(*handshake->doneCB)( handshake,
|
||||
handshake->io,
|
||||
isConnected,
|
||||
peer_id,
|
||||
handshake->peerSupportsEncryption,
|
||||
handshake->doneUserData );
|
||||
}
|
||||
|
||||
void
|
||||
tr_handshakeDone( tr_handshake * handshake, int isOK )
|
||||
{
|
||||
dbgmsg( handshake, "handshakeDone: %s", isOK ? "connected" : "aborting" );
|
||||
tr_peerIoSetIOFuncs( handshake->io, NULL, NULL, NULL, NULL );
|
||||
fireDoneFunc( handshake, isOK );
|
||||
tr_free( handshake );
|
||||
}
|
||||
|
||||
void
|
||||
tr_handshakeAbort( tr_handshake * handshake )
|
||||
{
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
gotError( struct bufferevent * evbuf UNUSED, short what UNUSED, void * arg )
|
||||
{
|
||||
tr_handshake * handshake = (tr_handshake *) arg;
|
||||
|
||||
/* if the error happened while we were sending a public key, we might
|
||||
* have encountered a peer that doesn't do encryption... reconnect and
|
||||
* try a plaintext handshake */
|
||||
if( ( ( handshake->state == AWAITING_YB ) || ( handshake->state == AWAITING_VC ) )
|
||||
&& ( !handshake->shunUnencryptedPeers )
|
||||
&& ( !tr_peerIoReconnect( handshake->io ) ) )
|
||||
{
|
||||
int msgSize;
|
||||
uint8_t * msg = buildHandshakeMessage( handshake, HANDSHAKE_EXTPREF_LTEP_PREFER, &msgSize );
|
||||
setReadState( handshake, AWAITING_HANDSHAKE );
|
||||
tr_peerIoWrite( handshake->io, msg, msgSize );
|
||||
tr_free( msg );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_handshakeDone( handshake, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
tr_handshake*
|
||||
tr_handshakeNew( tr_peerIo * io,
|
||||
tr_encryption_mode encryption_mode,
|
||||
handshakeDoneCB doneCB,
|
||||
void * doneUserData )
|
||||
{
|
||||
tr_handshake * handshake;
|
||||
|
||||
// w00t
|
||||
//static int count = 0;
|
||||
//if( count++ ) return NULL;
|
||||
|
||||
handshake = tr_new0( tr_handshake, 1 );
|
||||
handshake->io = io;
|
||||
handshake->crypto = tr_peerIoGetCrypto( io );
|
||||
handshake->shunUnencryptedPeers = encryption_mode==TR_ENCRYPTION_REQUIRED;
|
||||
handshake->doneCB = doneCB;
|
||||
handshake->doneUserData = doneUserData;
|
||||
handshake->handle = tr_peerIoGetHandle( io );
|
||||
|
||||
tr_peerIoSetIOMode( io, EV_READ|EV_WRITE, 0 );
|
||||
tr_peerIoSetIOFuncs( io, canRead, NULL, gotError, handshake );
|
||||
|
||||
dbgmsg( handshake, "new handshake for io %p", io );
|
||||
|
||||
if( tr_peerIoIsIncoming( io ) )
|
||||
setReadState( handshake, AWAITING_HANDSHAKE );
|
||||
else
|
||||
sendYa( handshake );
|
||||
|
||||
return handshake;
|
||||
}
|
||||
|
||||
const struct in_addr *
|
||||
tr_handshakeGetAddr( const struct tr_handshake * handshake, uint16_t * port )
|
||||
{
|
||||
assert( handshake != NULL );
|
||||
assert( handshake->io != NULL );
|
||||
|
||||
return tr_peerIoGetAddress( handshake->io, port );
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_HANDSHAKE_H
|
||||
#define TR_HANDSHAKE_H
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
struct in_addr;
|
||||
struct tr_peerIo;
|
||||
typedef struct tr_handshake tr_handshake;
|
||||
|
||||
typedef void (*handshakeDoneCB)(struct tr_handshake * handshake,
|
||||
struct tr_peerIo * io,
|
||||
int isConnected,
|
||||
const uint8_t * peerId,
|
||||
int peerSupportsEncryption,
|
||||
void * userData );
|
||||
|
||||
tr_handshake * tr_handshakeNew( struct tr_peerIo * io,
|
||||
tr_encryption_mode encryptionMode,
|
||||
handshakeDoneCB doneCB,
|
||||
void * doneUserData );
|
||||
|
||||
const struct in_addr * tr_handshakeGetAddr( const struct tr_handshake * handshake,
|
||||
uint16_t * setme_port );
|
||||
|
||||
void tr_handshakeAbort( tr_handshake * handshake );
|
||||
|
||||
#endif
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "evdns.h"
|
||||
|
||||
#ifdef __BEOS__
|
||||
extern int vasprintf( char **, const char *, va_list );
|
||||
#endif
|
||||
|
@ -84,7 +86,6 @@ struct tr_http_s {
|
|||
#define HTTP_LENGTH_FIXED 3
|
||||
#define HTTP_LENGTH_CHUNKED 4
|
||||
char lengthtype;
|
||||
tr_resolve_t * resolve;
|
||||
char * host;
|
||||
int port;
|
||||
int sock;
|
||||
|
@ -567,6 +568,20 @@ tr_httpGetBody( tr_http_t * http, const char ** buf, int * len )
|
|||
*len = http->body.used;
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_cb( int result, char type, int count, int ttl, void *addresses, void *arg)
|
||||
{
|
||||
tr_http_t * http = (tr_http_t *) arg;
|
||||
|
||||
if( (result!=DNS_ERR_NONE) || (type!=DNS_IPv4_A) || (ttl<0) || (count<1) )
|
||||
http->state = HTTP_STATE_ERROR;
|
||||
else {
|
||||
struct in_addr *in_addrs = addresses;
|
||||
http->sock = tr_netOpenTCP( &in_addrs[0], htons(http->port), 1 );
|
||||
http->state = HTTP_STATE_CONNECT;
|
||||
}
|
||||
}
|
||||
|
||||
tr_tristate_t
|
||||
tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
||||
{
|
||||
|
@ -586,8 +601,7 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
|||
http->state = HTTP_STATE_CONNECT;
|
||||
break;
|
||||
}
|
||||
http->resolve = tr_netResolveInit( http->host );
|
||||
if( NULL == http->resolve )
|
||||
if( evdns_resolve_ipv4( http->host, 0, resolve_cb, http ) )
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
@ -595,19 +609,7 @@ tr_httpPulse( tr_http_t * http, const char ** data, int * len )
|
|||
/* fallthrough */
|
||||
|
||||
case HTTP_STATE_RESOLVE:
|
||||
switch( tr_netResolvePulse( http->resolve, &addr ) )
|
||||
{
|
||||
case TR_NET_WAIT:
|
||||
return TR_NET_WAIT;
|
||||
case TR_NET_ERROR:
|
||||
goto err;
|
||||
case TR_NET_OK:
|
||||
tr_netResolveClose( http->resolve );
|
||||
http->resolve = NULL;
|
||||
http->sock = tr_netOpenTCP( &addr, htons( http->port ), 1 );
|
||||
http->state = HTTP_STATE_CONNECT;
|
||||
}
|
||||
/* fallthrough */
|
||||
return TR_NET_WAIT;
|
||||
|
||||
case HTTP_STATE_CONNECT:
|
||||
switch( sendrequest( http ) )
|
||||
|
@ -897,15 +899,8 @@ tr_httpWhatsMyAddress( tr_http_t * http )
|
|||
void
|
||||
tr_httpClose( tr_http_t * http )
|
||||
{
|
||||
if( NULL != http->resolve )
|
||||
{
|
||||
tr_netResolveClose( http->resolve );
|
||||
}
|
||||
free( http->host );
|
||||
if( 0 <= http->sock )
|
||||
{
|
||||
tr_netClose( http->sock );
|
||||
}
|
||||
tr_netClose( http->sock );
|
||||
free( http->header.buf );
|
||||
free( http->body.buf );
|
||||
free( http );
|
||||
|
|
|
@ -20,38 +20,41 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "completion.h"
|
||||
#include "crypto.h"
|
||||
#include "fastresume.h"
|
||||
#include "fdlimit.h"
|
||||
#include "inout.h"
|
||||
#include "list.h"
|
||||
#include "net.h"
|
||||
#include "peer.h"
|
||||
#include "sha1.h"
|
||||
#include "platform.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct tr_io_s
|
||||
struct tr_io
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
tr_torrent * tor;
|
||||
};
|
||||
|
||||
/****
|
||||
***** Low-level IO functions
|
||||
****/
|
||||
|
||||
enum { TR_IO_READ, TR_IO_WRITE };
|
||||
|
||||
#ifdef WIN32
|
||||
#define lseek _lseeki64
|
||||
#endif
|
||||
|
||||
enum { TR_IO_READ, TR_IO_WRITE };
|
||||
|
||||
static int
|
||||
readOrWriteBytes ( const tr_torrent_t * tor,
|
||||
readOrWriteBytes ( const tr_torrent * tor,
|
||||
int ioMode,
|
||||
int fileIndex,
|
||||
uint64_t fileOffset,
|
||||
void * buf,
|
||||
size_t buflen )
|
||||
{
|
||||
const tr_info_t * info = &tor->info;
|
||||
const tr_file_t * file = &info->files[fileIndex];
|
||||
const tr_info * info = &tor->info;
|
||||
const tr_file * file = &info->files[fileIndex];
|
||||
typedef size_t (* iofunc) ( int, void *, size_t );
|
||||
iofunc func = ioMode == TR_IO_READ ? (iofunc)read : (iofunc)write;
|
||||
char path[MAX_PATH_LENGTH];
|
||||
|
@ -85,13 +88,13 @@ readOrWriteBytes ( const tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static void
|
||||
findFileLocation ( const tr_torrent_t * tor,
|
||||
findFileLocation ( const tr_torrent * tor,
|
||||
int pieceIndex,
|
||||
int pieceOffset,
|
||||
int * fileIndex,
|
||||
uint64_t * fileOffset )
|
||||
{
|
||||
const tr_info_t * info = &tor->info;
|
||||
const tr_info * info = &tor->info;
|
||||
|
||||
int i;
|
||||
uint64_t piecePos = ((uint64_t)pieceIndex * info->pieceSize) + pieceOffset;
|
||||
|
@ -112,14 +115,14 @@ findFileLocation ( const tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static int
|
||||
ensureMinimumFileSize ( const tr_torrent_t * tor,
|
||||
ensureMinimumFileSize ( const tr_torrent * tor,
|
||||
int fileIndex,
|
||||
uint64_t minSize ) /* in bytes */
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct stat sb;
|
||||
const tr_file_t * file = &tor->info.files[fileIndex];
|
||||
const tr_file * file = &tor->info.files[fileIndex];
|
||||
|
||||
assert ( 0<=fileIndex && fileIndex<tor->info.fileCount );
|
||||
assert ( minSize <= file->length );
|
||||
|
@ -143,17 +146,17 @@ ensureMinimumFileSize ( const tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
static int
|
||||
readOrWritePiece ( tr_torrent_t * tor,
|
||||
int ioMode,
|
||||
int pieceIndex,
|
||||
int pieceOffset,
|
||||
uint8_t * buf,
|
||||
size_t buflen )
|
||||
readOrWritePiece ( tr_torrent * tor,
|
||||
int ioMode,
|
||||
int pieceIndex,
|
||||
int pieceOffset,
|
||||
uint8_t * buf,
|
||||
size_t buflen )
|
||||
{
|
||||
int ret = 0;
|
||||
int fileIndex;
|
||||
uint64_t fileOffset;
|
||||
const tr_info_t * info = &tor->info;
|
||||
const tr_info * info = &tor->info;
|
||||
|
||||
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
||||
assert( buflen <= (size_t) tr_torPieceCountBytes( tor, pieceIndex ) );
|
||||
|
@ -162,7 +165,7 @@ readOrWritePiece ( tr_torrent_t * tor,
|
|||
|
||||
while( buflen && !ret )
|
||||
{
|
||||
const tr_file_t * file = &info->files[fileIndex];
|
||||
const tr_file * file = &info->files[fileIndex];
|
||||
const uint64_t bytesThisPass = MIN( buflen, file->length - fileOffset );
|
||||
|
||||
if( ioMode == TR_IO_WRITE )
|
||||
|
@ -181,15 +184,15 @@ readOrWritePiece ( tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
int
|
||||
tr_ioRead( tr_io_t * io, int pieceIndex, int begin, int len, uint8_t * buf )
|
||||
tr_ioRead( tr_torrent * tor, int pieceIndex, int begin, int len, uint8_t * buf )
|
||||
{
|
||||
return readOrWritePiece ( io->tor, TR_IO_READ, pieceIndex, begin, buf, len );
|
||||
return readOrWritePiece ( tor, TR_IO_READ, pieceIndex, begin, buf, len );
|
||||
}
|
||||
|
||||
int
|
||||
tr_ioWrite( tr_io_t * io, int pieceIndex, int begin, int len, uint8_t * buf )
|
||||
tr_ioWrite( tr_torrent * tor, int pieceIndex, int begin, int len, uint8_t * buf )
|
||||
{
|
||||
return readOrWritePiece ( io->tor, TR_IO_WRITE, pieceIndex, begin, buf, len );
|
||||
return readOrWritePiece ( tor, TR_IO_WRITE, pieceIndex, begin, buf, len );
|
||||
}
|
||||
|
||||
/****
|
||||
|
@ -197,14 +200,14 @@ tr_ioWrite( tr_io_t * io, int pieceIndex, int begin, int len, uint8_t * buf )
|
|||
****/
|
||||
|
||||
static int
|
||||
tr_ioRecalculateHash ( tr_torrent_t * tor,
|
||||
tr_ioRecalculateHash ( tr_torrent * tor,
|
||||
int pieceIndex,
|
||||
uint8_t * setme )
|
||||
{
|
||||
int n;
|
||||
int ret;
|
||||
uint8_t * buf;
|
||||
const tr_info_t * info;
|
||||
const tr_info * info;
|
||||
|
||||
assert( tor != NULL );
|
||||
assert( setme != NULL );
|
||||
|
@ -215,16 +218,15 @@ tr_ioRecalculateHash ( tr_torrent_t * tor,
|
|||
|
||||
buf = malloc( n );
|
||||
ret = readOrWritePiece ( tor, TR_IO_READ, pieceIndex, 0, buf, n );
|
||||
if( !ret ) {
|
||||
SHA1( buf, n, setme );
|
||||
}
|
||||
if( !ret )
|
||||
tr_sha1( setme, buf, n, NULL );
|
||||
free( buf );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
checkPiece ( tr_torrent_t * tor, int pieceIndex )
|
||||
checkPiece ( tr_torrent * tor, int pieceIndex )
|
||||
{
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
int ret = tr_ioRecalculateHash( tor, pieceIndex, hash )
|
||||
|
@ -234,81 +236,24 @@ checkPiece ( tr_torrent_t * tor, int pieceIndex )
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
tr_ioCheckFiles( tr_torrent_t * tor )
|
||||
{
|
||||
assert( tor != NULL );
|
||||
assert( tor->completion != NULL );
|
||||
assert( tor->info.pieceCount > 0 );
|
||||
|
||||
if( tor->uncheckedPieces != NULL )
|
||||
{
|
||||
int i;
|
||||
|
||||
/* remove the unchecked pieces from completion... */
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
if( tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
||||
tr_cpPieceRem( tor->completion, i );
|
||||
|
||||
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
||||
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
{
|
||||
if( !tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
||||
continue;
|
||||
|
||||
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
||||
tr_bitfieldRem( tor->uncheckedPieces, i );
|
||||
}
|
||||
|
||||
tr_bitfieldFree( tor->uncheckedPieces );
|
||||
tor->uncheckedPieces = NULL;
|
||||
tor->fastResumeDirty = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
***** Life Cycle
|
||||
****/
|
||||
|
||||
tr_io_t*
|
||||
tr_ioNew ( tr_torrent_t * tor )
|
||||
{
|
||||
tr_io_t * io = tr_calloc( 1, sizeof( tr_io_t ) );
|
||||
io->tor = tor;
|
||||
return io;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_ioSync( tr_io_t * io )
|
||||
tr_ioClose( const tr_torrent * tor )
|
||||
{
|
||||
if( io != NULL )
|
||||
{
|
||||
int i;
|
||||
const tr_info_t * info = &io->tor->info;
|
||||
int i;
|
||||
const tr_info * info = &tor->info;
|
||||
|
||||
for( i=0; i<info->fileCount; ++i )
|
||||
tr_fdFileClose( io->tor->destination, info->files[i].name );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_ioClose( tr_io_t * io )
|
||||
{
|
||||
if( io != NULL )
|
||||
{
|
||||
tr_ioSync( io );
|
||||
tr_free( io );
|
||||
}
|
||||
for( i=0; i<info->fileCount; ++i )
|
||||
tr_fdFileClose( tor->destination, info->files[i].name );
|
||||
}
|
||||
|
||||
int
|
||||
tr_ioHash( tr_io_t * io, int pieceIndex )
|
||||
tr_ioHash( tr_torrent * tor, int pieceIndex )
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
tr_torrent_t * tor = io->tor;
|
||||
const int success = !checkPiece( tor, pieceIndex );
|
||||
|
||||
if( success )
|
||||
|
@ -324,9 +269,137 @@ tr_ioHash( tr_io_t * io, int pieceIndex )
|
|||
ret = TR_ERROR;
|
||||
}
|
||||
|
||||
/* Assign blame or credit to peers */
|
||||
for( i=0; i<tor->peerCount; ++i )
|
||||
tr_peerBlame( tor->peers[i], pieceIndex, success );
|
||||
tr_peerMgrSetBlame( tor->handle->peerMgr, tor->info.hash, pieceIndex, success );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct recheck_node
|
||||
{
|
||||
tr_torrent * torrent;
|
||||
tr_recheck_done_cb recheck_done_cb;
|
||||
run_status_t status_when_done;
|
||||
};
|
||||
|
||||
static void
|
||||
fireCheckDone( tr_torrent * torrent,
|
||||
tr_recheck_done_cb recheck_done_cb,
|
||||
run_status_t status_when_done )
|
||||
{
|
||||
torrent->runStatus = status_when_done;
|
||||
(*recheck_done_cb)( torrent );
|
||||
}
|
||||
|
||||
struct recheck_node currentNode;
|
||||
|
||||
static tr_list * recheckList = NULL;
|
||||
|
||||
static tr_thread * recheckThread = NULL;
|
||||
|
||||
static int stopCurrent = FALSE;
|
||||
|
||||
static void
|
||||
recheckThreadFunc( void * unused UNUSED )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
int i;
|
||||
tr_torrent * tor;
|
||||
|
||||
struct recheck_node * node = (struct recheck_node*) recheckList ? recheckList->data : NULL;
|
||||
if( node == NULL )
|
||||
break;
|
||||
|
||||
currentNode = *node;
|
||||
tor = currentNode.torrent;
|
||||
tr_list_remove_data( &recheckList, node );
|
||||
tr_free( node );
|
||||
|
||||
if( tor->uncheckedPieces == NULL ) {
|
||||
fireCheckDone( tor, currentNode.recheck_done_cb, currentNode.status_when_done );
|
||||
continue;
|
||||
}
|
||||
|
||||
tor->runStatus = TR_RUN_CHECKING;
|
||||
|
||||
/* remove the unchecked pieces from completion... */
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
if( tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
||||
tr_cpPieceRem( tor->completion, i );
|
||||
|
||||
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
||||
|
||||
for( i=0; i<tor->info.pieceCount && !stopCurrent; ++i )
|
||||
{
|
||||
if( !tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
||||
continue;
|
||||
|
||||
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
||||
tr_bitfieldRem( tor->uncheckedPieces, i );
|
||||
}
|
||||
|
||||
if( !stopCurrent )
|
||||
{
|
||||
tr_bitfieldFree( tor->uncheckedPieces );
|
||||
tor->uncheckedPieces = NULL;
|
||||
}
|
||||
stopCurrent = FALSE;
|
||||
tr_fastResumeSave( tor );
|
||||
fireCheckDone( tor, currentNode.recheck_done_cb, currentNode.status_when_done );
|
||||
}
|
||||
|
||||
recheckThread = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
tr_ioRecheckAdd( tr_torrent * tor,
|
||||
tr_recheck_done_cb recheck_done_cb,
|
||||
run_status_t status_when_done )
|
||||
{
|
||||
if( tor->uncheckedPieces == NULL )
|
||||
{
|
||||
fireCheckDone( tor, recheck_done_cb, status_when_done );
|
||||
}
|
||||
else
|
||||
{
|
||||
struct recheck_node * node;
|
||||
node = tr_new( struct recheck_node, 1 );
|
||||
node->torrent = tor;
|
||||
node->recheck_done_cb = recheck_done_cb;
|
||||
node->status_when_done = status_when_done;
|
||||
tr_list_append( &recheckList, node );
|
||||
|
||||
tor->runStatus = TR_RUN_CHECKING_WAIT;
|
||||
|
||||
if( recheckThread == NULL )
|
||||
recheckThread = tr_threadNew( recheckThreadFunc, NULL, "recheckThreadFunc" );
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compareRecheckByTorrent( const void * va, const void * vb )
|
||||
{
|
||||
const struct recheck_node * a = ( const struct recheck_node * ) va;
|
||||
const struct recheck_node * b = ( const struct recheck_node * ) vb;
|
||||
return a->torrent - b->torrent;
|
||||
}
|
||||
|
||||
void
|
||||
tr_ioRecheckRemove( tr_torrent * tor )
|
||||
{
|
||||
if( tor == currentNode.torrent )
|
||||
stopCurrent = TRUE;
|
||||
else {
|
||||
struct recheck_node tmp;
|
||||
tmp.torrent = tor;
|
||||
struct recheck_node * node = tr_list_remove( &recheckList, &tmp, compareRecheckByTorrent );
|
||||
if( node != NULL ) {
|
||||
fireCheckDone( tor, node->recheck_done_cb, node->status_when_done );
|
||||
tr_free( node );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,9 @@
|
|||
#ifndef TR_IO_H
|
||||
#define TR_IO_H 1
|
||||
|
||||
typedef struct tr_io_s tr_io_t;
|
||||
struct tr_torrent;
|
||||
|
||||
void tr_ioCheckFiles ( tr_torrent_t * );
|
||||
|
||||
tr_io_t * tr_ioNew ( tr_torrent_t * );
|
||||
typedef struct tr_io tr_io;
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioRead, tr_ioWrite
|
||||
|
@ -39,24 +37,29 @@ tr_io_t * tr_ioNew ( tr_torrent_t * );
|
|||
* TR_ERROR_ASSERT if the parameters are incorrect, one of the
|
||||
* TR_ERROR_IO_* otherwise.
|
||||
**********************************************************************/
|
||||
int tr_ioRead ( tr_io_t *, int index, int begin, int len, uint8_t * );
|
||||
int tr_ioWrite ( tr_io_t *, int index, int begin, int len, uint8_t * );
|
||||
int tr_ioRead ( struct tr_torrent*, int index, int begin, int len, uint8_t * );
|
||||
int tr_ioWrite ( struct tr_torrent *, int index, int begin, int len, uint8_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioHash
|
||||
***********************************************************************
|
||||
* Hashes the specified piece and updates the completion accordingly.
|
||||
**********************************************************************/
|
||||
int tr_ioHash ( tr_io_t *, int piece );
|
||||
/* hashes the specified piece and updates the completion accordingly. */
|
||||
int tr_ioHash ( tr_torrent*, int piece );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioSync
|
||||
***********************************************************************
|
||||
* Flush all data on disc by closing all files, and update the cache
|
||||
* file.
|
||||
**********************************************************************/
|
||||
void tr_ioSync( tr_io_t * );
|
||||
/* close all the files associated with this torrent*/
|
||||
void tr_ioClose( const tr_torrent * );
|
||||
|
||||
void tr_ioClose ( tr_io_t * );
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
typedef void (*tr_recheck_done_cb)( tr_torrent * tor );
|
||||
|
||||
void tr_ioRecheckAdd( tr_torrent * tor,
|
||||
tr_recheck_done_cb recheck_done_cb,
|
||||
run_status_t status_when_done );
|
||||
|
||||
void tr_ioRecheckRemove( tr_torrent * tor );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,30 +45,26 @@ typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
int tr_trackerInfoInit( struct tr_tracker_info_s * info,
|
||||
const char * address,
|
||||
int address_len );
|
||||
int tr_trackerInfoInit( struct tr_tracker_info * info,
|
||||
const char * address,
|
||||
int address_len );
|
||||
|
||||
void tr_trackerInfoClear( struct tr_tracker_info_s * info );
|
||||
|
||||
struct tr_peer_s;
|
||||
void tr_trackerInfoClear( struct tr_tracker_info * info );
|
||||
|
||||
void tr_peerIdNew ( char* buf, int buflen );
|
||||
|
||||
void tr_torrentResetTransferStats( tr_torrent_t * );
|
||||
void tr_torrentResetTransferStats( tr_torrent * );
|
||||
|
||||
int tr_torrentAddCompact( tr_torrent_t * tor, int from,
|
||||
const uint8_t * buf, int count );
|
||||
int tr_torrentAttachPeer( tr_torrent_t * tor, struct tr_peer_s * );
|
||||
void tr_torrentSetHasPiece( tr_torrent * tor, int pieceIndex, int has );
|
||||
|
||||
void tr_torrentSetHasPiece( tr_torrent_t * tor, int pieceIndex, int has );
|
||||
void tr_torrentLock ( const tr_torrent * );
|
||||
void tr_torrentUnlock ( const tr_torrent * );
|
||||
|
||||
void tr_torrentReaderLock ( const tr_torrent_t * );
|
||||
void tr_torrentReaderUnlock ( const tr_torrent_t * );
|
||||
void tr_torrentWriterLock ( tr_torrent_t * );
|
||||
void tr_torrentWriterUnlock ( tr_torrent_t * );
|
||||
void tr_torrentChangeMyPort ( tr_torrent *, int port );
|
||||
|
||||
void tr_torrentChangeMyPort ( tr_torrent_t *, int port );
|
||||
int tr_torrentExists( tr_handle *, const uint8_t * );
|
||||
tr_torrent* tr_torrentFindFromHash( tr_handle *, const uint8_t * );
|
||||
tr_torrent* tr_torrentFindFromObfuscatedHash( tr_handle *, const uint8_t* );
|
||||
|
||||
/* get the index of this piece's first block */
|
||||
#define tr_torPieceFirstBlock(tor,piece) ( (piece) * (tor)->blockCountInPiece )
|
||||
|
@ -89,37 +85,40 @@ void tr_torrentChangeMyPort ( tr_torrent_t *, int port );
|
|||
( ((block)==((tor)->blockCount-1)) ? (tor)->lastBlockSize : (tor)->blockSize )
|
||||
|
||||
#define tr_block(a,b) _tr_block(tor,a,b)
|
||||
int _tr_block( const tr_torrent_t * tor, int index, int begin );
|
||||
int _tr_block( const tr_torrent * tor, int index, int begin );
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_RUN_CHECKING = (1<<0), /* checking files' checksums */
|
||||
TR_RUN_RUNNING = (1<<1), /* seeding or leeching */
|
||||
TR_RUN_STOPPING = (1<<2), /* stopping */
|
||||
TR_RUN_STOPPING_NET_WAIT = (1<<3), /* waiting on network -- we're
|
||||
telling tracker we've stopped */
|
||||
TR_RUN_CHECKING_WAIT = (1<<0), /* waiting to be checked */
|
||||
TR_RUN_CHECKING = (1<<1), /* checking files' checksums */
|
||||
TR_RUN_RUNNING = (1<<2), /* seeding or leeching */
|
||||
TR_RUN_STOPPING = (1<<3), /* waiting for acknowledgment from tracker */
|
||||
TR_RUN_STOPPED = (1<<4) /* stopped */
|
||||
}
|
||||
run_status_t;
|
||||
|
||||
#define TR_ID_LEN 20
|
||||
|
||||
struct tr_torrent_s
|
||||
struct tr_torrent
|
||||
{
|
||||
tr_handle_t * handle;
|
||||
tr_info_t info;
|
||||
tr_handle * handle;
|
||||
tr_info info;
|
||||
|
||||
tr_speedlimit_t uploadLimitMode;
|
||||
tr_speedlimit_t downloadLimitMode;
|
||||
struct tr_ratecontrol_s * upload;
|
||||
struct tr_ratecontrol_s * download;
|
||||
struct tr_ratecontrol_s * swarmspeed;
|
||||
tr_speedlimit uploadLimitMode;
|
||||
tr_speedlimit downloadLimitMode;
|
||||
struct tr_ratecontrol * upload;
|
||||
struct tr_ratecontrol * download;
|
||||
struct tr_ratecontrol * swarmspeed;
|
||||
|
||||
struct tr_timer * saveTimer;
|
||||
|
||||
int error;
|
||||
char errorString[128];
|
||||
int hasChangedState;
|
||||
|
||||
uint8_t obfuscatedHash[SHA_DIGEST_LENGTH];
|
||||
|
||||
uint8_t * azId;
|
||||
int publicPort;
|
||||
|
||||
|
@ -136,27 +135,20 @@ struct tr_torrent_s
|
|||
int blockCountInPiece;
|
||||
int blockCountInLastPiece;
|
||||
|
||||
struct tr_completion_s * completion;
|
||||
struct tr_completion * completion;
|
||||
|
||||
volatile char dieFlag;
|
||||
struct tr_bitfield_s * uncheckedPieces;
|
||||
struct tr_bitfield * uncheckedPieces;
|
||||
run_status_t runStatus;
|
||||
run_status_t runStatusToSave;
|
||||
char runStatusToSaveIsSet;
|
||||
cp_status_t cpStatus;
|
||||
struct tr_thread_s * thread;
|
||||
struct tr_rwlock_s * lock;
|
||||
struct tr_lock * lock;
|
||||
|
||||
struct tr_tracker_s * tracker;
|
||||
struct tr_tracker * tracker;
|
||||
struct tr_publisher_tag * trackerSubscription;
|
||||
struct tr_io_s * io;
|
||||
uint64_t startDate;
|
||||
uint64_t stopDate;
|
||||
char ioLoaded;
|
||||
char fastResumeDirty;
|
||||
|
||||
int peerCount;
|
||||
struct tr_peer_s * peers[TR_MAX_PEER_COUNT];
|
||||
|
||||
uint64_t downloadedCur;
|
||||
uint64_t downloadedPrev;
|
||||
|
@ -169,31 +161,36 @@ struct tr_torrent_s
|
|||
uint8_t pexDisabled;
|
||||
|
||||
int8_t statCur;
|
||||
tr_stat_t stats[2];
|
||||
tr_stat stats[2];
|
||||
|
||||
tr_torrent_t * next;
|
||||
tr_torrent * next;
|
||||
};
|
||||
|
||||
struct tr_handle_s
|
||||
struct tr_handle
|
||||
{
|
||||
struct tr_event_handle_s * events;
|
||||
tr_encryption_mode encryptionMode;
|
||||
|
||||
struct tr_event_handle * events;
|
||||
|
||||
int torrentCount;
|
||||
tr_torrent_t * torrentList;
|
||||
tr_torrent * torrentList;
|
||||
|
||||
char * tag;
|
||||
int isPortSet;
|
||||
|
||||
char useUploadLimit;
|
||||
char useDownloadLimit;
|
||||
struct tr_ratecontrol_s * upload;
|
||||
struct tr_ratecontrol_s * download;
|
||||
struct tr_ratecontrol * upload;
|
||||
struct tr_ratecontrol * download;
|
||||
|
||||
struct tr_shared_s * shared;
|
||||
struct tr_peerMgr * peerMgr;
|
||||
struct tr_shared * shared;
|
||||
|
||||
tr_handle_status_t stats[2];
|
||||
tr_handle_status stats[2];
|
||||
int statCur;
|
||||
|
||||
uint8_t isClosed;
|
||||
|
||||
#define TR_AZ_ID_LEN 20
|
||||
uint8_t azId[TR_AZ_ID_LEN];
|
||||
};
|
||||
|
|
|
@ -585,7 +585,7 @@ ipc_mkgetinfo( struct ipc_info * info, size_t * len, enum ipc_msg id,
|
|||
}
|
||||
|
||||
int
|
||||
ipc_addinfo( benc_val_t * list, int tor, const tr_info_t * inf, int types )
|
||||
ipc_addinfo( benc_val_t * list, int tor, const tr_info * inf, int types )
|
||||
{
|
||||
benc_val_t * dict, * item, * file, * tier;
|
||||
int ii, jj, kk;
|
||||
|
@ -727,7 +727,7 @@ ipc_addinfo( benc_val_t * list, int tor, const tr_info_t * inf, int types )
|
|||
|
||||
int
|
||||
ipc_addstat( benc_val_t * list, int tor,
|
||||
const tr_stat_t * st, int types )
|
||||
const tr_stat * st, int types )
|
||||
{
|
||||
benc_val_t * dict, * item;
|
||||
int ii, used;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* yay for typedefs, we can't forward declare benc_val_t or tr_info_t
|
||||
/* yay for typedefs, we can't forward declare benc_val_t or tr_info
|
||||
like with structs */
|
||||
#include "bencode.h"
|
||||
#include "transmission.h"
|
||||
|
@ -159,8 +159,8 @@ uint8_t * ipc_mkstr ( struct ipc_info *, size_t *, enum ipc_msg, int64_t,
|
|||
uint8_t * ipc_mkvers ( size_t *, const char * );
|
||||
uint8_t * ipc_mkgetinfo( struct ipc_info *, size_t *, enum ipc_msg, int64_t,
|
||||
int, const int * );
|
||||
int ipc_addinfo ( benc_val_t *, int, const tr_info_t *, int );
|
||||
int ipc_addstat ( benc_val_t *, int, const tr_stat_t *, int );
|
||||
int ipc_addinfo ( benc_val_t *, int, const tr_info *, int );
|
||||
int ipc_addstat ( benc_val_t *, int, const tr_stat *, int );
|
||||
|
||||
/* sets errno to EINVAL on parse error or
|
||||
EPERM for unsupported protocol version */
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
#include "list.h"
|
||||
#include "utils.h"
|
||||
|
||||
static tr_list_t*
|
||||
static tr_list*
|
||||
node_alloc( void )
|
||||
{
|
||||
return tr_new0( tr_list_t, 1 );
|
||||
return tr_new0( tr_list, 1 );
|
||||
}
|
||||
|
||||
static void
|
||||
node_free( tr_list_t* node )
|
||||
node_free( tr_list* node )
|
||||
{
|
||||
tr_free( node );
|
||||
}
|
||||
|
@ -31,20 +31,20 @@ node_free( tr_list_t* node )
|
|||
***/
|
||||
|
||||
void
|
||||
tr_list_free( tr_list_t** list )
|
||||
tr_list_free( tr_list** list )
|
||||
{
|
||||
while( *list )
|
||||
{
|
||||
tr_list_t * node = *list;
|
||||
tr_list * node = *list;
|
||||
*list = (*list)->next;
|
||||
node_free( node );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_list_prepend( tr_list_t ** list, void * data )
|
||||
tr_list_prepend( tr_list ** list, void * data )
|
||||
{
|
||||
tr_list_t * node = node_alloc ();
|
||||
tr_list * node = node_alloc ();
|
||||
node->data = data;
|
||||
node->next = *list;
|
||||
if( *list )
|
||||
|
@ -53,14 +53,14 @@ tr_list_prepend( tr_list_t ** list, void * data )
|
|||
}
|
||||
|
||||
void
|
||||
tr_list_append( tr_list_t ** list, void * data )
|
||||
tr_list_append( tr_list ** list, void * data )
|
||||
{
|
||||
tr_list_t * node = node_alloc( );
|
||||
tr_list * node = node_alloc( );
|
||||
node->data = data;
|
||||
if( !*list )
|
||||
*list = node;
|
||||
else {
|
||||
tr_list_t * l = *list;
|
||||
tr_list * l = *list;
|
||||
while( l->next )
|
||||
l = l->next;
|
||||
l->next = node;
|
||||
|
@ -69,12 +69,12 @@ tr_list_append( tr_list_t ** list, void * data )
|
|||
}
|
||||
|
||||
void
|
||||
tr_list_insert_sorted( tr_list_t ** list,
|
||||
tr_list_insert_sorted( tr_list ** list,
|
||||
void * data,
|
||||
int compare(const void*,const void*) )
|
||||
{
|
||||
/* find l, the node that we'll insert this data before */
|
||||
tr_list_t * l;
|
||||
tr_list * l;
|
||||
for( l=*list; l!=NULL; l=l->next ) {
|
||||
const int c = (compare)( data, l->data );
|
||||
if( c <= 0 )
|
||||
|
@ -86,7 +86,7 @@ tr_list_insert_sorted( tr_list_t ** list,
|
|||
else if( l == *list )
|
||||
tr_list_prepend( list, data );
|
||||
else {
|
||||
tr_list_t * node = node_alloc( );
|
||||
tr_list * node = node_alloc( );
|
||||
node->data = data;
|
||||
if( l->prev ) { node->prev = l->prev; node->prev->next = node; }
|
||||
node->next = l;
|
||||
|
@ -95,8 +95,8 @@ tr_list_insert_sorted( tr_list_t ** list,
|
|||
}
|
||||
|
||||
|
||||
tr_list_t*
|
||||
tr_list_find_data ( tr_list_t * list, const void * data )
|
||||
tr_list*
|
||||
tr_list_find_data ( tr_list * list, const void * data )
|
||||
{
|
||||
for(; list; list=list->next )
|
||||
if( list->data == data )
|
||||
|
@ -105,20 +105,49 @@ tr_list_find_data ( tr_list_t * list, const void * data )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
tr_list_remove_data ( tr_list_t ** list, const void * data )
|
||||
static void*
|
||||
tr_list_remove_node ( tr_list ** list, tr_list * node )
|
||||
{
|
||||
tr_list_t * node = tr_list_find_data( *list, data );
|
||||
tr_list_t * prev = node ? node->prev : NULL;
|
||||
tr_list_t * next = node ? node->next : NULL;
|
||||
void * data;
|
||||
tr_list * prev = node ? node->prev : NULL;
|
||||
tr_list * next = node ? node->next : NULL;
|
||||
if( prev ) prev->next = next;
|
||||
if( next ) next->prev = prev;
|
||||
if( *list == node ) *list = next;
|
||||
data = node ? node->data : NULL;
|
||||
node_free( node );
|
||||
return data;
|
||||
}
|
||||
|
||||
tr_list_t*
|
||||
tr_list_find ( tr_list_t * list , const void * b, TrListCompareFunc func )
|
||||
void*
|
||||
tr_list_pop_front( tr_list ** list )
|
||||
{
|
||||
void * ret = NULL;
|
||||
if( *list != NULL )
|
||||
{
|
||||
ret = (*list)->data;
|
||||
tr_list_remove_node( list, *list );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void*
|
||||
tr_list_remove_data ( tr_list ** list, const void * data )
|
||||
{
|
||||
return tr_list_remove_node( list, tr_list_find_data( *list, data ) );
|
||||
}
|
||||
|
||||
void*
|
||||
tr_list_remove( tr_list ** list,
|
||||
const void * b,
|
||||
TrListCompareFunc compare_func )
|
||||
{
|
||||
return tr_list_remove_node( list, tr_list_find( *list, b, compare_func ) );
|
||||
}
|
||||
|
||||
|
||||
tr_list*
|
||||
tr_list_find ( tr_list * list , const void * b, TrListCompareFunc func )
|
||||
{
|
||||
for( ; list; list=list->next )
|
||||
if( !func( list->data, b ) )
|
||||
|
@ -128,11 +157,21 @@ tr_list_find ( tr_list_t * list , const void * b, TrListCompareFunc func )
|
|||
}
|
||||
|
||||
void
|
||||
tr_list_foreach( tr_list_t * list, TrListForeachFunc func )
|
||||
tr_list_foreach( tr_list * list, TrListForeachFunc func )
|
||||
{
|
||||
while( list )
|
||||
{
|
||||
while( list != NULL ) {
|
||||
func( list->data );
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tr_list_size( const tr_list * list )
|
||||
{
|
||||
int size = 0;
|
||||
while( list != NULL ) {
|
||||
++size;
|
||||
list = list->next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -13,41 +13,49 @@
|
|||
#ifndef TR_LIST_H
|
||||
#define TR_LIST_H
|
||||
|
||||
typedef struct tr_list_s
|
||||
typedef struct tr_list
|
||||
{
|
||||
void * data;
|
||||
struct tr_list_s * next;
|
||||
struct tr_list_s * prev;
|
||||
void * data;
|
||||
struct tr_list * next;
|
||||
struct tr_list * prev;
|
||||
}
|
||||
tr_list_t;
|
||||
tr_list;
|
||||
|
||||
typedef int (*TrListCompareFunc)(const void * a, const void * b);
|
||||
typedef void (*TrListForeachFunc)(void *);
|
||||
|
||||
void tr_list_free ( tr_list_t ** list );
|
||||
int tr_list_size ( const tr_list * list );
|
||||
|
||||
void tr_list_append ( tr_list_t ** list,
|
||||
void * data );
|
||||
void tr_list_free ( tr_list ** list );
|
||||
|
||||
void tr_list_prepend ( tr_list_t ** list,
|
||||
void * data );
|
||||
void tr_list_append ( tr_list ** list,
|
||||
void * data );
|
||||
|
||||
void tr_list_remove_data ( tr_list_t ** list,
|
||||
const void * data );
|
||||
void tr_list_prepend ( tr_list ** list,
|
||||
void * data );
|
||||
|
||||
void tr_list_insert_sorted ( tr_list_t ** list,
|
||||
void * data,
|
||||
TrListCompareFunc compare_func );
|
||||
void* tr_list_pop_front ( tr_list ** list );
|
||||
|
||||
tr_list_t* tr_list_find ( tr_list_t * list,
|
||||
const void * b,
|
||||
TrListCompareFunc compare_func );
|
||||
void* tr_list_remove_data ( tr_list ** list,
|
||||
const void * data );
|
||||
|
||||
tr_list_t* tr_list_find_data ( tr_list_t * list,
|
||||
const void * data );
|
||||
void* tr_list_remove ( tr_list ** list,
|
||||
const void * b,
|
||||
TrListCompareFunc compare_func );
|
||||
|
||||
void tr_list_foreach ( tr_list_t * list,
|
||||
TrListForeachFunc foreach_func );
|
||||
void tr_list_insert_sorted ( tr_list ** list,
|
||||
void * data,
|
||||
TrListCompareFunc compare_func );
|
||||
|
||||
tr_list* tr_list_find ( tr_list * list,
|
||||
const void * b,
|
||||
TrListCompareFunc compare_func );
|
||||
|
||||
tr_list* tr_list_find_data ( tr_list * list,
|
||||
const void * data );
|
||||
|
||||
void tr_list_foreach ( tr_list * list,
|
||||
TrListForeachFunc foreach_func );
|
||||
|
||||
#endif /* TR_LIST_H */
|
||||
|
||||
|
|
|
@ -21,14 +21,13 @@
|
|||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "trcompat.h" /* for strlcpy */
|
||||
#include "crypto.h" /* tr_sha1 */
|
||||
#include "trcompat.h" /* strlcpy */
|
||||
#include "transmission.h"
|
||||
#include "internal.h" /* for tr_torrent_t */
|
||||
#include "bencode.h"
|
||||
#include "makemeta.h"
|
||||
#include "platform.h" /* threads, locks */
|
||||
#include "shared.h" /* shared lock */
|
||||
#include "sha1.h"
|
||||
#include "utils.h" /* buildpath */
|
||||
#include "version.h"
|
||||
|
||||
|
@ -231,7 +230,7 @@ getHashInfo ( tr_metainfo_builder_t * b )
|
|||
|
||||
assert( bufptr-buf == (int)thisPieceSize );
|
||||
assert( pieceRemain == 0 );
|
||||
SHA1( buf, thisPieceSize, walk );
|
||||
tr_sha1( buf, walk, thisPieceSize, NULL );
|
||||
walk += SHA_DIGEST_LENGTH;
|
||||
|
||||
if( b->abortFlag ) {
|
||||
|
@ -410,11 +409,11 @@ static void tr_realMakeMetaInfo ( tr_metainfo_builder_t * builder )
|
|||
|
||||
static tr_metainfo_builder_t * queue = NULL;
|
||||
|
||||
static tr_thread_t * workerThread = NULL;
|
||||
static tr_thread * workerThread = NULL;
|
||||
|
||||
static tr_lock_t* getQueueLock( tr_handle_t * h )
|
||||
static tr_lock* getQueueLock( tr_handle_t * h )
|
||||
{
|
||||
static tr_lock_t * lock = NULL;
|
||||
static tr_lock * lock = NULL;
|
||||
|
||||
tr_sharedLock( h->shared );
|
||||
if( !lock )
|
||||
|
@ -433,7 +432,7 @@ static void workerFunc( void * user_data )
|
|||
tr_metainfo_builder_t * builder = NULL;
|
||||
|
||||
/* find the next builder to process */
|
||||
tr_lock_t * lock = getQueueLock ( handle );
|
||||
tr_lock * lock = getQueueLock ( handle );
|
||||
tr_lockLock( lock );
|
||||
if( queue != NULL ) {
|
||||
builder = queue;
|
||||
|
@ -458,7 +457,7 @@ tr_makeMetaInfo( tr_metainfo_builder_t * builder,
|
|||
const char * comment,
|
||||
int isPrivate )
|
||||
{
|
||||
tr_lock_t * lock;
|
||||
tr_lock * lock;
|
||||
|
||||
builder->abortFlag = 0;
|
||||
builder->isDone = 0;
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "crypto.h" /* tr_sha1 */
|
||||
#include "http.h" /* tr_httpParseUrl */
|
||||
#include "metainfo.h"
|
||||
#include "platform.h"
|
||||
#include "sha1.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define TORRENT_MAX_SIZE (5*1024*1024)
|
||||
|
@ -44,7 +44,7 @@
|
|||
/***********************************************************************
|
||||
* Local prototypes
|
||||
**********************************************************************/
|
||||
static int realparse( tr_info_t * inf, const uint8_t * buf, size_t len );
|
||||
static int realparse( tr_info * inf, const uint8_t * buf, size_t len );
|
||||
static void savedname( char * name, size_t len, const char * hash,
|
||||
const char * tag );
|
||||
static uint8_t * readtorrent( const char * path, size_t * len );
|
||||
|
@ -52,9 +52,9 @@ static int savetorrent( const char * hash, const char * tag,
|
|||
const uint8_t * buf, size_t buflen );
|
||||
static int getfile( char * buf, int size,
|
||||
const char * prefix, benc_val_t * name );
|
||||
static int getannounce( tr_info_t * inf, benc_val_t * meta );
|
||||
static int getannounce( tr_info * inf, benc_val_t * meta );
|
||||
static char * announceToScrape( const char * announce );
|
||||
static int parseFiles( tr_info_t * inf, benc_val_t * name,
|
||||
static int parseFiles( tr_info * inf, benc_val_t * name,
|
||||
benc_val_t * files, benc_val_t * length );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -63,7 +63,7 @@ static int parseFiles( tr_info_t * inf, benc_val_t * name,
|
|||
*
|
||||
**********************************************************************/
|
||||
int
|
||||
tr_metainfoParseFile( tr_info_t * inf, const char * tag,
|
||||
tr_metainfoParseFile( tr_info * inf, const char * tag,
|
||||
const char * path, int save )
|
||||
{
|
||||
uint8_t * buf;
|
||||
|
@ -102,7 +102,7 @@ tr_metainfoParseFile( tr_info_t * inf, const char * tag,
|
|||
}
|
||||
|
||||
int
|
||||
tr_metainfoParseData( tr_info_t * inf, const char * tag,
|
||||
tr_metainfoParseData( tr_info * inf, const char * tag,
|
||||
const uint8_t * data, size_t size, int save )
|
||||
{
|
||||
if( realparse( inf, data, size ) )
|
||||
|
@ -123,7 +123,7 @@ tr_metainfoParseData( tr_info_t * inf, const char * tag,
|
|||
}
|
||||
|
||||
int
|
||||
tr_metainfoParseHash( tr_info_t * inf, const char * tag, const char * hash )
|
||||
tr_metainfoParseHash( tr_info * inf, const char * tag, const char * hash )
|
||||
{
|
||||
struct stat sb;
|
||||
uint8_t * buf;
|
||||
|
@ -172,7 +172,7 @@ tr_metainfoParseHash( tr_info_t * inf, const char * tag, const char * hash )
|
|||
}
|
||||
|
||||
static int
|
||||
realparse( tr_info_t * inf, const uint8_t * buf, size_t size )
|
||||
realparse( tr_info * inf, const uint8_t * buf, size_t size )
|
||||
{
|
||||
benc_val_t meta, * beInfo, * val, * val2;
|
||||
int i;
|
||||
|
@ -192,8 +192,9 @@ realparse( tr_info_t * inf, const uint8_t * buf, size_t size )
|
|||
tr_bencFree( &meta );
|
||||
return TR_EINVALID;
|
||||
}
|
||||
SHA1( (uint8_t *) beInfo->begin,
|
||||
(long) beInfo->end - (long) beInfo->begin, inf->hash );
|
||||
|
||||
tr_sha1( inf->hash, beInfo->begin, beInfo->end - beInfo->begin, NULL );
|
||||
|
||||
for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
|
||||
{
|
||||
snprintf( inf->hashString + i * 2, sizeof( inf->hashString ) - i * 2,
|
||||
|
@ -254,7 +255,7 @@ realparse( tr_info_t * inf, const uint8_t * buf, size_t size )
|
|||
}
|
||||
inf->pieceCount = val->val.s.i / SHA_DIGEST_LENGTH;
|
||||
|
||||
inf->pieces = calloc ( inf->pieceCount, sizeof(tr_piece_t) );
|
||||
inf->pieces = calloc ( inf->pieceCount, sizeof(tr_piece) );
|
||||
|
||||
for ( i=0; i<inf->pieceCount; ++i )
|
||||
{
|
||||
|
@ -307,7 +308,7 @@ realparse( tr_info_t * inf, const uint8_t * buf, size_t size )
|
|||
return TR_EINVALID;
|
||||
}
|
||||
|
||||
void tr_metainfoFree( tr_info_t * inf )
|
||||
void tr_metainfoFree( tr_info * inf )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
|
@ -322,7 +323,7 @@ void tr_metainfoFree( tr_info_t * inf )
|
|||
}
|
||||
tr_free( inf->trackerList );
|
||||
|
||||
memset( inf, '\0', sizeof(tr_info_t) );
|
||||
memset( inf, '\0', sizeof(tr_info) );
|
||||
}
|
||||
|
||||
static int getfile( char * buf, int size,
|
||||
|
@ -381,12 +382,12 @@ static int getfile( char * buf, int size,
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int getannounce( tr_info_t * inf, benc_val_t * meta )
|
||||
static int getannounce( tr_info * inf, benc_val_t * meta )
|
||||
{
|
||||
benc_val_t * val, * subval, * urlval;
|
||||
char * address, * announce;
|
||||
int ii, jj, port, random, subcount;
|
||||
tr_tracker_info_t * sublist;
|
||||
tr_tracker_info * sublist;
|
||||
void * swapping;
|
||||
|
||||
/* Announce-list */
|
||||
|
@ -411,7 +412,7 @@ static int getannounce( tr_info_t * inf, benc_val_t * meta )
|
|||
/* iterate through the tier's items */
|
||||
for( jj = 0; jj < subval->val.l.count; jj++ )
|
||||
{
|
||||
tr_tracker_info_t tmp;
|
||||
tr_tracker_info tmp;
|
||||
|
||||
urlval = &subval->val.l.vals[jj];
|
||||
if( TYPE_STR != urlval->type ||
|
||||
|
@ -558,9 +559,9 @@ static char * announceToScrape( const char * announce )
|
|||
}
|
||||
|
||||
int
|
||||
tr_trackerInfoInit( tr_tracker_info_t * info,
|
||||
const char * address,
|
||||
int address_len )
|
||||
tr_trackerInfoInit( tr_tracker_info * info,
|
||||
const char * address,
|
||||
int address_len )
|
||||
{
|
||||
int ret = tr_httpParseUrl( address, address_len,
|
||||
&info->address,
|
||||
|
@ -573,12 +574,12 @@ tr_trackerInfoInit( tr_tracker_info_t * info,
|
|||
}
|
||||
|
||||
void
|
||||
tr_trackerInfoClear( tr_tracker_info_t * info )
|
||||
tr_trackerInfoClear( tr_tracker_info * info )
|
||||
{
|
||||
tr_free( info->address );
|
||||
tr_free( info->announce );
|
||||
tr_free( info->scrape );
|
||||
memset( info, '\0', sizeof(tr_tracker_info_t) );
|
||||
memset( info, '\0', sizeof(tr_tracker_info) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -690,7 +691,7 @@ savetorrent( const char * hash, const char * tag,
|
|||
}
|
||||
|
||||
static int
|
||||
parseFiles( tr_info_t * inf, benc_val_t * name,
|
||||
parseFiles( tr_info * inf, benc_val_t * name,
|
||||
benc_val_t * files, benc_val_t * length )
|
||||
{
|
||||
benc_val_t * item, * path;
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
|
||||
#include "transmission.h"
|
||||
|
||||
int tr_metainfoParseFile( tr_info_t *, const char * tag,
|
||||
int tr_metainfoParseFile( tr_info *, const char * tag,
|
||||
const char * path, int save );
|
||||
int tr_metainfoParseData( tr_info_t *, const char * tag,
|
||||
int tr_metainfoParseData( tr_info *, const char * tag,
|
||||
const uint8_t * data, size_t size, int save );
|
||||
int tr_metainfoParseHash( tr_info_t *, const char * tag, const char * hash );
|
||||
void tr_metainfoFree( tr_info_t * inf );
|
||||
int tr_metainfoParseHash( tr_info *, const char * tag, const char * hash );
|
||||
void tr_metainfoFree( tr_info * inf );
|
||||
void tr_metainfoRemoveSaved( const char * hashString, const char * tag );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,11 +57,7 @@ tr_netInit( void )
|
|||
|
||||
/***********************************************************************
|
||||
* DNS resolution
|
||||
**********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolve
|
||||
***********************************************************************
|
||||
*
|
||||
* Synchronous "resolution": only works with character strings
|
||||
* representing numbers expressed in the Internet standard `.' notation.
|
||||
* Returns a non-zero value if an error occurs.
|
||||
|
@ -72,184 +68,6 @@ int tr_netResolve( const char * address, struct in_addr * addr )
|
|||
return ( addr->s_addr == 0xFFFFFFFF );
|
||||
}
|
||||
|
||||
static tr_thread_t * resolveThread;
|
||||
static tr_lock_t * resolveLock;
|
||||
static tr_cond_t * resolveCond;
|
||||
static volatile int resolveDie;
|
||||
static tr_resolve_t * resolveQueue;
|
||||
|
||||
static void resolveRelease ( tr_resolve_t * );
|
||||
static void resolveFunc ( void * );
|
||||
|
||||
struct tr_resolve_s
|
||||
{
|
||||
tr_tristate_t status;
|
||||
char * address;
|
||||
struct in_addr addr;
|
||||
|
||||
int refcount;
|
||||
tr_resolve_t * next;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolveThreadInit
|
||||
***********************************************************************
|
||||
* Initializes the static variables used for resolution and launch the
|
||||
* gethostbyname thread.
|
||||
**********************************************************************/
|
||||
void tr_netResolveThreadInit( void )
|
||||
{
|
||||
resolveDie = 0;
|
||||
resolveQueue = NULL;
|
||||
resolveLock = tr_lockNew( );
|
||||
resolveCond = tr_condNew( );
|
||||
resolveThread = tr_threadNew( resolveFunc, NULL, "resolve" );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolveThreadClose
|
||||
***********************************************************************
|
||||
* Notices the gethostbyname thread that is should terminate. Doesn't
|
||||
* wait until it does, in case it is stuck in a resolution: we let it
|
||||
* die and clean itself up.
|
||||
**********************************************************************/
|
||||
void tr_netResolveThreadClose( void )
|
||||
{
|
||||
tr_lockLock( resolveLock );
|
||||
resolveDie = 1;
|
||||
tr_lockUnlock( resolveLock );
|
||||
tr_condSignal( resolveCond );
|
||||
tr_wait( 200 );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolveInit
|
||||
***********************************************************************
|
||||
* Adds an address to the resolution queue.
|
||||
**********************************************************************/
|
||||
tr_resolve_t * tr_netResolveInit( const char * address )
|
||||
{
|
||||
tr_resolve_t * r = tr_new0( tr_resolve_t, 1 );
|
||||
r->status = TR_NET_WAIT;
|
||||
r->address = strdup( address );
|
||||
r->refcount = 2;
|
||||
r->next = NULL;
|
||||
|
||||
tr_lockLock( resolveLock );
|
||||
if( !resolveQueue )
|
||||
{
|
||||
resolveQueue = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_resolve_t * iter;
|
||||
for( iter = resolveQueue; iter->next; iter = iter->next );
|
||||
iter->next = r;
|
||||
}
|
||||
tr_lockUnlock( resolveLock );
|
||||
tr_condSignal( resolveCond );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolvePulse
|
||||
***********************************************************************
|
||||
* Checks the current status of a resolution.
|
||||
**********************************************************************/
|
||||
tr_tristate_t tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
|
||||
{
|
||||
tr_tristate_t ret;
|
||||
|
||||
tr_lockLock( resolveLock );
|
||||
ret = r->status;
|
||||
if( ret == TR_NET_OK )
|
||||
{
|
||||
*addr = r->addr;
|
||||
}
|
||||
tr_lockUnlock( resolveLock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_netResolveClose
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_netResolveClose( tr_resolve_t * r )
|
||||
{
|
||||
resolveRelease( r );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* resolveRelease
|
||||
***********************************************************************
|
||||
* The allocated tr_resolve_t structures should be freed when
|
||||
* tr_netResolveClose was called *and* it was removed from the queue.
|
||||
* This can happen in any order, so we use a refcount to know we can
|
||||
* take it out.
|
||||
**********************************************************************/
|
||||
static void resolveRelease( tr_resolve_t * r )
|
||||
{
|
||||
if( --r->refcount < 1 )
|
||||
{
|
||||
free( r->address );
|
||||
free( r );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* resolveFunc
|
||||
***********************************************************************
|
||||
* Keeps waiting for addresses to resolve, and removes them from the
|
||||
* queue once resolution is done.
|
||||
**********************************************************************/
|
||||
static void resolveFunc( void * arg UNUSED )
|
||||
{
|
||||
tr_resolve_t * r;
|
||||
struct hostent * host;
|
||||
|
||||
tr_lockLock( resolveLock );
|
||||
|
||||
while( !resolveDie )
|
||||
{
|
||||
if( !( r = resolveQueue ) )
|
||||
{
|
||||
tr_condWait( resolveCond, resolveLock );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Blocking resolution */
|
||||
tr_lockUnlock( resolveLock );
|
||||
host = gethostbyname( r->address );
|
||||
tr_lockLock( resolveLock );
|
||||
|
||||
if( host )
|
||||
{
|
||||
memcpy( &r->addr, host->h_addr, host->h_length );
|
||||
r->status = TR_NET_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
r->status = TR_NET_ERROR;
|
||||
}
|
||||
|
||||
resolveQueue = r->next;
|
||||
resolveRelease( r );
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
tr_lockUnlock( resolveLock );
|
||||
tr_lockFree( resolveLock );
|
||||
resolveLock = NULL;
|
||||
while( ( r = resolveQueue ) )
|
||||
{
|
||||
resolveQueue = r->next;
|
||||
resolveRelease( r );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TCP/UDP sockets
|
||||
|
@ -469,12 +287,14 @@ int tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * addr )
|
|||
return ret;
|
||||
}
|
||||
|
||||
void tr_netClose( int s )
|
||||
void
|
||||
tr_netClose( int s )
|
||||
{
|
||||
tr_fdSocketClose( s );
|
||||
}
|
||||
|
||||
void tr_netNtop( const struct in_addr * addr, char * buf, int len )
|
||||
void
|
||||
tr_netNtop( const struct in_addr * addr, char * buf, int len )
|
||||
{
|
||||
const uint8_t * cast;
|
||||
|
||||
|
|
|
@ -67,13 +67,6 @@ struct sockaddr_in;
|
|||
**********************************************************************/
|
||||
int tr_netResolve( const char *, struct in_addr * );
|
||||
|
||||
typedef struct tr_resolve_s tr_resolve_t;
|
||||
void tr_netResolveThreadInit( void );
|
||||
void tr_netResolveThreadClose( void );
|
||||
tr_resolve_t * tr_netResolveInit( const char * address );
|
||||
tr_tristate_t tr_netResolvePulse( tr_resolve_t *, struct in_addr * );
|
||||
void tr_netResolveClose( tr_resolve_t * );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TCP and UDP sockets
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <event.h>
|
||||
#include "transmission.h"
|
||||
#include "crypto.h"
|
||||
#include "net.h"
|
||||
#include "peer-io.h"
|
||||
#include "ratecontrol.h"
|
||||
#include "trevent.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct tr_peerIo
|
||||
{
|
||||
struct tr_handle * handle;
|
||||
|
||||
struct in_addr in_addr;
|
||||
int port;
|
||||
int socket;
|
||||
int extensions;
|
||||
int encryptionMode;
|
||||
struct bufferevent * bufev;
|
||||
uint8_t peerId[20];
|
||||
|
||||
unsigned int isEncrypted : 1;
|
||||
unsigned int isIncoming : 1;
|
||||
unsigned int peerIdIsSet : 1;
|
||||
|
||||
tr_ratecontrol * rateToPeer;
|
||||
tr_ratecontrol * rateToClient;
|
||||
|
||||
tr_can_read_cb canRead;
|
||||
tr_did_write_cb didWrite;
|
||||
tr_net_error_cb gotError;
|
||||
void * userData;
|
||||
|
||||
tr_crypto * crypto;
|
||||
};
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
didWriteWrapper( struct bufferevent * e, void * userData )
|
||||
{
|
||||
tr_peerIo * c = (tr_peerIo *) userData;
|
||||
if( c->didWrite != NULL )
|
||||
(*c->didWrite)( e, c->userData );
|
||||
}
|
||||
|
||||
static void
|
||||
canReadWrapper( struct bufferevent * e, void * userData )
|
||||
{
|
||||
tr_peerIo * c = (tr_peerIo *) userData;
|
||||
|
||||
if( c->canRead == NULL )
|
||||
return;
|
||||
|
||||
for( ;; ) {
|
||||
const int ret = (*c->canRead)( e, c->userData );
|
||||
switch( ret ) {
|
||||
case READ_AGAIN: if( EVBUFFER_LENGTH( e->input ) ) continue; /* note fall-through */
|
||||
case READ_MORE: tr_peerIoSetIOMode( c, EV_READ, 0 ); return; break;
|
||||
case READ_DONE: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gotErrorWrapper( struct bufferevent * e, short what, void * userData )
|
||||
{
|
||||
tr_peerIo * c = (tr_peerIo *) userData;
|
||||
if( c->gotError != NULL )
|
||||
(*c->gotError)( e, what, c->userData );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
//static int total_io = 0;
|
||||
|
||||
static tr_peerIo*
|
||||
tr_peerIoNew( struct tr_handle * handle,
|
||||
struct in_addr * in_addr,
|
||||
const uint8_t * torrentHash,
|
||||
int isIncoming,
|
||||
int socket )
|
||||
{
|
||||
tr_peerIo * c;
|
||||
c = tr_new0( tr_peerIo, 1 );
|
||||
c->crypto = tr_cryptoNew( torrentHash, isIncoming );
|
||||
c->handle = handle;
|
||||
c->in_addr = *in_addr;
|
||||
c->socket = socket;
|
||||
c->rateToPeer = tr_rcInit( );
|
||||
c->rateToClient = tr_rcInit( );
|
||||
c->isIncoming = isIncoming ? 1 : 0;
|
||||
c->bufev = bufferevent_new( c->socket,
|
||||
canReadWrapper,
|
||||
didWriteWrapper,
|
||||
gotErrorWrapper,
|
||||
c );
|
||||
bufferevent_enable( c->bufev, EV_READ|EV_WRITE );
|
||||
return c;
|
||||
}
|
||||
|
||||
tr_peerIo*
|
||||
tr_peerIoNewIncoming( struct tr_handle * handle,
|
||||
struct in_addr * in_addr,
|
||||
int socket )
|
||||
{
|
||||
tr_peerIo * c;
|
||||
|
||||
assert( handle != NULL );
|
||||
assert( in_addr != NULL );
|
||||
assert( socket >= 0 );
|
||||
|
||||
c = tr_peerIoNew( handle, in_addr, NULL, 1, socket );
|
||||
c->port = -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
tr_peerIo*
|
||||
tr_peerIoNewOutgoing( struct tr_handle * handle,
|
||||
struct in_addr * in_addr,
|
||||
int port,
|
||||
const uint8_t * torrentHash )
|
||||
{
|
||||
tr_peerIo * c;
|
||||
|
||||
assert( handle != NULL );
|
||||
assert( in_addr != NULL );
|
||||
assert( port >= 0 );
|
||||
assert( torrentHash != NULL );
|
||||
|
||||
c = tr_peerIoNew( handle, in_addr, torrentHash, 0,
|
||||
tr_netOpenTCP( in_addr, port, 0 ) );
|
||||
c->port = port;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoFree( tr_peerIo * c )
|
||||
{
|
||||
if( c != NULL )
|
||||
{
|
||||
c->canRead = NULL;
|
||||
c->didWrite = NULL;
|
||||
c->gotError = NULL;
|
||||
tr_bufferevent_free( c->handle, c->bufev );
|
||||
tr_netClose( c->socket );
|
||||
|
||||
tr_rcClose( c->rateToClient );
|
||||
tr_rcClose( c->rateToPeer );
|
||||
|
||||
tr_cryptoFree( c->crypto );
|
||||
|
||||
tr_free( c );
|
||||
}
|
||||
}
|
||||
|
||||
tr_handle*
|
||||
tr_peerIoGetHandle( tr_peerIo * io )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( io->handle != NULL );
|
||||
|
||||
return io->handle;
|
||||
}
|
||||
|
||||
const struct in_addr*
|
||||
tr_peerIoGetAddress( const tr_peerIo * io, uint16_t * port )
|
||||
{
|
||||
assert( io != NULL );
|
||||
|
||||
if( port != NULL )
|
||||
*port = io->port;
|
||||
|
||||
return &io->in_addr;
|
||||
}
|
||||
|
||||
const char*
|
||||
tr_peerIoGetAddrStr( const tr_peerIo * io )
|
||||
{
|
||||
static char buf[512];
|
||||
assert( io != NULL );
|
||||
snprintf( buf, sizeof(buf), "%s:%u", inet_ntoa( io->in_addr ), (unsigned int)io->port );
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoSetIOFuncs( tr_peerIo * io,
|
||||
tr_can_read_cb readcb,
|
||||
tr_did_write_cb writecb,
|
||||
tr_net_error_cb errcb,
|
||||
void * userData )
|
||||
{
|
||||
io->canRead = readcb;
|
||||
io->didWrite = writecb;
|
||||
io->gotError = errcb;
|
||||
io->userData = userData;
|
||||
|
||||
if( EVBUFFER_LENGTH( io->bufev->input ) )
|
||||
canReadWrapper( io->bufev, io );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoSetIOMode( tr_peerIo * c, short enable, short disable )
|
||||
{
|
||||
tr_setBufferEventMode( c->handle, c->bufev, enable, disable );
|
||||
}
|
||||
|
||||
int
|
||||
tr_peerIoIsIncoming( const tr_peerIo * c )
|
||||
{
|
||||
return c->isIncoming ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_peerIoReconnect( tr_peerIo * io )
|
||||
{
|
||||
assert( !tr_peerIoIsIncoming( io ) );
|
||||
|
||||
if( io->socket >= 0 )
|
||||
tr_netClose( io->socket );
|
||||
|
||||
io->socket = tr_netOpenTCP( &io->in_addr, io->port, 0 );
|
||||
|
||||
if( io->socket >= 0 )
|
||||
{
|
||||
bufferevent_free( io->bufev );
|
||||
|
||||
io->bufev = bufferevent_new( io->socket,
|
||||
canReadWrapper,
|
||||
didWriteWrapper,
|
||||
gotErrorWrapper,
|
||||
io );
|
||||
bufferevent_enable( io->bufev, EV_READ|EV_WRITE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_peerIoSetTorrentHash( tr_peerIo * io,
|
||||
const uint8_t * hash )
|
||||
{
|
||||
assert( io != NULL );
|
||||
|
||||
tr_cryptoSetTorrentHash( io->crypto, hash );
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
tr_peerIoGetTorrentHash( tr_peerIo * io )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( io->crypto != NULL );
|
||||
|
||||
return tr_cryptoGetTorrentHash( io->crypto );
|
||||
}
|
||||
|
||||
int
|
||||
tr_peerIoHasTorrentHash( const tr_peerIo * io )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( io->crypto != NULL );
|
||||
|
||||
return tr_cryptoHasTorrentHash( io->crypto );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_peerIoSetPeersId( tr_peerIo * io,
|
||||
const uint8_t * peer_id )
|
||||
{
|
||||
assert( io != NULL );
|
||||
|
||||
if(( io->peerIdIsSet = peer_id != NULL ))
|
||||
memcpy( io->peerId, peer_id, 20 );
|
||||
else
|
||||
memset( io->peerId, 0, 20 );
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
tr_peerIoGetPeersId( const tr_peerIo * io )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( io->peerIdIsSet );
|
||||
|
||||
return io->peerId;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void
|
||||
tr_peerIoSetExtension( tr_peerIo * io,
|
||||
int extensions )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( ( extensions == LT_EXTENSIONS_NONE )
|
||||
|| ( extensions == LT_EXTENSIONS_LTEP )
|
||||
|| ( extensions == LT_EXTENSIONS_AZMP ) );
|
||||
|
||||
io->extensions = extensions;
|
||||
}
|
||||
|
||||
int
|
||||
tr_peerIoGetExtension( const tr_peerIo * io )
|
||||
{
|
||||
assert( io != NULL );
|
||||
|
||||
return io->extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
size_t
|
||||
tr_peerIoWriteBytesWaiting( const tr_peerIo * io )
|
||||
{
|
||||
return EVBUFFER_LENGTH( EVBUFFER_OUTPUT( io->bufev ) );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoWrite( tr_peerIo * io,
|
||||
const void * writeme,
|
||||
int writeme_len )
|
||||
{
|
||||
tr_bufferevent_write( io->handle, io->bufev, writeme, writeme_len );
|
||||
tr_rcTransferred( io->rateToPeer, writeme_len );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoWriteBuf( tr_peerIo * io,
|
||||
struct evbuffer * buf )
|
||||
{
|
||||
tr_peerIoWrite( io, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
|
||||
evbuffer_drain( buf, ~0 );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
tr_crypto*
|
||||
tr_peerIoGetCrypto( tr_peerIo * c )
|
||||
{
|
||||
return c->crypto;
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoSetEncryption( tr_peerIo * io,
|
||||
int encryptionMode )
|
||||
{
|
||||
assert( io != NULL );
|
||||
assert( encryptionMode==PEER_ENCRYPTION_NONE || encryptionMode==PEER_ENCRYPTION_RC4 );
|
||||
|
||||
io->encryptionMode = encryptionMode;
|
||||
}
|
||||
|
||||
int
|
||||
tr_peerIoIsEncrypted( const tr_peerIo * io )
|
||||
{
|
||||
return io!=NULL && io->encryptionMode==PEER_ENCRYPTION_RC4;
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoWriteBytes( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
const void * bytes,
|
||||
int byteCount )
|
||||
{
|
||||
uint8_t * tmp;
|
||||
|
||||
switch( io->encryptionMode )
|
||||
{
|
||||
case PEER_ENCRYPTION_NONE:
|
||||
/*fprintf( stderr, "writing %d plaintext bytes to outbuf...\n", byteCount );*/
|
||||
evbuffer_add( outbuf, bytes, byteCount );
|
||||
break;
|
||||
|
||||
case PEER_ENCRYPTION_RC4:
|
||||
/*fprintf( stderr, "encrypting and writing %d bytes to outbuf...\n", byteCount );*/
|
||||
tmp = tr_new( uint8_t, byteCount );
|
||||
tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
|
||||
tr_bufferevent_write( io->handle, io->bufev, tmp, byteCount );
|
||||
tr_free( tmp );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoWriteUint16( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
uint16_t writeme )
|
||||
{
|
||||
uint16_t tmp = htons( writeme );
|
||||
tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint16_t) );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoWriteUint32( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
uint32_t writeme )
|
||||
{
|
||||
uint32_t tmp = htonl( writeme );
|
||||
tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint32_t) );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoReadBytes( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
void * bytes,
|
||||
int byteCount )
|
||||
{
|
||||
assert( (int)EVBUFFER_LENGTH( inbuf ) >= byteCount );
|
||||
|
||||
switch( io->encryptionMode )
|
||||
{
|
||||
case PEER_ENCRYPTION_NONE:
|
||||
/*fprintf( stderr, "reading %d plaintext bytes from inbuf...\n", byteCount );*/
|
||||
evbuffer_remove( inbuf, bytes, byteCount );
|
||||
tr_rcTransferred( io->rateToClient, byteCount );
|
||||
break;
|
||||
|
||||
case PEER_ENCRYPTION_RC4:
|
||||
/*fprintf( stderr, "reading AND DECRYPTING %d bytes from inbuf...\n", byteCount );*/
|
||||
evbuffer_remove( inbuf, bytes, byteCount );
|
||||
tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
|
||||
tr_rcTransferred( io->rateToClient, byteCount );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoReadUint16( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
uint16_t * setme )
|
||||
{
|
||||
uint16_t tmp;
|
||||
tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint16_t) );
|
||||
*setme = ntohs( tmp );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoReadUint32( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
uint32_t * setme )
|
||||
{
|
||||
uint32_t tmp;
|
||||
tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint32_t) );
|
||||
*setme = ntohl( tmp );
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerIoDrain( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
int byteCount )
|
||||
{
|
||||
uint8_t * tmp = tr_new( uint8_t, byteCount );
|
||||
tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
|
||||
tr_free( tmp );
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
float
|
||||
tr_peerIoGetRateToClient( const tr_peerIo * io )
|
||||
{
|
||||
return io==NULL ? 0.0f : tr_rcRate( io->rateToClient );
|
||||
|
||||
}
|
||||
|
||||
float
|
||||
tr_peerIoGetRateToPeer( const tr_peerIo * io )
|
||||
{
|
||||
return io==NULL ? 0.0f : tr_rcRate( io->rateToPeer );
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_PEER_IO_H
|
||||
#define TR_PEER_IO_H
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct in_addr;
|
||||
struct evbuffer;
|
||||
struct bufferevent;
|
||||
struct tr_handle;
|
||||
struct tr_crypto;
|
||||
typedef struct tr_peerIo tr_peerIo;
|
||||
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
tr_peerIo*
|
||||
tr_peerIoNewOutgoing( struct tr_handle * handle,
|
||||
struct in_addr * addr,
|
||||
int port,
|
||||
const uint8_t * torrentHash );
|
||||
|
||||
tr_peerIo*
|
||||
tr_peerIoNewIncoming( struct tr_handle * handle,
|
||||
struct in_addr * addr,
|
||||
int socket );
|
||||
|
||||
void tr_peerIoFree ( tr_peerIo * io );
|
||||
|
||||
tr_handle* tr_peerIoGetHandle( tr_peerIo * io );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
enum
|
||||
{
|
||||
LT_EXTENSIONS_NONE,
|
||||
LT_EXTENSIONS_LTEP,
|
||||
LT_EXTENSIONS_AZMP
|
||||
};
|
||||
|
||||
void tr_peerIoSetExtension( tr_peerIo * io,
|
||||
int lt_extensions );
|
||||
|
||||
int tr_peerIoGetExtension( const tr_peerIo * io );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
const char*
|
||||
tr_peerIoGetAddrStr( const tr_peerIo * io );
|
||||
|
||||
const struct in_addr*
|
||||
tr_peerIoGetAddress( const tr_peerIo * io, uint16_t * port );
|
||||
|
||||
const uint8_t*
|
||||
tr_peerIoGetTorrentHash( tr_peerIo * io );
|
||||
|
||||
int tr_peerIoHasTorrentHash( const tr_peerIo * io );
|
||||
|
||||
void tr_peerIoSetTorrentHash( tr_peerIo * io,
|
||||
const uint8_t * hash );
|
||||
|
||||
int tr_peerIoReconnect( tr_peerIo * io );
|
||||
|
||||
int tr_peerIoIsIncoming( const tr_peerIo * io );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void tr_peerIoSetPeersId( tr_peerIo * io,
|
||||
const uint8_t * peer_id );
|
||||
|
||||
const uint8_t*
|
||||
tr_peerIoGetPeersId( const tr_peerIo * io );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
typedef enum { READ_MORE, READ_AGAIN, READ_DONE } ReadState;
|
||||
typedef ReadState (*tr_can_read_cb)(struct bufferevent*, void* user_data);
|
||||
typedef void (*tr_did_write_cb)(struct bufferevent *, void *);
|
||||
typedef void (*tr_net_error_cb)(struct bufferevent *, short what, void *);
|
||||
|
||||
void tr_peerIoSetIOFuncs( tr_peerIo * io,
|
||||
tr_can_read_cb readcb,
|
||||
tr_did_write_cb writecb,
|
||||
tr_net_error_cb errcb,
|
||||
void * user_data );
|
||||
|
||||
void tr_peerIoSetIOMode ( tr_peerIo * io,
|
||||
short enable_mode,
|
||||
short disable_mode );
|
||||
|
||||
size_t tr_peerIoWriteBytesWaiting( const tr_peerIo * io );
|
||||
|
||||
void tr_peerIoWrite( tr_peerIo * io,
|
||||
const void * writeme,
|
||||
int writeme_len );
|
||||
|
||||
void tr_peerIoWriteBuf( tr_peerIo * io,
|
||||
struct evbuffer * buf );
|
||||
|
||||
|
||||
float tr_peerIoGetRateToClient( const tr_peerIo * io );
|
||||
|
||||
float tr_peerIoGetRateToPeer( const tr_peerIo * io );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct tr_crypto* tr_peerIoGetCrypto( tr_peerIo * io );
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* these match the values in MSE's crypto_select */
|
||||
PEER_ENCRYPTION_NONE = (1<<0),
|
||||
PEER_ENCRYPTION_RC4 = (1<<1)
|
||||
}
|
||||
EncryptionMode;
|
||||
|
||||
void tr_peerIoSetEncryption( tr_peerIo * io,
|
||||
int encryptionMode );
|
||||
|
||||
int tr_peerIoIsEncrypted( const tr_peerIo * io );
|
||||
|
||||
void tr_peerIoWriteBytes ( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
const void * bytes,
|
||||
int byteCount );
|
||||
|
||||
void tr_peerIoWriteUint16 ( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
uint16_t writeme );
|
||||
|
||||
void tr_peerIoWriteUint32 ( tr_peerIo * io,
|
||||
struct evbuffer * outbuf,
|
||||
uint32_t writeme );
|
||||
|
||||
void tr_peerIoReadBytes ( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
void * bytes,
|
||||
int byteCount );
|
||||
|
||||
void tr_peerIoReadUint16 ( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
uint16_t * setme );
|
||||
|
||||
void tr_peerIoReadUint32 ( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
uint32_t * setme );
|
||||
|
||||
void tr_peerIoDrain ( tr_peerIo * io,
|
||||
struct evbuffer * inbuf,
|
||||
int byteCount );
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_PEER_MGR_PRIVATE_H
|
||||
#define TR_PEER_MGR_PRIVATE_H
|
||||
|
||||
#include <inttypes.h> /* uint16_t */
|
||||
#include <arpa/inet.h> /* struct in_addr */
|
||||
#include "publish.h" /* tr_publisher_tag */
|
||||
|
||||
struct tr_bitfield;
|
||||
struct tr_peerIo;
|
||||
struct tr_peermsgs;
|
||||
|
||||
typedef struct tr_peer
|
||||
{
|
||||
unsigned int peerIsChoked : 1;
|
||||
unsigned int peerIsInterested : 1;
|
||||
unsigned int clientIsChoked : 1;
|
||||
unsigned int clientIsInterested : 1;
|
||||
unsigned int peerSupportsEncryption : 1;
|
||||
|
||||
struct in_addr in_addr;
|
||||
uint16_t port;
|
||||
struct tr_peerIo * io;
|
||||
uint8_t from;
|
||||
|
||||
struct tr_bitfield * banned;
|
||||
struct tr_bitfield * blame;
|
||||
struct tr_bitfield * have;
|
||||
float progress;
|
||||
|
||||
/* the client name from the `v' string in LTEP's handshake dictionary */
|
||||
char * client;
|
||||
|
||||
time_t peerSentDataAt;
|
||||
|
||||
struct tr_peermsgs * msgs;
|
||||
tr_publisher_tag msgsTag;
|
||||
}
|
||||
tr_peer;
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_PEER_MGR_H
|
||||
#define TR_PEER_MGR_H
|
||||
|
||||
#include <inttypes.h> /* uint16_t */
|
||||
#include <arpa/inet.h> /* struct in_addr */
|
||||
|
||||
struct in_addr;
|
||||
struct tr_handle;
|
||||
struct tr_peer_stat;
|
||||
struct tr_torrent;
|
||||
typedef struct tr_peerMgr tr_peerMgr;
|
||||
|
||||
typedef struct tr_pex
|
||||
{
|
||||
struct in_addr in_addr;
|
||||
uint16_t port;
|
||||
uint8_t flags;
|
||||
}
|
||||
tr_pex;
|
||||
|
||||
int tr_pexCompare( const void * a, const void * b );
|
||||
|
||||
tr_peerMgr* tr_peerMgrNew( struct tr_handle * );
|
||||
|
||||
void tr_peerMgrFree( tr_peerMgr * manager );
|
||||
|
||||
int tr_peerMgrIsAcceptingConnections( const tr_peerMgr * manager );
|
||||
|
||||
void tr_peerMgrAddIncoming( tr_peerMgr * manager,
|
||||
struct in_addr * addr,
|
||||
int socket );
|
||||
|
||||
void tr_peerMgrAddPeers( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int from,
|
||||
const uint8_t * peerCompact,
|
||||
int peerCount );
|
||||
|
||||
void tr_peerMgrAddPex( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int from,
|
||||
const tr_pex * pex,
|
||||
int pexCount );
|
||||
|
||||
void tr_peerMgrSetBlame( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int pieceIndex,
|
||||
int success );
|
||||
|
||||
int tr_peerMgrGetPeers( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
tr_pex ** setme_pex );
|
||||
|
||||
void tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash );
|
||||
|
||||
void tr_peerMgrStopTorrent( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash );
|
||||
|
||||
void tr_peerMgrAddTorrent( tr_peerMgr * manager,
|
||||
struct tr_torrent * tor );
|
||||
|
||||
void tr_peerMgrRemoveTorrent( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash );
|
||||
|
||||
void tr_peerMgrTorrentAvailability( const tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int8_t * tab,
|
||||
int tabCount );
|
||||
|
||||
void tr_peerMgrTorrentStats( const tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int * setmePeersTotal,
|
||||
int * setmePeersConnected,
|
||||
int * setmePeersSendingToUs,
|
||||
int * setmePeersGettingFromUs,
|
||||
int * setmePeersFrom ); /* <-- array of TR_PEER_FROM__MAX */
|
||||
|
||||
struct tr_peer_stat * tr_peerMgrPeerStats( const tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
int * setmeCount );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 TR_P_H
|
||||
#define TR_P_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "publish.h"
|
||||
|
||||
struct tr_torrent;
|
||||
struct tr_peer;
|
||||
struct tr_bitfield;
|
||||
|
||||
typedef struct tr_peermsgs tr_peermsgs;
|
||||
|
||||
tr_peermsgs* tr_peerMsgsNew( struct tr_torrent * torrent,
|
||||
struct tr_peer * peer );
|
||||
|
||||
void tr_peerMsgsSetChoke( tr_peermsgs *, int doChoke );
|
||||
|
||||
void tr_peerMsgsHave( tr_peermsgs * msgs,
|
||||
uint32_t pieceIndex );
|
||||
|
||||
void tr_peerMsgsCancel( tr_peermsgs * msgs,
|
||||
uint32_t pieceIndex,
|
||||
uint32_t offset,
|
||||
uint32_t length );
|
||||
|
||||
void tr_peerMsgsFree( tr_peermsgs* );
|
||||
|
||||
|
||||
enum {
|
||||
TR_ADDREQ_OK=0,
|
||||
TR_ADDREQ_FULL,
|
||||
TR_ADDREQ_MISSING,
|
||||
TR_ADDREQ_CLIENT_CHOKED
|
||||
};
|
||||
|
||||
int tr_peerMsgsAddRequest( tr_peermsgs * peer,
|
||||
uint32_t index,
|
||||
uint32_t begin,
|
||||
uint32_t length );
|
||||
|
||||
/**
|
||||
*** PeerMsgs Publish / Subscribe
|
||||
**/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_PEERMSG_CLIENT_HAVE,
|
||||
TR_PEERMSG_CLIENT_BLOCK,
|
||||
TR_PEERMSG_GOT_ERROR,
|
||||
TR_PEERMSG_NEED_REQ
|
||||
}
|
||||
PeerMsgsEventType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PeerMsgsEventType eventType;
|
||||
uint32_t pieceIndex; /* for TR_PEERMSG_GOT_BLOCK, TR_PEERMSG_GOT_HAVE */
|
||||
uint32_t offset; /* for TR_PEERMSG_GOT_BLOCK */
|
||||
uint32_t length; /* for TR_PEERMSG_GOT_BLOCK */
|
||||
}
|
||||
tr_peermsgs_event;
|
||||
|
||||
tr_publisher_tag tr_peerMsgsSubscribe ( tr_peermsgs * peer,
|
||||
tr_delivery_func func,
|
||||
void * user );
|
||||
|
||||
void tr_peerMsgsUnsubscribe ( tr_peermsgs * peer,
|
||||
tr_publisher_tag tag );
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -174,7 +174,7 @@ typedef struct tr_request_s
|
|||
|
||||
struct tr_peer_s
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
tr_torrent * tor;
|
||||
|
||||
struct in_addr addr;
|
||||
tr_port_t port; /* peer's listening port, 0 if not known */
|
||||
|
@ -214,10 +214,10 @@ struct tr_peer_s
|
|||
uint8_t id[TR_ID_LEN];
|
||||
|
||||
/* The pieces that the peer has */
|
||||
tr_bitfield_t * bitfield;
|
||||
tr_bitfield * bitfield;
|
||||
|
||||
/* blocks we've requested from this peer */
|
||||
tr_bitfield_t * reqfield;
|
||||
tr_bitfield * reqfield;
|
||||
int pieceCount;
|
||||
float progress;
|
||||
|
||||
|
@ -225,9 +225,9 @@ struct tr_peer_s
|
|||
int badPcs;
|
||||
int banned;
|
||||
/* The pieces that the peer is contributing to */
|
||||
tr_bitfield_t * blamefield;
|
||||
tr_bitfield * blamefield;
|
||||
/* The bad pieces that the peer has contributed to */
|
||||
tr_bitfield_t * banfield;
|
||||
tr_bitfield * banfield;
|
||||
|
||||
uint8_t * buf;
|
||||
int size;
|
||||
|
@ -249,11 +249,11 @@ struct tr_peer_s
|
|||
int inBegin;
|
||||
int inLength;
|
||||
|
||||
tr_list_t * outRequests;
|
||||
tr_list * outRequests;
|
||||
uint64_t outDate;
|
||||
|
||||
tr_ratecontrol_t * download;
|
||||
tr_ratecontrol_t * upload;
|
||||
tr_ratecontrol * download;
|
||||
tr_ratecontrol * upload;
|
||||
|
||||
char * client;
|
||||
int extclient;
|
||||
|
@ -291,16 +291,6 @@ static void tr_htonl( uint32_t a, void * p )
|
|||
memcpy ( p, &u, sizeof( uint32_t ) );
|
||||
}
|
||||
|
||||
static const char* getPeerId( void )
|
||||
{
|
||||
static char * peerId = NULL;
|
||||
if( !peerId ) {
|
||||
peerId = tr_new0( char, TR_ID_LEN + 1 );
|
||||
tr_peerIdNew( peerId, TR_ID_LEN + 1 );
|
||||
}
|
||||
return peerId;
|
||||
}
|
||||
|
||||
static void tr_peerPieceIsCorrupt ( tr_peer_t *, int pieceIndex );
|
||||
|
||||
#include "peerext.h"
|
||||
|
@ -353,7 +343,7 @@ tr_peer_t * tr_peerInit( const struct in_addr * addr, tr_port_t port,
|
|||
|
||||
void tr_peerDestroy( tr_peer_t * peer )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
tr_request_t * r;
|
||||
int i, block;
|
||||
|
||||
|
@ -423,7 +413,7 @@ void tr_peerSetPrivate( tr_peer_t * peer, int private )
|
|||
}
|
||||
}
|
||||
|
||||
void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
|
||||
void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent * tor )
|
||||
{
|
||||
peer->tor = tor;
|
||||
}
|
||||
|
@ -435,7 +425,7 @@ void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
|
|||
**********************************************************************/
|
||||
int tr_peerRead( tr_peer_t * peer )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
int ret;
|
||||
uint64_t date;
|
||||
|
||||
|
@ -542,7 +532,7 @@ const uint8_t * tr_peerHash( const tr_peer_t * peer )
|
|||
**********************************************************************/
|
||||
int tr_peerPulse( tr_peer_t * peer )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
int ret, size;
|
||||
uint8_t * p;
|
||||
uint64_t date;
|
||||
|
@ -580,7 +570,7 @@ int tr_peerPulse( tr_peer_t * peer )
|
|||
if( PEER_STATUS_CONNECTING == peer->status )
|
||||
{
|
||||
uint8_t buf[HANDSHAKE_SIZE];
|
||||
const tr_info_t * inf;
|
||||
const tr_info * inf;
|
||||
|
||||
inf = tr_torrentInfo( tor );
|
||||
assert( 68 == HANDSHAKE_SIZE );
|
||||
|
@ -793,7 +783,7 @@ int tr_peerIsConnected( const tr_peer_t * peer )
|
|||
return peer && (peer->status == PEER_STATUS_CONNECTED);
|
||||
}
|
||||
|
||||
int tr_peerIsFrom( const tr_peer_t * peer )
|
||||
int tr_peerGetFrom( const tr_peer_t * peer )
|
||||
{
|
||||
return peer->from;
|
||||
}
|
||||
|
@ -885,7 +875,7 @@ static int peerIsGood( const tr_peer_t * peer )
|
|||
|
||||
void tr_peerBlame( tr_peer_t * peer, int piece, int success )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
|
||||
if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
|
||||
{
|
||||
|
@ -926,7 +916,7 @@ void tr_peerBlame( tr_peer_t * peer, int piece, int success )
|
|||
tr_bitfieldRem( peer->blamefield, piece );
|
||||
}
|
||||
|
||||
int tr_peerGetConnectable( const tr_torrent_t * tor, uint8_t ** _buf )
|
||||
int tr_peerGetConnectable( const tr_torrent * tor, uint8_t ** _buf )
|
||||
{
|
||||
int count = 0;
|
||||
uint8_t * buf;
|
||||
|
@ -969,7 +959,7 @@ int tr_peerGetConnectable( const tr_torrent_t * tor, uint8_t ** _buf )
|
|||
void
|
||||
tr_peerPieceIsCorrupt( tr_peer_t * peer, int pieceIndex )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
|
||||
const uint64_t byteCount = tr_torPieceCountBytes( tor, pieceIndex );
|
||||
|
||||
|
@ -986,7 +976,7 @@ tr_peerPieceIsCorrupt( tr_peer_t * peer, int pieceIndex )
|
|||
void
|
||||
tr_peerSentBlockToUs( tr_peer_t * peer, int byteCount )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
|
||||
assert( byteCount >= 0 );
|
||||
assert( byteCount <= tor->info.pieceSize );
|
||||
|
@ -1002,7 +992,7 @@ tr_peerSentBlockToUs( tr_peer_t * peer, int byteCount )
|
|||
void
|
||||
tr_peerGotBlockFromUs ( tr_peer_t * peer, int byteCount )
|
||||
{
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
|
||||
assert( byteCount >= 0 );
|
||||
assert( byteCount <= tor->info.pieceSize );
|
||||
|
@ -1016,7 +1006,7 @@ tr_peerGotBlockFromUs ( tr_peer_t * peer, int byteCount )
|
|||
}
|
||||
|
||||
static void
|
||||
tr_torrentSwiftPulse ( tr_torrent_t * tor )
|
||||
tr_torrentSwiftPulse ( tr_torrent * tor )
|
||||
{
|
||||
/* Preferred # of seconds for the request queue's turnaround time.
|
||||
This is just an arbitrary number. */
|
||||
|
@ -1091,7 +1081,7 @@ tr_swiftPulse( tr_handle_t * h )
|
|||
|
||||
if( lastPulseTime + SWIFT_REFRESH_INTERVAL_SEC <= time( NULL ) )
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
tr_torrent * tor;
|
||||
for( tor=h->torrentList; tor; tor=tor->next )
|
||||
tr_torrentSwiftPulse( tor );
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ tr_peer_t * tr_peerInit ( const struct in_addr *, tr_port_t, int sock
|
|||
void tr_peerDestroy ( tr_peer_t * );
|
||||
const char *tr_peerClient ( tr_peer_t * );
|
||||
void tr_peerSetPrivate ( tr_peer_t *, int );
|
||||
void tr_peerSetTorrent ( tr_peer_t *, struct tr_torrent_s * );
|
||||
void tr_peerSetTorrent ( tr_peer_t *, struct tr_torrent * );
|
||||
void tr_peerSentBlockToUs ( tr_peer_t *, int byteCount );
|
||||
void tr_peerGotBlockFromUs ( tr_peer_t *, int byteCount );
|
||||
int tr_peerRead ( tr_peer_t * );
|
||||
|
@ -42,7 +42,7 @@ uint64_t tr_peerDate ( const tr_peer_t * );
|
|||
const uint8_t * tr_peerHash ( const tr_peer_t * );
|
||||
int tr_peerPulse ( tr_peer_t * );
|
||||
int tr_peerIsConnected ( const tr_peer_t * );
|
||||
int tr_peerIsFrom ( const tr_peer_t * );
|
||||
int tr_peerGetFrom ( const tr_peer_t * );
|
||||
int tr_peerTimesChoked ( const tr_peer_t * );
|
||||
int tr_peerIsChokingUs ( const tr_peer_t * );
|
||||
int tr_peerIsChokedByUs ( const tr_peer_t * );
|
||||
|
@ -60,7 +60,7 @@ void tr_peerSetOptimistic ( tr_peer_t *, int );
|
|||
int tr_peerIsOptimistic ( const tr_peer_t * );
|
||||
void tr_peerBlame ( tr_peer_t *, int piece, int success );
|
||||
struct in_addr * tr_peerAddress ( tr_peer_t * );
|
||||
int tr_peerGetConnectable ( const struct tr_torrent_s *, uint8_t ** );
|
||||
int tr_peerGetConnectable ( const struct tr_torrent *, uint8_t ** );
|
||||
|
||||
void tr_swiftPulse ( tr_handle_t * );
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ azmsgNameIndex( const char * name, int len )
|
|||
}
|
||||
|
||||
static uint8_t *
|
||||
makeAZHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * buflen )
|
||||
makeAZHandshake( tr_torrent * tor, tr_peer_t * peer, int * buflen )
|
||||
{
|
||||
char * buf;
|
||||
benc_val_t val, * msgsval, * msgdictval;
|
||||
|
@ -224,7 +224,7 @@ peertreeToBencAZ( tr_peertree_t * tree, benc_val_t * val )
|
|||
}
|
||||
|
||||
static int
|
||||
makeAZPex( tr_torrent_t * tor, tr_peer_t * peer, char ** buf, int * len )
|
||||
makeAZPex( tr_torrent * tor, tr_peer_t * peer, char ** buf, int * len )
|
||||
{
|
||||
benc_val_t val;
|
||||
|
||||
|
@ -235,7 +235,7 @@ makeAZPex( tr_torrent_t * tor, tr_peer_t * peer, char ** buf, int * len )
|
|||
}
|
||||
|
||||
static int
|
||||
sendAZHandshake( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
sendAZHandshake( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
uint8_t * buf;
|
||||
int len;
|
||||
|
@ -372,7 +372,7 @@ static int
|
|||
parseAZHandshake( tr_peer_t * peer, uint8_t * buf, int len )
|
||||
{
|
||||
benc_val_t val, * sub, * sub2, * dict, * subsub;
|
||||
tr_bitfield_t * msgs;
|
||||
tr_bitfield * msgs;
|
||||
int ii, idx, newclient;
|
||||
char * client;
|
||||
|
||||
|
@ -492,9 +492,9 @@ parseAZHandshake( tr_peer_t * peer, uint8_t * buf, int len )
|
|||
}
|
||||
|
||||
static int
|
||||
parseAZPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
|
||||
parseAZPex( tr_torrent * tor, tr_peer_t * peer, uint8_t * buf, int len )
|
||||
{
|
||||
tr_info_t * info = &tor->info;
|
||||
tr_info * info = &tor->info;
|
||||
benc_val_t val, * list, * pair;
|
||||
int ii, used;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define EXTENDED_PEX_ID 1
|
||||
|
||||
static int
|
||||
makeCommonPex( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
makeCommonPex( tr_torrent * tor, tr_peer_t * peer,
|
||||
int ( *peerfunc )( tr_peertree_t *, benc_val_t * ),
|
||||
const char * extrakey, benc_val_t * extraval,
|
||||
char ** retbuf, int * retlen )
|
||||
|
@ -122,7 +122,7 @@ makeCommonPex( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
}
|
||||
|
||||
static char *
|
||||
makeExtendedHandshake( tr_torrent_t * tor, tr_peer_t * peer, int * len )
|
||||
makeExtendedHandshake( tr_torrent * tor, tr_peer_t * peer, int * len )
|
||||
{
|
||||
benc_val_t val, * msgsval;
|
||||
char * buf;
|
||||
|
@ -205,7 +205,7 @@ peertreeToBencUT( tr_peertree_t * tree, benc_val_t * val )
|
|||
}
|
||||
|
||||
static int
|
||||
makeUTPex( tr_torrent_t * tor, tr_peer_t * peer, char ** buf, int * len )
|
||||
makeUTPex( tr_torrent * tor, tr_peer_t * peer, char ** buf, int * len )
|
||||
{
|
||||
benc_val_t val;
|
||||
|
||||
|
@ -299,7 +299,7 @@ parseExtendedHandshake( tr_peer_t * peer, uint8_t * buf, int len )
|
|||
}
|
||||
|
||||
static int
|
||||
parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
|
||||
parseUTPex( tr_torrent * tor, tr_peer_t * peer, uint8_t * buf, int len )
|
||||
{
|
||||
benc_val_t val, * sub;
|
||||
int used;
|
||||
|
@ -326,11 +326,13 @@ parseUTPex( tr_torrent_t * tor, tr_peer_t * peer, uint8_t * buf, int len )
|
|||
sub = tr_bencDictFind( &val, "added" );
|
||||
if( NULL != sub && TYPE_STR == sub->type && 0 == sub->val.s.i % 6 )
|
||||
{
|
||||
#if 0
|
||||
used = tr_torrentAddCompact( tor, TR_PEER_FROM_PEX,
|
||||
( uint8_t * )sub->val.s.s,
|
||||
sub->val.s.i / 6 );
|
||||
peer_dbg( "GET extended-pex, got %i peers, used %i",
|
||||
sub->val.s.i / 6, used );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -105,9 +105,9 @@ fillHeader( tr_peer_t * peer, int size, int id, uint8_t * buf )
|
|||
}
|
||||
|
||||
static uint8_t *
|
||||
blockPending( tr_torrent_t * tor,
|
||||
tr_peer_t * peer,
|
||||
int * size )
|
||||
blockPending( tr_torrent * tor,
|
||||
tr_peer_t * peer,
|
||||
int * size )
|
||||
{
|
||||
if( !peer->outBlockLoaded ) /* we need to load the block for the next request */
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ blockPending( tr_torrent_t * tor,
|
|||
tr_htonl( r->begin, buf );
|
||||
buf += 4;
|
||||
|
||||
tr_ioRead( tor->io, r->index, r->begin, r->length, buf );
|
||||
tr_ioRead( tor, r->index, r->begin, r->length, buf );
|
||||
|
||||
peer_dbg( "SEND piece %d/%d (%d bytes)",
|
||||
r->index, r->begin, r->length );
|
||||
|
@ -274,10 +274,10 @@ static void sendHave( tr_peer_t * peer, int piece )
|
|||
* - id = 5 (1 byte)
|
||||
* - bitfield (X bytes)
|
||||
**********************************************************************/
|
||||
static void sendBitfield( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
static void sendBitfield( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
uint8_t * p;
|
||||
const tr_bitfield_t * bitfield;
|
||||
const tr_bitfield * bitfield;
|
||||
|
||||
bitfield = tr_cpPieceBitfield( tor->completion );
|
||||
p = getMessagePointer( peer, bitfield->len, PEER_MSG_BITFIELD );
|
||||
|
@ -292,9 +292,9 @@ static void sendBitfield( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
|
||||
static void sendRequest( tr_torrent * tor, tr_peer_t * peer, int block )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
tr_request_t * r;
|
||||
uint8_t * p;
|
||||
|
||||
|
@ -343,7 +343,7 @@ static void sendCancel( tr_peer_t * peer, int index, int begin,
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
static void broadcastCancel( tr_torrent_t * tor, int index, int begin,
|
||||
static void broadcastCancel( tr_torrent * tor, int index, int begin,
|
||||
int length )
|
||||
{
|
||||
int i, j;
|
||||
|
@ -385,7 +385,7 @@ static void broadcastCancel( tr_torrent_t * tor, int index, int begin,
|
|||
* - eid = Y (1 byte)
|
||||
* - data (X bytes)
|
||||
**********************************************************************/
|
||||
static int sendExtended( tr_torrent_t * tor, tr_peer_t * peer, int id )
|
||||
static int sendExtended( tr_torrent * tor, tr_peer_t * peer, int id )
|
||||
{
|
||||
uint8_t * p;
|
||||
char * buf;
|
||||
|
@ -433,7 +433,7 @@ static int sendExtended( tr_torrent_t * tor, tr_peer_t * peer, int id )
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
static int sendAZPex( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
static int sendAZPex( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
uint8_t * p;
|
||||
char * buf;
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
*
|
||||
**********************************************************************/
|
||||
|
||||
static int parseChoke( tr_torrent_t * tor,
|
||||
tr_peer_t * peer,
|
||||
int len,
|
||||
int choking )
|
||||
static int parseChoke( tr_torrent * tor,
|
||||
tr_peer_t * peer,
|
||||
int len,
|
||||
int choking )
|
||||
{
|
||||
tr_request_t * r;
|
||||
int i;
|
||||
|
@ -101,10 +101,10 @@ static int parseInterested( tr_peer_t * peer, int len,
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
static int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
static int parseHave( tr_torrent * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
uint32_t piece;
|
||||
|
||||
if( len != 4 )
|
||||
|
@ -139,10 +139,10 @@ static int parseHave( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
static int parseBitfield( tr_torrent * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
int bitfieldSize;
|
||||
int i;
|
||||
|
||||
|
@ -194,10 +194,10 @@ static int parseBitfield( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
static int parseRequest( tr_torrent * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
int index, begin, length;
|
||||
tr_request_t * r;
|
||||
|
||||
|
@ -281,10 +281,10 @@ static void updateRequests( tr_peer_t * peer, int index, int begin )
|
|||
}
|
||||
}
|
||||
|
||||
static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
static int parsePiece( tr_torrent * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
int index, begin, block, i, ret;
|
||||
|
||||
if( 8 > len )
|
||||
|
@ -334,7 +334,7 @@ static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
tr_bitfieldAdd( peer->blamefield, index );
|
||||
|
||||
/* Write to disk */
|
||||
if( ( ret = tr_ioWrite( tor->io, index, begin, len - 8, &p[8] ) ) )
|
||||
if( ( ret = tr_ioWrite( tor, index, begin, len - 8, &p[8] ) ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
@ -379,13 +379,13 @@ static int reqCompare( const void * va, const void * vb )
|
|||
return a->length - b->length;
|
||||
}
|
||||
|
||||
static int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
static int parseCancel( tr_torrent * tor, tr_peer_t * peer,
|
||||
uint8_t * p, int len )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
int index, begin, length;
|
||||
tr_request_t req;
|
||||
tr_list_t * l;
|
||||
tr_list * l;
|
||||
|
||||
if( len != 12 )
|
||||
{
|
||||
|
@ -474,8 +474,8 @@ parseMessageHeader( tr_peer_t * peer, uint8_t * buf, int buflen,
|
|||
}
|
||||
}
|
||||
|
||||
static int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
int id, uint8_t * p, int len )
|
||||
static int parseMessage( tr_torrent * tor, tr_peer_t * peer,
|
||||
int id, uint8_t * p, int len )
|
||||
{
|
||||
int extid;
|
||||
|
||||
|
@ -597,9 +597,9 @@ static const uint8_t * parseBufHash( const tr_peer_t * peer )
|
|||
}
|
||||
}
|
||||
|
||||
static int parseHandshake( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
static int parseHandshake( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
tr_info_t * inf = &tor->info;
|
||||
tr_info * inf = &tor->info;
|
||||
int ii, extmsgs, azproto;
|
||||
char * dbgsup, * dbgwant;
|
||||
|
||||
|
@ -694,7 +694,7 @@ static int parseHandshake( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int sendInitial( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
static int sendInitial( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
if( PEER_STATUS_CONNECTED != peer->status )
|
||||
{
|
||||
|
@ -715,7 +715,7 @@ static int sendInitial( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
static int parseBuf( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
int len, ret, msgid;
|
||||
uint8_t * buf;
|
||||
|
|
|
@ -38,7 +38,7 @@ static int
|
|||
checkPeer( tr_peer_t * peer )
|
||||
{
|
||||
int ret;
|
||||
tr_torrent_t * tor = peer->tor;
|
||||
tr_torrent * tor = peer->tor;
|
||||
const uint64_t now = tr_date( );
|
||||
const uint64_t idleTime = now - peer->date;
|
||||
const uint64_t idleSecs = idleTime / 1000u;
|
||||
|
@ -137,9 +137,9 @@ checkPeer( tr_peer_t * peer )
|
|||
return TR_OK;
|
||||
}
|
||||
|
||||
static int isPieceInteresting( const tr_torrent_t * tor,
|
||||
const tr_peer_t * peer,
|
||||
int piece )
|
||||
static int isPieceInteresting( const tr_torrent * tor,
|
||||
const tr_peer_t * peer,
|
||||
int piece )
|
||||
{
|
||||
if( tor->info.pieces[piece].dnd ) /* we don't want it */
|
||||
return 0;
|
||||
|
@ -162,10 +162,10 @@ static int isPieceInteresting( const tr_torrent_t * tor,
|
|||
* Returns 1 if 'peer' has at least one piece that we want but
|
||||
* haven't completed, or 0 otherwise.
|
||||
**********************************************************************/
|
||||
static int isInteresting( const tr_torrent_t * tor, const tr_peer_t * peer )
|
||||
static int isInteresting( const tr_torrent * tor, const tr_peer_t * peer )
|
||||
{
|
||||
int i;
|
||||
const tr_bitfield_t * bitfield = tr_cpPieceBitfield( tor->completion );
|
||||
const tr_bitfield * bitfield = tr_cpPieceBitfield( tor->completion );
|
||||
|
||||
if( !peer->bitfield )
|
||||
{
|
||||
|
@ -183,7 +183,7 @@ static int isInteresting( const tr_torrent_t * tor, const tr_peer_t * peer )
|
|||
}
|
||||
|
||||
static void
|
||||
updateInterest( tr_torrent_t * tor, tr_peer_t * peer )
|
||||
updateInterest( tr_torrent * tor, tr_peer_t * peer )
|
||||
{
|
||||
const int i = !!isInteresting( tor, peer );
|
||||
|
||||
|
@ -223,12 +223,12 @@ int comparePieces (const void * aIn, const void * bIn)
|
|||
return a->piece - b->piece;
|
||||
}
|
||||
|
||||
static int* getPreferredPieces( const tr_torrent_t * tor,
|
||||
const tr_peer_t * peer,
|
||||
int * pieceCount,
|
||||
int * isEndgame )
|
||||
static int* getPreferredPieces( const tr_torrent * tor,
|
||||
const tr_peer_t * peer,
|
||||
int * pieceCount,
|
||||
int * isEndgame )
|
||||
{
|
||||
const tr_info_t * inf = &tor->info;
|
||||
const tr_info * inf = &tor->info;
|
||||
|
||||
int i;
|
||||
int poolSize = 0;
|
||||
|
|
|
@ -56,11 +56,11 @@
|
|||
**** THREADS
|
||||
***/
|
||||
|
||||
struct tr_thread_s
|
||||
struct tr_thread
|
||||
{
|
||||
void (* func ) ( void * );
|
||||
void * arg;
|
||||
char * name;
|
||||
const char * name;
|
||||
|
||||
#ifdef __BEOS__
|
||||
thread_id thread;
|
||||
|
@ -82,8 +82,8 @@ struct tr_thread_s
|
|||
static ThreadFuncReturnType
|
||||
ThreadFunc( void * _t )
|
||||
{
|
||||
tr_thread_t * t = _t;
|
||||
char* name = tr_strdup( t->name );
|
||||
tr_thread * t = _t;
|
||||
const char * name = t->name;
|
||||
|
||||
#ifdef __BEOS__
|
||||
/* This is required because on BeOS, SIGINT is sent to each thread,
|
||||
|
@ -95,23 +95,21 @@ ThreadFunc( void * _t )
|
|||
t->func( t->arg );
|
||||
tr_dbg( "Thread '%s' exited", name );
|
||||
|
||||
tr_free( name );
|
||||
|
||||
#ifdef WIN32
|
||||
_endthreadex( 0 );
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
tr_thread_t *
|
||||
tr_thread *
|
||||
tr_threadNew( void (*func)(void *),
|
||||
void * arg,
|
||||
const char * name )
|
||||
{
|
||||
tr_thread_t * t = tr_new0( tr_thread_t, 1 );
|
||||
tr_thread * t = tr_new0( tr_thread, 1 );
|
||||
t->func = func;
|
||||
t->arg = arg;
|
||||
t->name = tr_strdup( name );
|
||||
t->name = name;
|
||||
|
||||
#ifdef __BEOS__
|
||||
t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
|
||||
|
@ -126,21 +124,19 @@ tr_threadNew( void (*func)(void *),
|
|||
}
|
||||
|
||||
int
|
||||
tr_amInThread ( const tr_thread_t * t )
|
||||
tr_amInThread ( const tr_thread * t )
|
||||
{
|
||||
int ret;
|
||||
#ifdef __BEOS__
|
||||
ret = find_thread(NULL) == t->thread;
|
||||
return find_thread(NULL) == t->thread;
|
||||
#elif defined(WIN32)
|
||||
ret = GetCurrentThreadId() == t->thread_id;
|
||||
return GetCurrentThreadId() == t->thread_id;
|
||||
#else
|
||||
ret = pthread_equal( t->thread, pthread_self( ) );
|
||||
return pthread_equal( t->thread, pthread_self( ) );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
tr_threadJoin( tr_thread_t * t )
|
||||
tr_threadJoin( tr_thread * t )
|
||||
{
|
||||
if( t != NULL )
|
||||
{
|
||||
|
@ -155,7 +151,6 @@ tr_threadJoin( tr_thread_t * t )
|
|||
#endif
|
||||
|
||||
tr_dbg( "Thread '%s' joined", t->name );
|
||||
tr_free( t->name );
|
||||
t->name = NULL;
|
||||
t->func = NULL;
|
||||
tr_free( t );
|
||||
|
@ -166,7 +161,7 @@ tr_threadJoin( tr_thread_t * t )
|
|||
**** LOCKS
|
||||
***/
|
||||
|
||||
struct tr_lock_s
|
||||
struct tr_lock
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
sem_id lock;
|
||||
|
@ -177,10 +172,10 @@ struct tr_lock_s
|
|||
#endif
|
||||
};
|
||||
|
||||
tr_lock_t*
|
||||
tr_lock*
|
||||
tr_lockNew( void )
|
||||
{
|
||||
tr_lock_t * l = tr_new0( tr_lock_t, 1 );
|
||||
tr_lock * l = tr_new0( tr_lock, 1 );
|
||||
|
||||
#ifdef __BEOS__
|
||||
l->lock = create_sem( 1, "" );
|
||||
|
@ -194,7 +189,7 @@ tr_lockNew( void )
|
|||
}
|
||||
|
||||
void
|
||||
tr_lockFree( tr_lock_t * l )
|
||||
tr_lockFree( tr_lock * l )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
delete_sem( l->lock );
|
||||
|
@ -207,7 +202,7 @@ tr_lockFree( tr_lock_t * l )
|
|||
}
|
||||
|
||||
int
|
||||
tr_lockTryLock( tr_lock_t * l ) /* success on zero! */
|
||||
tr_lockTryLock( tr_lock * l ) /* success on zero! */
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
return acquire_sem_etc( l->lock, 1, B_RELATIVE_TIMEOUT, 0 );
|
||||
|
@ -219,7 +214,7 @@ tr_lockTryLock( tr_lock_t * l ) /* success on zero! */
|
|||
}
|
||||
|
||||
void
|
||||
tr_lockLock( tr_lock_t * l )
|
||||
tr_lockLock( tr_lock * l )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
acquire_sem( l->lock );
|
||||
|
@ -231,7 +226,7 @@ tr_lockLock( tr_lock_t * l )
|
|||
}
|
||||
|
||||
void
|
||||
tr_lockUnlock( tr_lock_t * l )
|
||||
tr_lockUnlock( tr_lock * l )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
release_sem( l->lock );
|
||||
|
@ -242,121 +237,11 @@ tr_lockUnlock( tr_lock_t * l )
|
|||
#endif
|
||||
}
|
||||
|
||||
/***
|
||||
**** RW LOCK
|
||||
***/
|
||||
|
||||
struct tr_rwlock_s
|
||||
{
|
||||
tr_lock_t * lock;
|
||||
tr_cond_t * readCond;
|
||||
tr_cond_t * writeCond;
|
||||
size_t readCount;
|
||||
size_t wantToRead;
|
||||
size_t wantToWrite;
|
||||
int haveWriter;
|
||||
};
|
||||
|
||||
static void
|
||||
tr_rwSignal( tr_rwlock_t * rw )
|
||||
{
|
||||
if ( rw->wantToWrite )
|
||||
tr_condSignal( rw->writeCond );
|
||||
else if ( rw->wantToRead )
|
||||
tr_condBroadcast( rw->readCond );
|
||||
}
|
||||
|
||||
tr_rwlock_t*
|
||||
tr_rwNew ( void )
|
||||
{
|
||||
tr_rwlock_t * rw = tr_new0( tr_rwlock_t, 1 );
|
||||
rw->lock = tr_lockNew( );
|
||||
rw->readCond = tr_condNew( );
|
||||
rw->writeCond = tr_condNew( );
|
||||
return rw;
|
||||
}
|
||||
|
||||
void
|
||||
tr_rwReaderLock( tr_rwlock_t * rw )
|
||||
{
|
||||
tr_lockLock( rw->lock );
|
||||
rw->wantToRead++;
|
||||
while( rw->haveWriter || rw->wantToWrite )
|
||||
tr_condWait( rw->readCond, rw->lock );
|
||||
rw->wantToRead--;
|
||||
rw->readCount++;
|
||||
tr_lockUnlock( rw->lock );
|
||||
}
|
||||
|
||||
int
|
||||
tr_rwReaderTrylock( tr_rwlock_t * rw )
|
||||
{
|
||||
int ret = FALSE;
|
||||
tr_lockLock( rw->lock );
|
||||
if ( !rw->haveWriter && !rw->wantToWrite ) {
|
||||
rw->readCount++;
|
||||
ret = TRUE;
|
||||
}
|
||||
tr_lockUnlock( rw->lock );
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
tr_rwReaderUnlock( tr_rwlock_t * rw )
|
||||
{
|
||||
tr_lockLock( rw->lock );
|
||||
--rw->readCount;
|
||||
if( !rw->readCount )
|
||||
tr_rwSignal( rw );
|
||||
tr_lockUnlock( rw->lock );
|
||||
}
|
||||
|
||||
void
|
||||
tr_rwWriterLock( tr_rwlock_t * rw )
|
||||
{
|
||||
tr_lockLock( rw->lock );
|
||||
rw->wantToWrite++;
|
||||
while( rw->haveWriter || rw->readCount )
|
||||
tr_condWait( rw->writeCond, rw->lock );
|
||||
rw->wantToWrite--;
|
||||
rw->haveWriter = TRUE;
|
||||
tr_lockUnlock( rw->lock );
|
||||
}
|
||||
|
||||
int
|
||||
tr_rwWriterTrylock( tr_rwlock_t * rw )
|
||||
{
|
||||
int ret = FALSE;
|
||||
tr_lockLock( rw->lock );
|
||||
if( !rw->haveWriter && !rw->readCount )
|
||||
ret = rw->haveWriter = TRUE;
|
||||
tr_lockUnlock( rw->lock );
|
||||
return ret;
|
||||
}
|
||||
void
|
||||
tr_rwWriterUnlock( tr_rwlock_t * rw )
|
||||
{
|
||||
tr_lockLock( rw->lock );
|
||||
rw->haveWriter = FALSE;
|
||||
tr_rwSignal( rw );
|
||||
tr_lockUnlock( rw->lock );
|
||||
}
|
||||
|
||||
void
|
||||
tr_rwFree( tr_rwlock_t * rw )
|
||||
{
|
||||
tr_condFree( rw->writeCond );
|
||||
tr_condFree( rw->readCond );
|
||||
tr_lockFree( rw->lock );
|
||||
tr_free( rw );
|
||||
}
|
||||
|
||||
/***
|
||||
**** COND
|
||||
***/
|
||||
|
||||
struct tr_cond_s
|
||||
struct tr_cond
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
sem_id sem;
|
||||
|
@ -364,7 +249,7 @@ struct tr_cond_s
|
|||
int start, end;
|
||||
#elif defined(WIN32)
|
||||
tr_list * events;
|
||||
tr_lock_t * lock;
|
||||
tr_lock * lock;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
|
@ -383,10 +268,10 @@ static DWORD getContEventTLS( void )
|
|||
}
|
||||
#endif
|
||||
|
||||
tr_cond_t*
|
||||
tr_cond*
|
||||
tr_condNew( void )
|
||||
{
|
||||
tr_cond_t * c = tr_new0( tr_cond_t, 1 );
|
||||
tr_cond * c = tr_new0( tr_cond, 1 );
|
||||
#ifdef __BEOS__
|
||||
c->sem = create_sem( 1, "" );
|
||||
c->start = 0;
|
||||
|
@ -401,7 +286,7 @@ tr_condNew( void )
|
|||
}
|
||||
|
||||
void
|
||||
tr_condWait( tr_cond_t * c, tr_lock_t * l )
|
||||
tr_condWait( tr_cond * c, tr_lock * l )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
|
||||
|
@ -449,7 +334,7 @@ tr_condWait( tr_cond_t * c, tr_lock_t * l )
|
|||
}
|
||||
|
||||
#ifdef __BEOS__
|
||||
static int condTrySignal( tr_cond_t * c )
|
||||
static int condTrySignal( tr_cond * c )
|
||||
{
|
||||
if( c->start == c->end )
|
||||
return 1;
|
||||
|
@ -473,7 +358,7 @@ static int condTrySignal( tr_cond_t * c )
|
|||
}
|
||||
#endif
|
||||
void
|
||||
tr_condSignal( tr_cond_t * c )
|
||||
tr_condSignal( tr_cond * c )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
|
||||
|
@ -496,7 +381,7 @@ tr_condSignal( tr_cond_t * c )
|
|||
}
|
||||
|
||||
void
|
||||
tr_condBroadcast( tr_cond_t * c )
|
||||
tr_condBroadcast( tr_cond * c )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
|
||||
|
@ -520,7 +405,7 @@ tr_condBroadcast( tr_cond_t * c )
|
|||
}
|
||||
|
||||
void
|
||||
tr_condFree( tr_cond_t * c )
|
||||
tr_condFree( tr_cond * c )
|
||||
{
|
||||
#ifdef __BEOS__
|
||||
delete_sem( c->sem );
|
||||
|
|
|
@ -24,46 +24,30 @@
|
|||
#ifndef TR_PLATFORM_H
|
||||
#define TR_PLATFORM_H
|
||||
|
||||
typedef struct tr_lock_s tr_lock_t;
|
||||
typedef struct tr_cond_s tr_cond_t;
|
||||
typedef struct tr_thread_s tr_thread_t;
|
||||
typedef struct tr_lock tr_lock;
|
||||
typedef struct tr_cond tr_cond;
|
||||
typedef struct tr_thread tr_thread;
|
||||
|
||||
const char * tr_getHomeDirectory( void );
|
||||
const char * tr_getCacheDirectory( void );
|
||||
const char * tr_getTorrentsDirectory( void );
|
||||
|
||||
tr_thread_t* tr_threadNew ( void (*func)(void *), void * arg, const char * name );
|
||||
void tr_threadJoin ( tr_thread_t * );
|
||||
tr_thread* tr_threadNew ( void (*func)(void *), void * arg, const char * name );
|
||||
void tr_threadJoin ( tr_thread * );
|
||||
int tr_amInThread ( const tr_thread * );
|
||||
int tr_amInThread ( const tr_thread_t * );
|
||||
|
||||
tr_lock_t * tr_lockNew ( void );
|
||||
void tr_lockFree ( tr_lock_t * );
|
||||
int tr_lockTryLock ( tr_lock_t * );
|
||||
void tr_lockLock ( tr_lock_t * );
|
||||
void tr_lockUnlock ( tr_lock_t * );
|
||||
|
||||
tr_cond_t * tr_condNew ( void );
|
||||
void tr_condFree ( tr_cond_t * );
|
||||
void tr_condSignal ( tr_cond_t * );
|
||||
void tr_condBroadcast ( tr_cond_t * );
|
||||
void tr_condWait ( tr_cond_t *, tr_lock_t * );
|
||||
|
||||
/***
|
||||
**** RW lock:
|
||||
**** The lock can be had by one writer or any number of readers.
|
||||
***/
|
||||
|
||||
typedef struct tr_rwlock_s tr_rwlock_t;
|
||||
|
||||
tr_rwlock_t* tr_rwNew ( void );
|
||||
void tr_rwFree ( tr_rwlock_t * );
|
||||
void tr_rwReaderLock ( tr_rwlock_t * );
|
||||
int tr_rwReaderTrylock ( tr_rwlock_t * );
|
||||
void tr_rwReaderUnlock ( tr_rwlock_t * );
|
||||
void tr_rwWriterLock ( tr_rwlock_t * );
|
||||
int tr_rwWriterTrylock ( tr_rwlock_t * );
|
||||
void tr_rwWriterUnlock ( tr_rwlock_t * );
|
||||
tr_lock * tr_lockNew ( void );
|
||||
void tr_lockFree ( tr_lock * );
|
||||
int tr_lockTryLock ( tr_lock * );
|
||||
void tr_lockLock ( tr_lock * );
|
||||
void tr_lockUnlock ( tr_lock * );
|
||||
|
||||
tr_cond * tr_condNew ( void );
|
||||
void tr_condFree ( tr_cond * );
|
||||
void tr_condSignal ( tr_cond * );
|
||||
void tr_condBroadcast ( tr_cond * );
|
||||
void tr_condWait ( tr_cond *, tr_lock * );
|
||||
|
||||
struct in_addr; /* forward declaration to calm gcc down */
|
||||
int
|
||||
|
|
|
@ -19,19 +19,19 @@
|
|||
|
||||
#define GROW 32
|
||||
|
||||
struct tr_ptrArray_s
|
||||
struct tr_ptrArray
|
||||
{
|
||||
void ** items;
|
||||
int n_items;
|
||||
int n_alloc;
|
||||
};
|
||||
|
||||
tr_ptrArray_t*
|
||||
tr_ptrArray*
|
||||
tr_ptrArrayNew( void )
|
||||
{
|
||||
tr_ptrArray_t * p;
|
||||
tr_ptrArray * p;
|
||||
|
||||
p = tr_new( tr_ptrArray_t, 1 );
|
||||
p = tr_new( tr_ptrArray, 1 );
|
||||
p->n_items = 0;
|
||||
p->n_alloc = GROW;
|
||||
p->items = tr_new( void*, p->n_alloc );
|
||||
|
@ -40,7 +40,7 @@ tr_ptrArrayNew( void )
|
|||
}
|
||||
|
||||
void
|
||||
tr_ptrArrayFree( tr_ptrArray_t * t )
|
||||
tr_ptrArrayFree( tr_ptrArray * t )
|
||||
{
|
||||
assert( t != NULL );
|
||||
assert( t->items != NULL );
|
||||
|
@ -50,32 +50,42 @@ tr_ptrArrayFree( tr_ptrArray_t * t )
|
|||
}
|
||||
|
||||
void**
|
||||
tr_ptrArrayPeek( tr_ptrArray_t * t, int * size )
|
||||
tr_ptrArrayPeek( tr_ptrArray * t, int * size )
|
||||
{
|
||||
*size = t->n_items;
|
||||
return t->items;
|
||||
}
|
||||
|
||||
void*
|
||||
tr_ptrArrayNth( tr_ptrArray* t, int i )
|
||||
{
|
||||
assert( t != NULL );
|
||||
assert( i >= 0 );
|
||||
assert( i < t->n_items );
|
||||
|
||||
return t->items[i];
|
||||
}
|
||||
|
||||
int
|
||||
tr_ptrArraySize( const tr_ptrArray_t * t )
|
||||
tr_ptrArraySize( const tr_ptrArray * t )
|
||||
{
|
||||
return t->n_items;
|
||||
}
|
||||
|
||||
int
|
||||
tr_ptrArrayEmpty( const tr_ptrArray_t * t )
|
||||
tr_ptrArrayEmpty( const tr_ptrArray * t )
|
||||
{
|
||||
return t->n_items == 0;
|
||||
}
|
||||
|
||||
void
|
||||
tr_ptrArrayClear( tr_ptrArray_t * t )
|
||||
tr_ptrArrayClear( tr_ptrArray * t )
|
||||
{
|
||||
t->n_items = 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_ptrArrayInsert( tr_ptrArray_t * t, void * ptr, int pos )
|
||||
tr_ptrArrayInsert( tr_ptrArray * t, void * ptr, int pos )
|
||||
{
|
||||
if( pos<0 || pos>t->n_items )
|
||||
pos = t->n_items;
|
||||
|
@ -95,13 +105,13 @@ tr_ptrArrayInsert( tr_ptrArray_t * t, void * ptr, int pos )
|
|||
}
|
||||
|
||||
int
|
||||
tr_ptrArrayAppend( tr_ptrArray_t * t, void * ptr )
|
||||
tr_ptrArrayAppend( tr_ptrArray * t, void * ptr )
|
||||
{
|
||||
return tr_ptrArrayInsert( t, ptr, -1 );
|
||||
}
|
||||
|
||||
void
|
||||
tr_ptrArrayErase( tr_ptrArray_t * t, int begin, int end )
|
||||
tr_ptrArrayErase( tr_ptrArray * t, int begin, int end )
|
||||
{
|
||||
assert( begin >= 0 );
|
||||
if( end < 0 ) end = t->n_items;
|
||||
|
@ -120,12 +130,11 @@ tr_ptrArrayErase( tr_ptrArray_t * t, int begin, int end )
|
|||
**/
|
||||
|
||||
int
|
||||
tr_ptrArrayLowerBound( const tr_ptrArray_t * t,
|
||||
void * ptr,
|
||||
int compare( const void *,const void * ),
|
||||
int * exact_match )
|
||||
tr_ptrArrayLowerBound( const tr_ptrArray * t,
|
||||
const void * ptr,
|
||||
int compare( const void *,const void * ),
|
||||
int * exact_match )
|
||||
{
|
||||
int c = -1;
|
||||
int len = t->n_items;
|
||||
int first = 0;
|
||||
|
||||
|
@ -133,7 +142,7 @@ tr_ptrArrayLowerBound( const tr_ptrArray_t * t,
|
|||
{
|
||||
int half = len / 2;
|
||||
int middle = first + half;
|
||||
c = compare( t->items[middle], ptr );
|
||||
const int c = compare( t->items[middle], ptr );
|
||||
if( c < 0 ) {
|
||||
first = middle + 1;
|
||||
len = len - half - 1;
|
||||
|
@ -154,18 +163,18 @@ tr_ptrArrayLowerBound( const tr_ptrArray_t * t,
|
|||
}
|
||||
|
||||
int
|
||||
tr_ptrArrayInsertSorted( tr_ptrArray_t * t,
|
||||
void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
tr_ptrArrayInsertSorted( tr_ptrArray * t,
|
||||
void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
{
|
||||
const int pos = tr_ptrArrayLowerBound( t, ptr, compare, NULL );
|
||||
return tr_ptrArrayInsert( t, ptr, pos );
|
||||
}
|
||||
|
||||
void*
|
||||
tr_ptrArrayFindSorted( tr_ptrArray_t * t,
|
||||
void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
tr_ptrArrayFindSorted( tr_ptrArray * t,
|
||||
const void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
{
|
||||
int match;
|
||||
const int pos = tr_ptrArrayLowerBound( t, ptr, compare, &match );
|
||||
|
@ -173,9 +182,9 @@ tr_ptrArrayFindSorted( tr_ptrArray_t * t,
|
|||
}
|
||||
|
||||
void*
|
||||
tr_ptrArrayRemoveSorted( tr_ptrArray_t * t,
|
||||
void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
tr_ptrArrayRemoveSorted( tr_ptrArray * t,
|
||||
void * ptr,
|
||||
int compare(const void*,const void*) )
|
||||
{
|
||||
void * ret = NULL;
|
||||
int match;
|
||||
|
|
|
@ -16,24 +16,25 @@
|
|||
/**
|
||||
* A simple pointer array that resizes itself dynamically.
|
||||
*/
|
||||
typedef struct tr_ptrArray_s tr_ptrArray_t;
|
||||
typedef struct tr_ptrArray tr_ptrArray;
|
||||
|
||||
tr_ptrArray_t * tr_ptrArrayNew ( void );
|
||||
void tr_ptrArrayFree ( tr_ptrArray_t* );
|
||||
void** tr_ptrArrayPeek ( tr_ptrArray_t*, int * size );
|
||||
void** tr_ptrArrayBase ( tr_ptrArray_t* );
|
||||
void tr_ptrArrayClear ( tr_ptrArray_t* );
|
||||
int tr_ptrArrayInsert ( tr_ptrArray_t*, void*, int pos );
|
||||
int tr_ptrArrayAppend ( tr_ptrArray_t*, void* );
|
||||
void tr_ptrArrayErase ( tr_ptrArray_t*, int begin, int end );
|
||||
int tr_ptrArraySize ( const tr_ptrArray_t* );
|
||||
int tr_ptrArrayEmpty ( const tr_ptrArray_t* );
|
||||
tr_ptrArray * tr_ptrArrayNew ( void );
|
||||
|
||||
int tr_ptrArrayInsertSorted( tr_ptrArray_t*, void*,
|
||||
int compare(const void*,const void*) );
|
||||
void* tr_ptrArrayRemoveSorted( tr_ptrArray_t*, void*,
|
||||
int compare(const void*,const void*) );
|
||||
void* tr_ptrArrayFindSorted ( tr_ptrArray_t*, void*,
|
||||
int compare(const void*,const void*) );
|
||||
void tr_ptrArrayFree ( tr_ptrArray* );
|
||||
void* tr_ptrArrayNth ( tr_ptrArray*, int n );
|
||||
void** tr_ptrArrayPeek ( tr_ptrArray*, int * size );
|
||||
void** tr_ptrArrayBase ( tr_ptrArray* );
|
||||
void tr_ptrArrayClear ( tr_ptrArray* );
|
||||
int tr_ptrArrayInsert ( tr_ptrArray*, void*, int pos );
|
||||
int tr_ptrArrayAppend ( tr_ptrArray*, void* );
|
||||
void tr_ptrArrayErase ( tr_ptrArray*, int begin, int end );
|
||||
int tr_ptrArraySize ( const tr_ptrArray* );
|
||||
int tr_ptrArrayEmpty ( const tr_ptrArray* );
|
||||
int tr_ptrArrayInsertSorted ( tr_ptrArray*, void*,
|
||||
int compare(const void*,const void*) );
|
||||
void* tr_ptrArrayRemoveSorted ( tr_ptrArray*, void*,
|
||||
int compare(const void*,const void*) );
|
||||
void* tr_ptrArrayFindSorted ( tr_ptrArray*, const void*,
|
||||
int compare(const void*,const void*) );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "list.h"
|
||||
#include "publish.h"
|
||||
#include "utils.h"
|
||||
|
@ -22,7 +23,7 @@ struct tr_publisher_node
|
|||
|
||||
struct tr_publisher_s
|
||||
{
|
||||
tr_list_t * list;
|
||||
tr_list * list;
|
||||
};
|
||||
|
||||
tr_publisher_t*
|
||||
|
@ -32,10 +33,14 @@ tr_publisherNew( void )
|
|||
}
|
||||
|
||||
void
|
||||
tr_publisherFree( tr_publisher_t * p )
|
||||
tr_publisherFree( tr_publisher_t ** p )
|
||||
{
|
||||
tr_list_free( &p->list );
|
||||
tr_free( p );
|
||||
assert( p != NULL );
|
||||
assert( *p != NULL );
|
||||
|
||||
tr_list_free( &(*p)->list );
|
||||
tr_free( *p );
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
tr_publisher_tag
|
||||
|
@ -63,10 +68,10 @@ tr_publisherPublish( tr_publisher_t * p,
|
|||
void * source,
|
||||
void * event )
|
||||
{
|
||||
tr_list_t * walk;
|
||||
tr_list * walk;
|
||||
for( walk=p->list; walk!=NULL; )
|
||||
{
|
||||
tr_list_t * next = walk->next;
|
||||
tr_list * next = walk->next;
|
||||
struct tr_publisher_node * node = (struct tr_publisher_node*)walk->data;
|
||||
(node->func)(source, event, node->user_data);
|
||||
walk = next;
|
||||
|
|
|
@ -42,7 +42,7 @@ void tr_publisherUnsubscribe ( tr_publisher_t * publisher,
|
|||
|
||||
tr_publisher_t * tr_publisherNew ( void );
|
||||
|
||||
void tr_publisherFree ( tr_publisher_t * publisher );
|
||||
void tr_publisherFree ( tr_publisher_t ** publisher );
|
||||
|
||||
void tr_publisherPublish ( tr_publisher_t * publisher,
|
||||
void * source,
|
||||
|
|
|
@ -38,13 +38,13 @@
|
|||
typedef struct
|
||||
{
|
||||
uint64_t date;
|
||||
int size;
|
||||
uint64_t size;
|
||||
}
|
||||
tr_transfer_t;
|
||||
|
||||
struct tr_ratecontrol_s
|
||||
struct tr_ratecontrol
|
||||
{
|
||||
tr_lock_t * lock;
|
||||
tr_lock * lock;
|
||||
int limit;
|
||||
int newest;
|
||||
tr_transfer_t transfers[HISTORY_SIZE];
|
||||
|
@ -52,14 +52,14 @@ struct tr_ratecontrol_s
|
|||
|
||||
/* return the xfer rate over the last `interval' seconds in KiB/sec */
|
||||
static float
|
||||
rateForInterval( const tr_ratecontrol_t * r, int interval_msec )
|
||||
rateForInterval( const tr_ratecontrol * r, int interval_msec )
|
||||
{
|
||||
uint64_t bytes = 0;
|
||||
const uint64_t now = tr_date ();
|
||||
const uint64_t cutoff = tr_date () - interval_msec;
|
||||
int i = r->newest;
|
||||
for( ;; )
|
||||
{
|
||||
if( r->transfers[i].date + interval_msec < now )
|
||||
if( r->transfers[i].date < cutoff )
|
||||
break;
|
||||
|
||||
bytes += r->transfers[i].size;
|
||||
|
@ -75,17 +75,17 @@ rateForInterval( const tr_ratecontrol_t * r, int interval_msec )
|
|||
****
|
||||
***/
|
||||
|
||||
tr_ratecontrol_t*
|
||||
tr_ratecontrol*
|
||||
tr_rcInit( void )
|
||||
{
|
||||
tr_ratecontrol_t * r = tr_new0( tr_ratecontrol_t, 1 );
|
||||
tr_ratecontrol * r = tr_new0( tr_ratecontrol, 1 );
|
||||
r->limit = 0;
|
||||
r->lock = tr_lockNew( );
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
tr_rcClose( tr_ratecontrol_t * r )
|
||||
tr_rcClose( tr_ratecontrol * r )
|
||||
{
|
||||
tr_rcReset( r );
|
||||
tr_lockFree( r->lock );
|
||||
|
@ -97,26 +97,34 @@ tr_rcClose( tr_ratecontrol_t * r )
|
|||
***/
|
||||
|
||||
int
|
||||
tr_rcCanTransfer( const tr_ratecontrol_t * r )
|
||||
tr_rcCanTransfer( const tr_ratecontrol * r )
|
||||
{
|
||||
int ret;
|
||||
tr_lockLock( (tr_lock_t*)r->lock );
|
||||
|
||||
ret = rateForInterval( r, SHORT_INTERVAL_MSEC ) < r->limit;
|
||||
if( r == NULL )
|
||||
ret = 0;
|
||||
else {
|
||||
tr_lockLock( (tr_lock*)r->lock );
|
||||
ret = rateForInterval( r, SHORT_INTERVAL_MSEC ) < r->limit;
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
||||
tr_lockUnlock( (tr_lock_t*)r->lock );
|
||||
return ret;
|
||||
}
|
||||
|
||||
float
|
||||
tr_rcRate( const tr_ratecontrol_t * r )
|
||||
tr_rcRate( const tr_ratecontrol * r )
|
||||
{
|
||||
float ret;
|
||||
tr_lockLock( (tr_lock_t*)r->lock );
|
||||
|
||||
ret = rateForInterval( r, LONG_INTERVAL_MSEC );
|
||||
if( r == NULL )
|
||||
ret = 0.0f;
|
||||
else {
|
||||
tr_lockLock( (tr_lock*)r->lock );
|
||||
ret = rateForInterval( r, LONG_INTERVAL_MSEC );
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
||||
tr_lockUnlock( (tr_lock_t*)r->lock );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -125,14 +133,14 @@ tr_rcRate( const tr_ratecontrol_t * r )
|
|||
***/
|
||||
|
||||
void
|
||||
tr_rcTransferred( tr_ratecontrol_t * r, int size )
|
||||
tr_rcTransferred( tr_ratecontrol * r, size_t size )
|
||||
{
|
||||
uint64_t now;
|
||||
|
||||
if( size < 100 ) /* don't count small messages */
|
||||
return;
|
||||
|
||||
tr_lockLock( (tr_lock_t*)r->lock );
|
||||
tr_lockLock( (tr_lock*)r->lock );
|
||||
|
||||
now = tr_date ();
|
||||
if( r->transfers[r->newest].date + GRANULARITY_MSEC >= now )
|
||||
|
@ -143,28 +151,28 @@ tr_rcTransferred( tr_ratecontrol_t * r, int size )
|
|||
r->transfers[r->newest].size = size;
|
||||
}
|
||||
|
||||
tr_lockUnlock( (tr_lock_t*)r->lock );
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
||||
void
|
||||
tr_rcReset( tr_ratecontrol_t * r )
|
||||
tr_rcReset( tr_ratecontrol * r )
|
||||
{
|
||||
tr_lockLock( (tr_lock_t*)r->lock );
|
||||
tr_lockLock( (tr_lock*)r->lock );
|
||||
r->newest = 0;
|
||||
memset( r->transfers, 0, sizeof(tr_transfer_t) * HISTORY_SIZE );
|
||||
tr_lockUnlock( (tr_lock_t*)r->lock );
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
||||
void
|
||||
tr_rcSetLimit( tr_ratecontrol_t * r, int limit )
|
||||
tr_rcSetLimit( tr_ratecontrol * r, int limit )
|
||||
{
|
||||
tr_lockLock( (tr_lock_t*)r->lock );
|
||||
tr_lockLock( (tr_lock*)r->lock );
|
||||
r->limit = limit;
|
||||
tr_lockUnlock( (tr_lock_t*)r->lock );
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
||||
int
|
||||
tr_rcGetLimit( const tr_ratecontrol_t * r )
|
||||
tr_rcGetLimit( const tr_ratecontrol * r )
|
||||
{
|
||||
return r->limit;
|
||||
}
|
||||
|
|
|
@ -25,15 +25,15 @@
|
|||
#ifndef _TR_RATECONTROL_H_
|
||||
#define _TR_RATECONTROL_H_
|
||||
|
||||
typedef struct tr_ratecontrol_s tr_ratecontrol_t;
|
||||
typedef struct tr_ratecontrol tr_ratecontrol;
|
||||
|
||||
tr_ratecontrol_t * tr_rcInit( void );
|
||||
void tr_rcSetLimit( tr_ratecontrol_t *, int );
|
||||
int tr_rcGetLimit( const tr_ratecontrol_t * );
|
||||
int tr_rcCanTransfer( const tr_ratecontrol_t * );
|
||||
void tr_rcTransferred( tr_ratecontrol_t *, int );
|
||||
float tr_rcRate( const tr_ratecontrol_t * );
|
||||
void tr_rcReset( tr_ratecontrol_t * );
|
||||
void tr_rcClose( tr_ratecontrol_t * );
|
||||
tr_ratecontrol * tr_rcInit( void );
|
||||
void tr_rcSetLimit( tr_ratecontrol *, int );
|
||||
int tr_rcGetLimit( const tr_ratecontrol * );
|
||||
int tr_rcCanTransfer( const tr_ratecontrol * );
|
||||
void tr_rcTransferred( tr_ratecontrol *, size_t byteCount );
|
||||
float tr_rcRate( const tr_ratecontrol * );
|
||||
void tr_rcReset( tr_ratecontrol * );
|
||||
void tr_rcClose( tr_ratecontrol * );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
sha1.c: Implementation of SHA-1 Secure Hash Algorithm-1
|
||||
|
||||
Based upon: NIST FIPS180-1 Secure Hash Algorithm-1
|
||||
http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||
|
||||
Non-official Japanese Translation by HIRATA Yasuyuki:
|
||||
http://yasu.asuka.net/translations/SHA-1.html
|
||||
|
||||
Copyright (C) 2002 vi@nwr.jp. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgement in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as beging the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Note:
|
||||
The copyright notice above is copied from md5.h by L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Thank him since I'm not a good speaker of English. :)
|
||||
|
||||
$Id$
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
#if !defined(HAVE_OPENSSL) && !defined(HAVE_LIBSSL)
|
||||
|
||||
#define BITS 8
|
||||
#define INLINE inline
|
||||
|
||||
struct sha1_state_s
|
||||
{
|
||||
sha1_byte_t sha1_buf[64]; /* 512 bits */
|
||||
int sha1_count; /* How many bytes are used */
|
||||
sha1_word_t sha1_size1; /* Length counter Lower Word */
|
||||
sha1_word_t sha1_size2; /* Length counter Upper Word */
|
||||
sha1_word_t sha1_h[5]; /* Hash output */
|
||||
};
|
||||
|
||||
/*
|
||||
* Packing bytes to a word
|
||||
*
|
||||
* Should not assume p is aligned to word boundary
|
||||
*/
|
||||
static INLINE sha1_word_t packup(sha1_byte_t *p)
|
||||
{
|
||||
/* Portable, but slow */
|
||||
return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3] << 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpacking a word to bytes
|
||||
*
|
||||
* Should not assume p is aligned to word boundary
|
||||
*/
|
||||
static void unpackup(sha1_byte_t *p, sha1_word_t q)
|
||||
{
|
||||
p[0] = (q >> 24) & 0xff;
|
||||
p[1] = (q >> 16) & 0xff;
|
||||
p[2] = (q >> 8) & 0xff;
|
||||
p[3] = (q >> 0) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Processing a block
|
||||
*/
|
||||
static inline void sha1_update_now(sha1_state_t *pms, sha1_byte_t *bp)
|
||||
{
|
||||
sha1_word_t tmp, a, b, c, d, e, w[16+16];
|
||||
int i, s;
|
||||
|
||||
/* pack 64 bytes into 16 words */
|
||||
for(i = 0; i < 16; i++) {
|
||||
w[i] = packup(bp + i * sizeof(sha1_word_t));
|
||||
}
|
||||
memcpy(w + 16, w + 0, sizeof(sha1_word_t) * 16);
|
||||
|
||||
a = pms->sha1_h[0], b = pms->sha1_h[1], c = pms->sha1_h[2], d = pms->sha1_h[3], e = pms->sha1_h[4];
|
||||
|
||||
#define rot(x,n) (((x) << n) | ((x) >> (32-n)))
|
||||
#define f0(b, c, d) ((b&c)|(~b&d))
|
||||
#define f1(b, c, d) (b^c^d)
|
||||
#define f2(b, c, d) ((b&c)|(b&d)|(c&d))
|
||||
#define f3(b, c, d) (b^c^d)
|
||||
#define k0 0x5a827999
|
||||
#define k1 0x6ed9eba1
|
||||
#define k2 0x8f1bbcdc
|
||||
#define k3 0xca62c1d6
|
||||
|
||||
/* t=0-15 */
|
||||
s = 0;
|
||||
for(i = 0; i < 16; i++) {
|
||||
tmp = rot(a, 5) + f0(b, c, d) + e + w[s] + k0;
|
||||
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
||||
s = (s + 1) % 16;
|
||||
}
|
||||
|
||||
/* t=16-19 */
|
||||
for(i = 16; i < 20; i++) {
|
||||
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
||||
w[s+16] = w[s];
|
||||
tmp = rot(a, 5) + f0(b, c, d) + e + w[s] + k0;
|
||||
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
||||
s = (s + 1) % 16;
|
||||
}
|
||||
|
||||
/* t=20-39 */
|
||||
for(i = 0; i < 20; i++) {
|
||||
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
||||
w[s+16] = w[s];
|
||||
tmp = rot(a, 5) + f1(b, c, d) + e + w[s] + k1;
|
||||
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
||||
s = (s + 1) % 16;
|
||||
}
|
||||
|
||||
/* t=40-59 */
|
||||
for(i = 0; i < 20; i++) {
|
||||
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
||||
w[s+16] = w[s];
|
||||
tmp = rot(a, 5) + f2(b, c, d) + e + w[s] + k2;
|
||||
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
||||
s = (s + 1) % 16;
|
||||
}
|
||||
|
||||
/* t=60-79 */
|
||||
for(i = 0; i < 20; i++) {
|
||||
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
||||
w[s+16] = w[s];
|
||||
tmp = rot(a, 5) + f3(b, c, d) + e + w[s] + k3;
|
||||
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
||||
s = (s + 1) % 16;
|
||||
}
|
||||
|
||||
pms->sha1_h[0] += a, pms->sha1_h[1] += b, pms->sha1_h[2] += c, pms->sha1_h[3] += d, pms->sha1_h[4] += e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment sha1_size1, sha1_size2 field of sha1_state_t
|
||||
*/
|
||||
static INLINE void incr(sha1_state_t *pms, int v)
|
||||
{
|
||||
sha1_word_t q;
|
||||
|
||||
q = pms->sha1_size1 + v * BITS;
|
||||
if(q < pms->sha1_size1) {
|
||||
pms->sha1_size2++;
|
||||
}
|
||||
pms->sha1_size1 = q;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize sha1_state_t as FIPS specifies
|
||||
*/
|
||||
void sha1_init(sha1_state_t *pms)
|
||||
{
|
||||
memset(pms, 0, sizeof(*pms));
|
||||
pms->sha1_h[0] = 0x67452301; /* Initialize H[0]-H[4] */
|
||||
pms->sha1_h[1] = 0xEFCDAB89;
|
||||
pms->sha1_h[2] = 0x98BADCFE;
|
||||
pms->sha1_h[3] = 0x10325476;
|
||||
pms->sha1_h[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill block and update output when needed
|
||||
*/
|
||||
void sha1_update(sha1_state_t *pms, sha1_byte_t *bufp, int length)
|
||||
{
|
||||
/* Is the buffer partially filled? */
|
||||
if(pms->sha1_count != 0) {
|
||||
if(pms->sha1_count + length >= (signed) sizeof(pms->sha1_buf)) { /* buffer is filled enough */
|
||||
int fil = sizeof(pms->sha1_buf) - pms->sha1_count; /* length to copy */
|
||||
|
||||
memcpy(pms->sha1_buf + pms->sha1_count, bufp, fil);
|
||||
sha1_update_now(pms, pms->sha1_buf);
|
||||
length -= fil;
|
||||
bufp += fil;
|
||||
pms->sha1_count = 0;
|
||||
incr(pms, fil);
|
||||
} else {
|
||||
memcpy(pms->sha1_buf + pms->sha1_count, bufp, length);
|
||||
pms->sha1_count += length;
|
||||
incr(pms, length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop to update state */
|
||||
for(;;) {
|
||||
if(length < (signed) sizeof(pms->sha1_buf)) { /* Short to fill up the buffer */
|
||||
if(length) {
|
||||
memcpy(pms->sha1_buf, bufp, length);
|
||||
}
|
||||
pms->sha1_count = length;
|
||||
incr(pms, length);
|
||||
break;
|
||||
}
|
||||
sha1_update_now(pms, bufp);
|
||||
length -= sizeof(pms->sha1_buf);
|
||||
bufp += sizeof(pms->sha1_buf);
|
||||
incr(pms, sizeof(pms->sha1_buf));
|
||||
}
|
||||
}
|
||||
|
||||
void sha1_finish(sha1_state_t *pms, sha1_byte_t output[SHA1_OUTPUT_SIZE])
|
||||
{
|
||||
int i;
|
||||
sha1_byte_t buf[1];
|
||||
|
||||
/* fill a bit */
|
||||
buf[0] = 0x80;
|
||||
sha1_update(pms, buf, 1);
|
||||
|
||||
/* Decrement sha1_size1, sha1_size2 */
|
||||
if((pms->sha1_size1 -= BITS) == 0) {
|
||||
pms->sha1_size2--;
|
||||
}
|
||||
|
||||
/* fill zeros */
|
||||
if(pms->sha1_count > (signed) (sizeof(pms->sha1_buf) - 2 * sizeof(sha1_word_t))) {
|
||||
memset(pms->sha1_buf + pms->sha1_count, 0, sizeof(pms->sha1_buf) - pms->sha1_count);
|
||||
sha1_update_now(pms, pms->sha1_buf);
|
||||
pms->sha1_count = 0;
|
||||
}
|
||||
memset(pms->sha1_buf + pms->sha1_count, 0,
|
||||
sizeof(pms->sha1_buf) - pms->sha1_count - sizeof(sha1_word_t) * 2);
|
||||
|
||||
/* fill last length */
|
||||
unpackup(pms->sha1_buf + sizeof(pms->sha1_buf) - sizeof(sha1_word_t) * 2, pms->sha1_size2);
|
||||
unpackup(pms->sha1_buf + sizeof(pms->sha1_buf) - sizeof(sha1_word_t) * 1, pms->sha1_size1);
|
||||
|
||||
/* final update */
|
||||
sha1_update_now(pms, pms->sha1_buf);
|
||||
|
||||
/* move hash value to output byte array */
|
||||
for(i = 0; i < (signed) (sizeof(pms->sha1_h)/sizeof(sha1_word_t)); i++) {
|
||||
unpackup(output + i * sizeof(sha1_word_t), pms->sha1_h[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_sha1( const void * input_buffer, int length, unsigned char * output)
|
||||
{
|
||||
sha1_state_t pms;
|
||||
sha1_init( &pms );
|
||||
sha1_update( &pms, (sha1_byte_t *) input_buffer, length );
|
||||
sha1_finish( &pms, (sha1_byte_t *) output );
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
sha1.h: Implementation of SHA-1 Secure Hash Algorithm-1
|
||||
|
||||
Based upon: NIST FIPS180-1 Secure Hash Algorithm-1
|
||||
http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||
|
||||
Non-official Japanese Translation by HIRATA Yasuyuki:
|
||||
http://yasu.asuka.net/translations/SHA-1.html
|
||||
|
||||
Copyright (C) 2002 vi@nwr.jp. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgement in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as beging the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Note:
|
||||
The copyright notice above is copied from md5.h by L. Petet Deutsch
|
||||
<ghost@aladdin.com>. Thank him since I'm not a good speaker of English. :)
|
||||
|
||||
$Id$
|
||||
*/
|
||||
#ifndef SHA1_H
|
||||
#define SHA1_H
|
||||
|
||||
/* We use OpenSSL whenever possible, since it is likely to be more
|
||||
optimized and it is ok to use it with a MIT-licensed application.
|
||||
Otherwise, we use the included implementation by vi@nwr.jp. */
|
||||
#if defined(HAVE_OPENSSL) || defined(HAVE_LIBSSL)
|
||||
|
||||
#undef SHA_DIGEST_LENGTH
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <inttypes.h>
|
||||
#define SHA1_OUTPUT_SIZE 20 /* in bytes */
|
||||
|
||||
typedef struct sha1_state_s sha1_state_t;
|
||||
typedef uint32_t sha1_word_t; /* 32bits unsigned integer */
|
||||
typedef uint8_t sha1_byte_t; /* 8bits unsigned integer */
|
||||
|
||||
/* Initialize SHA-1 algorithm */
|
||||
void sha1_init(sha1_state_t *pms);
|
||||
|
||||
/* Append a string to SHA-1 algorithm */
|
||||
void sha1_update(sha1_state_t *pms, sha1_byte_t *input_buffer, int length);
|
||||
|
||||
/* Finish the SHA-1 algorithm and return the hash */
|
||||
void sha1_finish(sha1_state_t *pms, sha1_byte_t output[SHA1_OUTPUT_SIZE]);
|
||||
|
||||
/* Convenience version of the above */
|
||||
void tr_sha1( const void * input_buffer, int length, unsigned char * output);
|
||||
|
||||
#define SHA1(in,inlen,out) tr_sha1(in,inlen,out)
|
||||
|
||||
#endif /* ifndef HAVE_OPENSSL, HAVE_LIBSSL */
|
||||
|
||||
#endif /* #ifndef SHA1_H */
|
|
@ -25,53 +25,44 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "choking.h"
|
||||
#include "handshake.h"
|
||||
#include "natpmp.h"
|
||||
#include "net.h"
|
||||
#include "peer.h"
|
||||
#include "peer-io.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "platform.h"
|
||||
#include "shared.h"
|
||||
#include "trevent.h"
|
||||
#include "upnp.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Maximum number of peers that we keep in our local list */
|
||||
/* This is an arbitrary number, but it seems to work well */
|
||||
#define MAX_PEER_COUNT 128
|
||||
|
||||
struct tr_shared_s
|
||||
struct tr_shared
|
||||
{
|
||||
tr_handle_t * h;
|
||||
volatile int die;
|
||||
tr_thread_t * thread;
|
||||
tr_lock_t * lock;
|
||||
tr_handle * h;
|
||||
tr_lock * lock;
|
||||
tr_timer * pulseTimer;
|
||||
|
||||
/* Incoming connections */
|
||||
int publicPort;
|
||||
int bindPort;
|
||||
int bindSocket;
|
||||
int peerCount;
|
||||
tr_peer_t * peers[MAX_PEER_COUNT];
|
||||
int publicPort;
|
||||
int bindPort;
|
||||
int bindSocket;
|
||||
|
||||
/* NAT-PMP/UPnP */
|
||||
tr_natpmp_t * natpmp;
|
||||
tr_upnp_t * upnp;
|
||||
|
||||
/* Choking */
|
||||
tr_choking_t * choking;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Local prototypes
|
||||
**********************************************************************/
|
||||
static void SharedLoop( void * );
|
||||
static void SetPublicPort( tr_shared_t *, int );
|
||||
static void AcceptPeers( tr_shared_t * );
|
||||
static void ReadPeers( tr_shared_t * );
|
||||
static void DispatchPeers( tr_shared_t * );
|
||||
static int SharedLoop( void * );
|
||||
static void SetPublicPort( tr_shared *, int );
|
||||
static void AcceptPeers( tr_shared * );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -79,9 +70,9 @@ static void DispatchPeers( tr_shared_t * );
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
tr_shared_t * tr_sharedInit( tr_handle_t * h )
|
||||
tr_shared * tr_sharedInit( tr_handle * h )
|
||||
{
|
||||
tr_shared_t * s = calloc( 1, sizeof( tr_shared_t ) );
|
||||
tr_shared * s = calloc( 1, sizeof( tr_shared ) );
|
||||
|
||||
s->h = h;
|
||||
s->lock = tr_lockNew( );
|
||||
|
@ -90,9 +81,7 @@ tr_shared_t * tr_sharedInit( tr_handle_t * h )
|
|||
s->bindSocket = -1;
|
||||
s->natpmp = tr_natpmpInit();
|
||||
s->upnp = tr_upnpInit();
|
||||
s->choking = tr_chokingInit( h );
|
||||
s->die = 0;
|
||||
s->thread = tr_threadNew( SharedLoop, s, "shared" );
|
||||
s->pulseTimer = tr_timerNew( h, SharedLoop, s, 250 );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -102,40 +91,27 @@ tr_shared_t * tr_sharedInit( tr_handle_t * h )
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_sharedClose( tr_shared_t * s )
|
||||
void tr_sharedClose( tr_shared * s )
|
||||
{
|
||||
int ii;
|
||||
fprintf( stderr, "deleting pulse tag\n" );
|
||||
tr_timerFree( &s->pulseTimer );
|
||||
|
||||
/* Stop the thread */
|
||||
s->die = 1;
|
||||
tr_threadJoin( s->thread );
|
||||
|
||||
/* Clean up */
|
||||
for( ii = 0; ii < s->peerCount; ii++ )
|
||||
{
|
||||
tr_peerDestroy( s->peers[ii] );
|
||||
}
|
||||
if( s->bindSocket > -1 )
|
||||
{
|
||||
tr_netClose( s->bindSocket );
|
||||
}
|
||||
tr_netClose( s->bindSocket );
|
||||
tr_lockFree( s->lock );
|
||||
tr_natpmpClose( s->natpmp );
|
||||
tr_upnpClose( s->upnp );
|
||||
tr_chokingClose( s->choking );
|
||||
free( s );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedLock, tr_sharedUnlock
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_sharedLock( tr_shared_t * s )
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
void tr_sharedLock( tr_shared * s )
|
||||
{
|
||||
tr_lockLock( s->lock );
|
||||
}
|
||||
void tr_sharedUnlock( tr_shared_t * s )
|
||||
void tr_sharedUnlock( tr_shared * s )
|
||||
{
|
||||
tr_lockUnlock( s->lock );
|
||||
}
|
||||
|
@ -145,7 +121,7 @@ void tr_sharedUnlock( tr_shared_t * s )
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_sharedSetPort( tr_shared_t * s, int port )
|
||||
void tr_sharedSetPort( tr_shared * s, int port )
|
||||
{
|
||||
#ifdef BEOS_NETSERVER
|
||||
/* BeOS net_server seems to be unable to set incoming connections
|
||||
|
@ -196,12 +172,7 @@ void tr_sharedSetPort( tr_shared_t * s, int port )
|
|||
tr_sharedUnlock( s );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedGetPublicPort
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
int tr_sharedGetPublicPort( tr_shared_t * s )
|
||||
int tr_sharedGetPublicPort( tr_shared * s )
|
||||
{
|
||||
return s->publicPort;
|
||||
}
|
||||
|
@ -211,7 +182,7 @@ int tr_sharedGetPublicPort( tr_shared_t * s )
|
|||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_sharedTraversalEnable( tr_shared_t * s, int enable )
|
||||
void tr_sharedTraversalEnable( tr_shared * s, int enable )
|
||||
{
|
||||
if( enable )
|
||||
{
|
||||
|
@ -225,7 +196,7 @@ void tr_sharedTraversalEnable( tr_shared_t * s, int enable )
|
|||
}
|
||||
}
|
||||
|
||||
int tr_sharedTraversalStatus( tr_shared_t * s )
|
||||
int tr_sharedTraversalStatus( tr_shared * s )
|
||||
{
|
||||
int statuses[] = {
|
||||
TR_NAT_TRAVERSAL_MAPPED,
|
||||
|
@ -255,14 +226,6 @@ int tr_sharedTraversalStatus( tr_shared_t * s )
|
|||
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedSetLimit
|
||||
**********************************************************************/
|
||||
void tr_sharedSetLimit( tr_shared_t * s, int limit )
|
||||
{
|
||||
tr_chokingSetLimit( s->choking, limit );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Local functions
|
||||
|
@ -271,61 +234,36 @@ void tr_sharedSetLimit( tr_shared_t * s, int limit )
|
|||
/***********************************************************************
|
||||
* SharedLoop
|
||||
**********************************************************************/
|
||||
static void SharedLoop( void * _s )
|
||||
static int
|
||||
SharedLoop( void * vs )
|
||||
{
|
||||
tr_shared_t * s = _s;
|
||||
uint64_t date1, date2, lastchoke = 0;
|
||||
int newPort;
|
||||
int newPort;
|
||||
tr_shared * s = vs;
|
||||
|
||||
tr_sharedLock( s );
|
||||
|
||||
while( !s->die )
|
||||
{
|
||||
date1 = tr_date();
|
||||
/* NAT-PMP and UPnP pulses */
|
||||
newPort = -1;
|
||||
tr_natpmpPulse( s->natpmp, &newPort );
|
||||
if( 0 < newPort && newPort != s->publicPort )
|
||||
SetPublicPort( s, newPort );
|
||||
tr_upnpPulse( s->upnp );
|
||||
|
||||
/* NAT-PMP and UPnP pulses */
|
||||
newPort = -1;
|
||||
tr_natpmpPulse( s->natpmp, &newPort );
|
||||
if( 0 < newPort && newPort != s->publicPort )
|
||||
{
|
||||
SetPublicPort( s, newPort );
|
||||
}
|
||||
tr_upnpPulse( s->upnp );
|
||||
|
||||
/* Handle incoming connections */
|
||||
AcceptPeers( s );
|
||||
ReadPeers( s );
|
||||
DispatchPeers( s );
|
||||
|
||||
/* Update choking every second */
|
||||
if( date1 > lastchoke + 1000 )
|
||||
{
|
||||
tr_chokingPulse( s->choking );
|
||||
lastchoke = date1;
|
||||
}
|
||||
|
||||
tr_swiftPulse ( s->h );
|
||||
|
||||
/* Wait up to 20 ms */
|
||||
date2 = tr_date();
|
||||
if( date2 < date1 + 20 )
|
||||
{
|
||||
tr_sharedUnlock( s );
|
||||
tr_wait( date1 + 20 - date2 );
|
||||
tr_sharedLock( s );
|
||||
}
|
||||
}
|
||||
/* Handle incoming connections */
|
||||
AcceptPeers( s );
|
||||
|
||||
tr_sharedUnlock( s );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SetPublicPort
|
||||
**********************************************************************/
|
||||
static void SetPublicPort( tr_shared_t * s, int port )
|
||||
static void SetPublicPort( tr_shared * s, int port )
|
||||
{
|
||||
tr_handle_t * h = s->h;
|
||||
tr_torrent_t * tor;
|
||||
tr_handle * h = s->h;
|
||||
tr_torrent * tor;
|
||||
|
||||
s->publicPort = port;
|
||||
|
||||
|
@ -338,106 +276,22 @@ static void SetPublicPort( tr_shared_t * s, int port )
|
|||
***********************************************************************
|
||||
* Check incoming connections and add the peers to our local list
|
||||
**********************************************************************/
|
||||
static void AcceptPeers( tr_shared_t * s )
|
||||
{
|
||||
int socket;
|
||||
struct in_addr addr;
|
||||
|
||||
static void
|
||||
AcceptPeers( tr_shared * s )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
if( s->bindSocket < 0 || s->peerCount >= MAX_PEER_COUNT )
|
||||
{
|
||||
int socket;
|
||||
struct in_addr addr;
|
||||
|
||||
if( s->bindSocket < 0 || !tr_peerMgrIsAcceptingConnections( s->h->peerMgr ) )
|
||||
break;
|
||||
}
|
||||
|
||||
socket = tr_netAccept( s->bindSocket, &addr, NULL );
|
||||
if( socket < 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
s->peers[s->peerCount++] = tr_peerInit( &addr, 0, socket,
|
||||
TR_PEER_FROM_INCOMING );
|
||||
|
||||
tr_peerMgrAddIncoming( s->h->peerMgr, &addr, socket );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* ReadPeers
|
||||
***********************************************************************
|
||||
* Try to read handshakes
|
||||
**********************************************************************/
|
||||
static void ReadPeers( tr_shared_t * s )
|
||||
{
|
||||
int ii;
|
||||
|
||||
for( ii = 0; ii < s->peerCount; )
|
||||
{
|
||||
if( tr_peerRead( s->peers[ii] ) )
|
||||
{
|
||||
tr_peerDestroy( s->peers[ii] );
|
||||
s->peerCount--;
|
||||
memmove( &s->peers[ii], &s->peers[ii+1],
|
||||
( s->peerCount - ii ) * sizeof( tr_peer_t * ) );
|
||||
continue;
|
||||
}
|
||||
ii++;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DispatchPeers
|
||||
***********************************************************************
|
||||
* If we got a handshake, try to find the torrent for this peer
|
||||
**********************************************************************/
|
||||
static void DispatchPeers( tr_shared_t * s )
|
||||
{
|
||||
tr_handle_t * h = s->h;
|
||||
int ii;
|
||||
const uint64_t now = tr_date();
|
||||
|
||||
for( ii = 0; ii < s->peerCount; )
|
||||
{
|
||||
const uint8_t * hash = tr_peerHash( s->peers[ii] );
|
||||
|
||||
if( !hash && now > tr_peerDate( s->peers[ii] ) + 10000 )
|
||||
{
|
||||
/* 10 seconds and no handshake, drop it */
|
||||
tr_peerDestroy( s->peers[ii] );
|
||||
goto removePeer;
|
||||
}
|
||||
if( hash )
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
|
||||
for( tor = h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_torrentWriterLock( tor );
|
||||
if( tor->runStatus != TR_RUN_RUNNING )
|
||||
{
|
||||
tr_torrentWriterUnlock( tor );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !memcmp( tor->info.hash, hash, SHA_DIGEST_LENGTH ) )
|
||||
{
|
||||
/* Found it! */
|
||||
tr_torrentAttachPeer( tor, s->peers[ii] );
|
||||
tr_torrentWriterUnlock( tor );
|
||||
goto removePeer;
|
||||
}
|
||||
tr_torrentWriterUnlock( tor );
|
||||
}
|
||||
|
||||
/* Couldn't find a torrent, we probably removed it */
|
||||
tr_peerDestroy( s->peers[ii] );
|
||||
goto removePeer;
|
||||
}
|
||||
ii++;
|
||||
continue;
|
||||
|
||||
removePeer:
|
||||
s->peerCount--;
|
||||
memmove( &s->peers[ii], &s->peers[ii+1],
|
||||
( s->peerCount - ii ) * sizeof( tr_peer_t * ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "transmission.h"
|
||||
|
||||
typedef struct tr_shared_s tr_shared_t;
|
||||
typedef struct tr_shared tr_shared;
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedInit, tr_sharedClose
|
||||
|
@ -35,8 +35,8 @@ typedef struct tr_shared_s tr_shared_t;
|
|||
* Starts / stops a thread to handle running things that are shared
|
||||
* among the torrents: NAT-PMP/UPnP, incoming connections, peer choking
|
||||
**********************************************************************/
|
||||
tr_shared_t * tr_sharedInit ( tr_handle_t * );
|
||||
void tr_sharedClose ( tr_shared_t * );
|
||||
tr_shared * tr_sharedInit ( tr_handle * );
|
||||
void tr_sharedClose ( tr_shared * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedLock, tr_sharedUnlock
|
||||
|
@ -44,8 +44,8 @@ void tr_sharedClose ( tr_shared_t * );
|
|||
* Gets / releases exclusive access to ressources used by the shared
|
||||
* thread
|
||||
**********************************************************************/
|
||||
void tr_sharedLock ( tr_shared_t * );
|
||||
void tr_sharedUnlock ( tr_shared_t * );
|
||||
void tr_sharedLock ( tr_shared * );
|
||||
void tr_sharedUnlock ( tr_shared * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedSetPort
|
||||
|
@ -53,8 +53,8 @@ void tr_sharedUnlock ( tr_shared_t * );
|
|||
* Changes the port for incoming connections. tr_sharedGetPublicPort
|
||||
* should be called with the shared lock held.
|
||||
**********************************************************************/
|
||||
void tr_sharedSetPort ( tr_shared_t *, int port );
|
||||
int tr_sharedGetPublicPort ( tr_shared_t * s );
|
||||
void tr_sharedSetPort ( tr_shared *, int port );
|
||||
int tr_sharedGetPublicPort ( tr_shared * s );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedTraversalEnable, tr_sharedTraversalStatus
|
||||
|
@ -62,15 +62,9 @@ int tr_sharedGetPublicPort ( tr_shared_t * s );
|
|||
* Enables/disables and retrieves the status of NAT traversal. Should
|
||||
* be called with the shared lock held.
|
||||
**********************************************************************/
|
||||
void tr_sharedTraversalEnable ( tr_shared_t *, int enable );
|
||||
int tr_sharedTraversalStatus ( tr_shared_t * );
|
||||
void tr_sharedTraversalEnable ( tr_shared *, int enable );
|
||||
int tr_sharedTraversalStatus ( tr_shared * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_sharedSetLimit
|
||||
***********************************************************************
|
||||
*
|
||||
**********************************************************************/
|
||||
void tr_sharedSetLimit ( tr_shared_t *, int limit );
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h> /* u_char for event.h */
|
||||
#include <event.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "trevent.h"
|
||||
#include "timer.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef int tr_timer_func ( void * user_data );
|
||||
typedef void tr_data_free_func( void * user_data );
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
struct timer_node
|
||||
{
|
||||
tr_handle_t * handle;
|
||||
struct event * event;
|
||||
tr_timer_func * func;
|
||||
void * user_data;
|
||||
tr_data_free_func * free_func;
|
||||
struct timeval tv;
|
||||
uint8_t doFree;
|
||||
};
|
||||
|
||||
void
|
||||
tr_timerFree( struct timer_node ** node )
|
||||
{
|
||||
if( *node )
|
||||
{
|
||||
(*node)->doFree = 1;
|
||||
*node = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
timerCB( int fd UNUSED, short event UNUSED, void * arg )
|
||||
{
|
||||
struct timer_node * node = (struct timer_node *) arg;
|
||||
|
||||
if( !node->doFree )
|
||||
node->doFree = !(node->func)(node->user_data);
|
||||
|
||||
if( !node->doFree )
|
||||
tr_event_add( node->handle, node->event, &node->tv );
|
||||
else {
|
||||
if( node->free_func != NULL )
|
||||
(node->free_func)( node->user_data );
|
||||
tr_event_del( node->handle, node->event );
|
||||
tr_free( node );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tr_timer_tag
|
||||
tr_timerNew( tr_handle_t * handle,
|
||||
tr_timer_func func,
|
||||
void * user_data,
|
||||
tr_data_free_func free_func,
|
||||
int timeout_milliseconds )
|
||||
{
|
||||
struct timer_node * node;
|
||||
|
||||
assert( func != NULL );
|
||||
assert( timeout_milliseconds >= 0 );
|
||||
|
||||
node = tr_new( struct timer_node, 1 );
|
||||
node->handle = handle;
|
||||
node->event = tr_new0( struct event, 1 );
|
||||
node->func = func;
|
||||
node->user_data = user_data;
|
||||
node->free_func = free_func;
|
||||
node->doFree = 0;
|
||||
node->tv = timevalMsec ( timeout_milliseconds );
|
||||
timeout_set( node->event, timerCB, node );
|
||||
tr_event_add( handle, node->event, &node->tv );
|
||||
return node;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* 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 _TR_TIMER_H_
|
||||
#define _TR_TIMER_H_
|
||||
|
||||
typedef struct timer_node * tr_timer_tag;
|
||||
|
||||
/**
|
||||
* Calls timer_func(user_data) after the specified interval.
|
||||
* The timer is freed if timer_func returns zero.
|
||||
* Otherwise, it's called again after the same interval.
|
||||
*
|
||||
* If free_func is non-NULL, free_func(user_data) is called
|
||||
* by the timer when it's freed (either from timer_func returning
|
||||
* zero or from a client call to tr_timerFree). This is useful
|
||||
* if user_data has resources that need to be freed.
|
||||
*/
|
||||
tr_timer_tag tr_timerNew( struct tr_handle_s * handle,
|
||||
int timer_func( void * user_data ),
|
||||
void * user_data,
|
||||
void free_func( void * user_data ),
|
||||
int timeout_milliseconds );
|
||||
|
||||
/**
|
||||
* Frees a timer and sets its tag to NULL.
|
||||
*/
|
||||
void tr_timerFree( tr_timer_tag * tag );
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -28,7 +28,6 @@
|
|||
#include "net.h"
|
||||
#include "ptrarray.h"
|
||||
#include "publish.h"
|
||||
#include "timer.h"
|
||||
#include "tracker.h"
|
||||
#include "trevent.h"
|
||||
#include "utils.h"
|
||||
|
@ -65,9 +64,9 @@ typedef struct
|
|||
{
|
||||
tr_handle_t * handle;
|
||||
|
||||
tr_ptrArray_t * torrents;
|
||||
tr_ptrArray_t * scraping;
|
||||
tr_ptrArray_t * scrapeQueue;
|
||||
tr_ptrArray * torrents;
|
||||
tr_ptrArray * scraping;
|
||||
tr_ptrArray * scrapeQueue;
|
||||
|
||||
/* these are set from the latest scrape or tracker response */
|
||||
int announceIntervalMsec;
|
||||
|
@ -78,8 +77,8 @@ typedef struct
|
|||
back than we asked for */
|
||||
int multiscrapeMax;
|
||||
|
||||
tr_tracker_info_t * redirect;
|
||||
tr_tracker_info_t * addresses;
|
||||
tr_tracker_info * redirect;
|
||||
tr_tracker_info * addresses;
|
||||
int addressIndex;
|
||||
int addressCount;
|
||||
int * tierFronts;
|
||||
|
@ -91,14 +90,16 @@ typedef struct
|
|||
This is immutable for the life of the tracker object. */
|
||||
char key_param[TR_KEY_LEN+1];
|
||||
|
||||
tr_timer_tag scrapeTag;
|
||||
tr_timer * scrapeTimer;
|
||||
|
||||
struct evhttp_connection * connection;
|
||||
}
|
||||
Tracker;
|
||||
|
||||
/* this is the Torrent struct, but since it's the pointer
|
||||
passed around in the public API of this tracker module,
|
||||
its *public* name is tr_tracker_s... wheee */
|
||||
typedef struct tr_tracker_s
|
||||
its *public* name is tr_tracker... wheee */
|
||||
typedef struct tr_tracker
|
||||
{
|
||||
tr_publisher_t * publisher;
|
||||
|
||||
|
@ -129,12 +130,12 @@ typedef struct tr_tracker_s
|
|||
|
||||
Tracker * tracker;
|
||||
|
||||
tr_timer_tag scrapeTag;
|
||||
tr_timer_tag reannounceTag;
|
||||
tr_timer * scrapeTimer;
|
||||
tr_timer * reannounceTimer;
|
||||
|
||||
struct evhttp_request * httpReq;
|
||||
|
||||
tr_torrent_t * torrent;
|
||||
tr_torrent * torrent;
|
||||
}
|
||||
Torrent;
|
||||
|
||||
|
@ -158,47 +159,27 @@ torrentCompare( const void * va, const void * vb )
|
|||
****
|
||||
***/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char * address;
|
||||
int port;
|
||||
struct evhttp_connection * evconn;
|
||||
}
|
||||
connection_key_t;
|
||||
|
||||
static int
|
||||
connectionCompare( const void * va, const void * vb )
|
||||
{
|
||||
const connection_key_t * a = (const connection_key_t *) va;
|
||||
const connection_key_t * b = (const connection_key_t *) vb;
|
||||
int ret = strcmp( a->address, b->address );
|
||||
if( ret ) return ret;
|
||||
return a->port - b->port;
|
||||
}
|
||||
|
||||
static struct evhttp_connection*
|
||||
getConnection( const char * address, int port )
|
||||
getConnection( Tracker * tracker, const char * address, int port )
|
||||
{
|
||||
connection_key_t *val, tmp;
|
||||
|
||||
static tr_ptrArray_t * connections = NULL;
|
||||
if( !connections )
|
||||
connections = tr_ptrArrayNew( );
|
||||
|
||||
tmp.address = (char*) address;
|
||||
tmp.port = port;
|
||||
val = tr_ptrArrayFindSorted( connections, &tmp, connectionCompare );
|
||||
|
||||
if( !val )
|
||||
if( tracker->connection != NULL )
|
||||
{
|
||||
val = tr_new( connection_key_t, 1 );
|
||||
val->address = tr_strdup( address );
|
||||
val->port = port;
|
||||
val->evconn = evhttp_connection_new( address, port );
|
||||
tr_ptrArrayInsertSorted( connections, val, connectionCompare );
|
||||
char * a = NULL;
|
||||
unsigned short p = 0;
|
||||
evhttp_connection_get_peer( tracker->connection, &a, &p );
|
||||
|
||||
/* old one matches -- reuse it */
|
||||
if( a && !strcmp(a,address) && p==port )
|
||||
return tracker->connection;
|
||||
|
||||
/* old one doesn't match -- throw it away */
|
||||
evhttp_connection_free( tracker->connection );
|
||||
tracker->connection = NULL;
|
||||
}
|
||||
|
||||
return val->evconn;
|
||||
/* make a new connection */
|
||||
tracker->connection = evhttp_connection_new( address, port );
|
||||
return tracker->connection;
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -252,10 +233,10 @@ publishStopped( Torrent * tor )
|
|||
**** LIFE CYCLE
|
||||
***/
|
||||
|
||||
static tr_ptrArray_t *
|
||||
static tr_ptrArray *
|
||||
getTrackerLookupTable( void )
|
||||
{
|
||||
static tr_ptrArray_t * myTrackers = NULL;
|
||||
static tr_ptrArray * myTrackers = NULL;
|
||||
if( !myTrackers )
|
||||
myTrackers = tr_ptrArrayNew( );
|
||||
return myTrackers;
|
||||
|
@ -280,17 +261,18 @@ tr_trackerScrapeSoon( Tracker * t )
|
|||
if( !tr_ptrArrayEmpty( t->scraping ) )
|
||||
return;
|
||||
|
||||
if( !t->scrapeTag )
|
||||
t->scrapeTag = tr_timerNew( t->handle,
|
||||
onTrackerScrapeNow, t,
|
||||
NULL, 1000 );
|
||||
if( !t->scrapeTimer )
|
||||
t->scrapeTimer = tr_timerNew( t->handle, onTrackerScrapeNow, t, 1000 );
|
||||
}
|
||||
|
||||
static int trackerCount = 0;
|
||||
static int torrentCount = 0;
|
||||
|
||||
static Tracker*
|
||||
tr_trackerGet( const tr_torrent_t * tor )
|
||||
tr_trackerGet( const tr_torrent * tor )
|
||||
{
|
||||
const tr_info_t * info = &tor->info;
|
||||
tr_ptrArray_t * trackers = getTrackerLookupTable( );
|
||||
const tr_info * info = &tor->info;
|
||||
tr_ptrArray * trackers = getTrackerLookupTable( );
|
||||
Tracker *t, tmp;
|
||||
assert( info != NULL );
|
||||
assert( info->primaryAddress && *info->primaryAddress );
|
||||
|
@ -302,10 +284,11 @@ tr_trackerGet( const tr_torrent_t * tor )
|
|||
if( t == NULL ) /* no such tracker.... create one */
|
||||
{
|
||||
int i, j, sum, *iwalk;
|
||||
tr_tracker_info_t * nwalk;
|
||||
tr_tracker_info * nwalk;
|
||||
tr_dbg( "making a new tracker for \"%s\"", info->primaryAddress );
|
||||
|
||||
t = tr_new0( Tracker, 1 );
|
||||
fprintf( stderr, "TRACKER new tracker %p addr %s; counts are trackers %d torrents %d\n", t, info->primaryAddress, ++trackerCount, torrentCount );
|
||||
t->handle = tor->handle;
|
||||
t->primaryAddress = tr_strdup( info->primaryAddress );
|
||||
t->scrapeIntervalMsec = DEFAULT_SCRAPE_INTERVAL_MSEC;
|
||||
|
@ -319,7 +302,7 @@ tr_trackerGet( const tr_torrent_t * tor )
|
|||
|
||||
for( sum=i=0; i<info->trackerTiers; ++i )
|
||||
sum += info->trackerList[i].count;
|
||||
t->addresses = nwalk = tr_new0( tr_tracker_info_t, sum );
|
||||
t->addresses = nwalk = tr_new0( tr_tracker_info, sum );
|
||||
t->addressIndex = 0;
|
||||
t->addressCount = sum;
|
||||
t->tierFronts = iwalk = tr_new0( int, sum );
|
||||
|
@ -330,7 +313,7 @@ tr_trackerGet( const tr_torrent_t * tor )
|
|||
|
||||
for( j=0; j<info->trackerList[i].count; ++j )
|
||||
{
|
||||
const tr_tracker_info_t * src = &info->trackerList[i].list[j];
|
||||
const tr_tracker_info * src = &info->trackerList[i].list[j];
|
||||
nwalk->address = tr_strdup( src->address );
|
||||
nwalk->port = src->port;
|
||||
nwalk->announce = tr_strdup( src->announce );
|
||||
|
@ -370,7 +353,7 @@ escape( char * out, const uint8_t * in, int in_len ) /* rfc2396 */
|
|||
*out = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
onTorrentFreeNow( void * vtor )
|
||||
{
|
||||
Torrent * tor = (Torrent *) vtor;
|
||||
|
@ -380,11 +363,14 @@ onTorrentFreeNow( void * vtor )
|
|||
tr_ptrArrayRemoveSorted( t->scrapeQueue, tor, torrentCompare );
|
||||
tr_ptrArrayRemoveSorted( t->scraping, tor, torrentCompare );
|
||||
|
||||
tr_timerFree( &tor->scrapeTag );
|
||||
tr_timerFree( &tor->reannounceTag );
|
||||
tr_publisherFree( tor->publisher );
|
||||
fprintf( stderr, "TRACKER freeing torrent %p name %s; counts are trackers %d torrents %d\n", tor, tor->torrent->info.name, trackerCount, --torrentCount );
|
||||
tr_timerFree( &tor->scrapeTimer );
|
||||
tr_timerFree( &tor->reannounceTimer );
|
||||
tr_publisherFree( &tor->publisher );
|
||||
tr_free( tor->trackerID );
|
||||
tr_free( tor->lastRequest );
|
||||
if( tor->httpReq != NULL )
|
||||
evhttp_request_free( tor->httpReq );
|
||||
tr_free( tor );
|
||||
|
||||
if( tr_ptrArrayEmpty( t->torrents ) ) /* last one.. free the tracker too */
|
||||
|
@ -392,6 +378,11 @@ onTorrentFreeNow( void * vtor )
|
|||
int i;
|
||||
tr_ptrArrayRemoveSorted( getTrackerLookupTable( ), t, trackerCompare );
|
||||
|
||||
fprintf( stderr, "TRACKER freeing tracker %p; counts are trackers %d torrents %d\n", t, --trackerCount, torrentCount );
|
||||
|
||||
if( t->connection != NULL )
|
||||
evhttp_connection_free( t->connection );
|
||||
|
||||
tr_ptrArrayFree( t->torrents );
|
||||
tr_ptrArrayFree( t->scrapeQueue );
|
||||
tr_ptrArrayFree( t->scraping );
|
||||
|
@ -404,26 +395,23 @@ onTorrentFreeNow( void * vtor )
|
|||
tr_free( t->redirect );
|
||||
}
|
||||
|
||||
tr_timerFree( &t->scrapeTag );
|
||||
tr_timerFree( &t->scrapeTimer );
|
||||
|
||||
tr_free( t->primaryAddress );
|
||||
tr_free( t->addresses );
|
||||
tr_free( t->tierFronts );
|
||||
tr_free( t );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
tr_trackerFree( Torrent * tor )
|
||||
{
|
||||
tr_timerNew( tor->tracker->handle,
|
||||
onTorrentFreeNow, tor, NULL, 0 );
|
||||
tr_runInEventThread( tor->tracker->handle, onTorrentFreeNow, tor );
|
||||
}
|
||||
|
||||
Torrent*
|
||||
tr_trackerNew( tr_torrent_t * torrent )
|
||||
tr_trackerNew( tr_torrent * torrent )
|
||||
{
|
||||
Torrent * tor;
|
||||
Tracker * t = tr_trackerGet( torrent );
|
||||
|
@ -431,6 +419,7 @@ tr_trackerNew( tr_torrent_t * torrent )
|
|||
|
||||
/* create a new Torrent and queue it for scraping */
|
||||
tor = tr_new0( Torrent, 1 );
|
||||
fprintf( stderr, "TRACKER new torrent %p name %s; counts are trackers %d torrents %d\n", tor, torrent->info.name, trackerCount, ++torrentCount );
|
||||
tor->publisher = tr_publisherNew( );
|
||||
tor->tracker = t;
|
||||
tor->torrent = torrent;
|
||||
|
@ -488,7 +477,7 @@ updateAddresses( Tracker * t, const struct evhttp_request * req )
|
|||
successful, it will be moved to the front of the tier." */
|
||||
const int i = t->addressIndex;
|
||||
const int j = t->tierFronts[i];
|
||||
const tr_tracker_info_t swap = t->addresses[i];
|
||||
const tr_tracker_info swap = t->addresses[i];
|
||||
t->addresses[i] = t->addresses[j];
|
||||
t->addresses[j] = swap;
|
||||
}
|
||||
|
@ -497,21 +486,21 @@ updateAddresses( Tracker * t, const struct evhttp_request * req )
|
|||
|| ( req->response_code == HTTP_MOVETEMP ) )
|
||||
{
|
||||
const char * loc = evhttp_find_header( req->input_headers, "Location" );
|
||||
tr_tracker_info_t tmp;
|
||||
tr_tracker_info tmp;
|
||||
if( tr_trackerInfoInit( &tmp, loc, -1 ) ) /* a bad redirect? */
|
||||
{
|
||||
moveToNextAddress = TRUE;
|
||||
}
|
||||
else if( req->response_code == HTTP_MOVEPERM )
|
||||
{
|
||||
tr_tracker_info_t * cur = &t->addresses[t->addressIndex];
|
||||
tr_tracker_info * cur = &t->addresses[t->addressIndex];
|
||||
tr_trackerInfoClear( cur );
|
||||
*cur = tmp;
|
||||
}
|
||||
else if( req->response_code == HTTP_MOVETEMP )
|
||||
{
|
||||
if( t->redirect == NULL )
|
||||
t->redirect = tr_new0( tr_tracker_info_t, 1 );
|
||||
t->redirect = tr_new0( tr_tracker_info, 1 );
|
||||
else
|
||||
tr_trackerInfoClear( t->redirect );
|
||||
*t->redirect = tmp;
|
||||
|
@ -534,7 +523,7 @@ updateAddresses( Tracker * t, const struct evhttp_request * req )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static tr_tracker_info_t *
|
||||
static tr_tracker_info *
|
||||
getCurrentAddress( const Tracker * t )
|
||||
{
|
||||
assert( t->addresses != NULL );
|
||||
|
@ -546,7 +535,7 @@ getCurrentAddress( const Tracker * t )
|
|||
static int
|
||||
trackerSupportsScrape( const Tracker * t )
|
||||
{
|
||||
const tr_tracker_info_t * info = getCurrentAddress( t );
|
||||
const tr_tracker_info * info = getCurrentAddress( t );
|
||||
|
||||
return ( info != NULL )
|
||||
&& ( info->scrape != NULL )
|
||||
|
@ -559,7 +548,7 @@ addCommonHeaders( const Tracker * t,
|
|||
struct evhttp_request * req )
|
||||
{
|
||||
char buf[1024];
|
||||
tr_tracker_info_t * address = getCurrentAddress( t );
|
||||
tr_tracker_info * address = getCurrentAddress( t );
|
||||
snprintf( buf, sizeof(buf), "%s:%d", address->address, address->port );
|
||||
evhttp_add_header( req->output_headers, "Host", buf );
|
||||
evhttp_add_header( req->output_headers, "Connection", "close" );
|
||||
|
@ -582,7 +571,7 @@ onTorrentScrapeNow( void * vtor )
|
|||
tr_ptrArrayInsertSorted( tor->tracker->scrapeQueue, tor, torrentCompare );
|
||||
tr_trackerScrapeSoon( tor->tracker );
|
||||
}
|
||||
tor->scrapeTag = NULL;
|
||||
tor->scrapeTimer = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -638,11 +627,8 @@ onScrapeResponse( struct evhttp_request * req, void * vt )
|
|||
assert( tr_ptrArrayFindSorted(t->scraping,tor,torrentCompare) );
|
||||
tr_ptrArrayRemoveSorted( t->scraping, tor, torrentCompare );
|
||||
|
||||
assert( !tor->scrapeTag );
|
||||
tor->scrapeTag = tr_timerNew( t->handle,
|
||||
onTorrentScrapeNow,
|
||||
tor, NULL,
|
||||
t->scrapeIntervalMsec );
|
||||
assert( !tor->scrapeTimer );
|
||||
tor->scrapeTimer = tr_timerNew( t->handle, onTorrentScrapeNow, tor, t->scrapeIntervalMsec );
|
||||
tr_dbg( "Torrent '%s' scrape successful."
|
||||
" Rescraping in %d seconds",
|
||||
tor->torrent->info.name, t->scrapeIntervalMsec/1000 );
|
||||
|
@ -699,7 +685,7 @@ static int
|
|||
onTrackerScrapeNow( void * vt )
|
||||
{
|
||||
Tracker * t = (Tracker*) vt;
|
||||
const tr_tracker_info_t * address = getCurrentAddress( t );
|
||||
const tr_tracker_info * address = getCurrentAddress( t );
|
||||
|
||||
assert( tr_ptrArrayEmpty( t->scraping ) );
|
||||
|
||||
|
@ -743,7 +729,7 @@ onTrackerScrapeNow( void * vt )
|
|||
/* ping the tracker */
|
||||
tr_inf( "Sending scrape to tracker %s:%d: %s",
|
||||
address->address, address->port, uri );
|
||||
evcon = getConnection( address->address, address->port );
|
||||
evcon = getConnection( t, address->address, address->port );
|
||||
evhttp_connection_set_timeout( evcon, SCRAPE_TIMEOUT_INTERVAL_SEC );
|
||||
req = evhttp_request_new( onScrapeResponse, t );
|
||||
assert( req );
|
||||
|
@ -751,7 +737,7 @@ onTrackerScrapeNow( void * vt )
|
|||
tr_evhttp_make_request( t->handle, evcon, req, EVHTTP_REQ_GET, uri );
|
||||
}
|
||||
|
||||
t->scrapeTag = NULL;
|
||||
t->scrapeTimer = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -772,7 +758,7 @@ torrentIsRunning( const Torrent * tor )
|
|||
static char*
|
||||
buildTrackerRequestURI( const Torrent * tor, const char * eventName )
|
||||
{
|
||||
const tr_torrent_t * torrent = tor->torrent;
|
||||
const tr_torrent * torrent = tor->torrent;
|
||||
const int stopping = !strcmp( eventName, "stopped" );
|
||||
const int numwant = stopping ? 0 : NUMWANT;
|
||||
char buf[4096];
|
||||
|
@ -964,9 +950,8 @@ onTrackerResponse( struct evhttp_request * req, void * vtor )
|
|||
else if( reannounceInterval > 0 ) {
|
||||
tr_dbg( "torrent '%s' reannouncing in %d seconds",
|
||||
tor->torrent->info.name, (reannounceInterval/1000) );
|
||||
tor->reannounceTag = tr_timerNew( tor->tracker->handle,
|
||||
onReannounceNow, tor, NULL,
|
||||
reannounceInterval );
|
||||
assert( tor->reannounceTimer == NULL );
|
||||
tor->reannounceTimer = tr_timerNew( tor->tracker->handle, onReannounceNow, tor, reannounceInterval );
|
||||
tor->manualAnnounceAllowedAt
|
||||
= tr_date() + MANUAL_ANNOUNCE_INTERVAL_MSEC;
|
||||
}
|
||||
|
@ -976,7 +961,7 @@ static int
|
|||
sendTrackerRequest( void * vtor, const char * eventName )
|
||||
{
|
||||
Torrent * tor = (Torrent *) vtor;
|
||||
const tr_tracker_info_t * address = getCurrentAddress( tor->tracker );
|
||||
const tr_tracker_info * address = getCurrentAddress( tor->tracker );
|
||||
char * uri = buildTrackerRequestURI( tor, eventName );
|
||||
struct evhttp_connection * evcon = NULL;
|
||||
|
||||
|
@ -987,9 +972,9 @@ sendTrackerRequest( void * vtor, const char * eventName )
|
|||
uri );
|
||||
|
||||
/* kill any pending requests */
|
||||
tr_timerFree( &tor->reannounceTag );
|
||||
tr_timerFree( &tor->reannounceTimer );
|
||||
|
||||
evcon = getConnection( address->address, address->port );
|
||||
evcon = getConnection( tor->tracker, address->address, address->port );
|
||||
if ( !evcon ) {
|
||||
tr_err( "Can't make a connection to %s:%d", address->address, address->port );
|
||||
tr_free( uri );
|
||||
|
@ -1011,7 +996,7 @@ onReannounceNow( void * vtor )
|
|||
{
|
||||
Torrent * tor = (Torrent *) vtor;
|
||||
sendTrackerRequest( tor, "" );
|
||||
tor->reannounceTag = NULL;
|
||||
tor->reannounceTimer = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -1034,7 +1019,7 @@ tr_trackerUnsubscribe( Torrent * tor,
|
|||
tr_publisherUnsubscribe( tor->publisher, tag );
|
||||
}
|
||||
|
||||
const tr_tracker_info_t *
|
||||
const tr_tracker_info *
|
||||
tr_trackerGetAddress( const Torrent * tor )
|
||||
{
|
||||
return getCurrentAddress( tor->tracker );
|
||||
|
@ -1070,7 +1055,7 @@ tr_trackerStart( Torrent * tor )
|
|||
{
|
||||
tr_peerIdNew( tor->peer_id, sizeof(tor->peer_id) );
|
||||
|
||||
if( !tor->reannounceTag && !tor->httpReq )
|
||||
if( !tor->reannounceTimer && !tor->httpReq )
|
||||
sendTrackerRequest( tor, "started" );
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
*** Locating a tracker
|
||||
**/
|
||||
|
||||
struct tr_tracker_s * tr_trackerNew( tr_torrent_t * );
|
||||
struct tr_tracker * tr_trackerNew( tr_torrent * );
|
||||
|
||||
void tr_trackerFree ( struct tr_tracker_s * );
|
||||
void tr_trackerFree ( struct tr_tracker * );
|
||||
|
||||
/**
|
||||
*** Tracker Publish / Subscribe
|
||||
|
@ -55,34 +55,34 @@ typedef struct
|
|||
}
|
||||
tr_tracker_event_t;
|
||||
|
||||
tr_publisher_tag tr_trackerSubscribe ( struct tr_tracker_s * tag,
|
||||
tr_delivery_func func,
|
||||
void * user );
|
||||
tr_publisher_tag tr_trackerSubscribe ( struct tr_tracker * tag,
|
||||
tr_delivery_func func,
|
||||
void * user );
|
||||
|
||||
void tr_trackerUnsubscribe ( struct tr_tracker_s * tracker,
|
||||
tr_publisher_tag tag );
|
||||
void tr_trackerUnsubscribe ( struct tr_tracker * tracker,
|
||||
tr_publisher_tag tag );
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
void tr_trackerStart ( struct tr_tracker_s * );
|
||||
void tr_trackerStart ( struct tr_tracker * );
|
||||
|
||||
void tr_trackerCompleted ( struct tr_tracker_s * );
|
||||
void tr_trackerCompleted ( struct tr_tracker * );
|
||||
|
||||
void tr_trackerStop ( struct tr_tracker_s * );
|
||||
void tr_trackerStop ( struct tr_tracker * );
|
||||
|
||||
void tr_trackerReannounce ( struct tr_tracker_s * );
|
||||
void tr_trackerReannounce ( struct tr_tracker * );
|
||||
|
||||
void tr_trackerChangeMyPort ( struct tr_tracker_s * );
|
||||
void tr_trackerChangeMyPort ( struct tr_tracker * );
|
||||
|
||||
const tr_tracker_info_t * tr_trackerGetAddress( const struct tr_tracker_s * );
|
||||
const tr_tracker_info * tr_trackerGetAddress( const struct tr_tracker * );
|
||||
|
||||
int tr_trackerCanManualAnnounce ( const struct tr_tracker_s * );
|
||||
int tr_trackerCanManualAnnounce ( const struct tr_tracker * );
|
||||
|
||||
void tr_trackerGetCounts ( const struct tr_tracker_s *,
|
||||
int * setme_completedCount,
|
||||
int * setme_leecherCount,
|
||||
int * setme_seederCount );
|
||||
void tr_trackerGetCounts ( const struct tr_tracker *,
|
||||
int * setme_completedCount,
|
||||
int * setme_leecherCount,
|
||||
int * setme_seederCount );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "fdlimit.h"
|
||||
#include "list.h"
|
||||
#include "net.h"
|
||||
#include "peer-mgr.h"
|
||||
#include "platform.h"
|
||||
#include "ratecontrol.h"
|
||||
#include "shared.h"
|
||||
|
@ -62,6 +63,38 @@ tr_peerIdNew ( char * buf, int buflen )
|
|||
buf[TR_ID_LEN] = '\0';
|
||||
}
|
||||
|
||||
const char*
|
||||
getPeerId( void )
|
||||
{
|
||||
static char * peerId = NULL;
|
||||
if( !peerId ) {
|
||||
peerId = tr_new0( char, TR_ID_LEN + 1 );
|
||||
tr_peerIdNew( peerId, TR_ID_LEN + 1 );
|
||||
}
|
||||
return peerId;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_encryption_mode
|
||||
tr_getEncryptionMode( tr_handle * handle )
|
||||
{
|
||||
assert( handle != NULL );
|
||||
|
||||
return handle->encryptionMode;
|
||||
}
|
||||
|
||||
void
|
||||
tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
|
||||
{
|
||||
assert( handle != NULL );
|
||||
assert( mode==TR_ENCRYPTION_PREFERRED || mode==TR_ENCRYPTION_REQUIRED );
|
||||
|
||||
handle->encryptionMode = mode;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -77,15 +110,24 @@ tr_handle_t * tr_init( const char * tag )
|
|||
tr_handle_t * h;
|
||||
int i;
|
||||
|
||||
#ifndef WIN32
|
||||
/* Don't exit when writing on a broken socket */
|
||||
signal( SIGPIPE, SIG_IGN );
|
||||
#endif
|
||||
|
||||
tr_msgInit();
|
||||
|
||||
h = tr_new0( tr_handle_t, 1 );
|
||||
if( !h )
|
||||
return NULL;
|
||||
|
||||
h->encryptionMode = TR_ENCRYPTION_PREFERRED;
|
||||
|
||||
tr_eventInit( h );
|
||||
while( !h->events )
|
||||
tr_wait( 50 );
|
||||
|
||||
tr_netInit();
|
||||
tr_netResolveThreadInit();
|
||||
|
||||
h->tag = strdup( tag );
|
||||
if( !h->tag ) {
|
||||
|
@ -93,16 +135,12 @@ tr_handle_t * tr_init( const char * tag )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
h->peerMgr = tr_peerMgrNew( h );
|
||||
|
||||
/* Azureus identity */
|
||||
for( i=0; i < TR_AZ_ID_LEN; ++i )
|
||||
h->azId[i] = tr_rand( 0xff );
|
||||
|
||||
#ifndef WIN32
|
||||
/* Don't exit when writing on a broken socket */
|
||||
signal( SIGPIPE, SIG_IGN );
|
||||
#endif
|
||||
|
||||
/* Initialize rate and file descripts controls */
|
||||
h->upload = tr_rcInit();
|
||||
h->download = tr_rcInit();
|
||||
|
@ -126,6 +164,13 @@ void tr_setBindPort( tr_handle_t * h, int port )
|
|||
tr_sharedSetPort( h->shared, port );
|
||||
}
|
||||
|
||||
int
|
||||
tr_getPublicPort( const tr_handle_t * h )
|
||||
{
|
||||
assert( h != NULL );
|
||||
return tr_sharedGetPublicPort( h->shared );
|
||||
}
|
||||
|
||||
void tr_natTraversalEnable( tr_handle_t * h, int enable )
|
||||
{
|
||||
tr_sharedLock( h->shared );
|
||||
|
@ -133,9 +178,9 @@ void tr_natTraversalEnable( tr_handle_t * h, int enable )
|
|||
tr_sharedUnlock( h->shared );
|
||||
}
|
||||
|
||||
tr_handle_status_t * tr_handleStatus( tr_handle_t * h )
|
||||
tr_handle_status * tr_handleStatus( tr_handle_t * h )
|
||||
{
|
||||
tr_handle_status_t * s;
|
||||
tr_handle_status * s;
|
||||
|
||||
h->statCur = ( h->statCur + 1 ) % 2;
|
||||
s = &h->stats[h->statCur];
|
||||
|
@ -171,10 +216,8 @@ tr_setGlobalSpeedLimit( tr_handle_t * h,
|
|||
{
|
||||
if( up_or_down == TR_DOWN )
|
||||
tr_rcSetLimit( h->download, KiB_sec );
|
||||
else {
|
||||
else
|
||||
tr_rcSetLimit( h->upload, KiB_sec );
|
||||
tr_sharedSetLimit( h->shared, KiB_sec );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -194,18 +237,18 @@ tr_getGlobalSpeedLimit( tr_handle_t * h,
|
|||
|
||||
void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
tr_torrent * tor;
|
||||
|
||||
*dl = 0.0;
|
||||
*ul = 0.0;
|
||||
tr_sharedLock( h->shared );
|
||||
for( tor = h->torrentList; tor; tor = tor->next )
|
||||
{
|
||||
tr_torrentReaderLock( tor );
|
||||
tr_torrentLock( tor );
|
||||
if( tor->cpStatus == TR_CP_INCOMPLETE )
|
||||
*dl += tr_rcRate( tor->download );
|
||||
*ul += tr_rcRate( tor->upload );
|
||||
tr_torrentReaderUnlock( tor );
|
||||
tr_torrentUnlock( tor );
|
||||
}
|
||||
tr_sharedUnlock( h->shared );
|
||||
}
|
||||
|
@ -217,7 +260,7 @@ int tr_torrentCount( tr_handle_t * h )
|
|||
|
||||
void tr_torrentIterate( tr_handle_t * h, tr_callback_t func, void * d )
|
||||
{
|
||||
tr_torrent_t * tor, * next;
|
||||
tr_torrent * tor, * next;
|
||||
|
||||
for( tor = h->torrentList; tor; tor = next )
|
||||
{
|
||||
|
@ -226,21 +269,47 @@ void tr_torrentIterate( tr_handle_t * h, tr_callback_t func, void * d )
|
|||
}
|
||||
}
|
||||
|
||||
void tr_close( tr_handle_t * h )
|
||||
static void
|
||||
tr_closeImpl( void * vh )
|
||||
{
|
||||
tr_handle_t * h = vh;
|
||||
fprintf( stderr, "in tr_closeImpl\n" );
|
||||
tr_peerMgrFree( h->peerMgr );
|
||||
fprintf( stderr, "calling mgr free\n" );
|
||||
|
||||
tr_rcClose( h->upload );
|
||||
tr_rcClose( h->download );
|
||||
|
||||
tr_eventClose( h );
|
||||
|
||||
fprintf( stderr, "calling shared close\n" );
|
||||
tr_sharedClose( h->shared );
|
||||
fprintf( stderr, "calling fd close\n" );
|
||||
tr_fdClose();
|
||||
|
||||
fprintf( stderr, "setting h->closed to TRUE\n" );
|
||||
h->isClosed = TRUE;
|
||||
}
|
||||
void
|
||||
tr_close( tr_handle_t * h )
|
||||
{
|
||||
fprintf( stderr, "torrentCount is %d\n", h->torrentCount );
|
||||
assert( tr_torrentCount( h ) == 0 );
|
||||
|
||||
fprintf( stderr, "here I am in tr_close...\n" );
|
||||
tr_runInEventThread( h, tr_closeImpl, h );
|
||||
while( !h->isClosed )
|
||||
tr_wait( 200 );
|
||||
|
||||
tr_eventClose( h );
|
||||
while( h->events != NULL ) {
|
||||
fprintf( stderr, "waiting for libevent thread to close...\n" );
|
||||
tr_wait( 200 );
|
||||
}
|
||||
|
||||
free( h->tag );
|
||||
free( h );
|
||||
|
||||
tr_netResolveThreadClose();
|
||||
}
|
||||
|
||||
tr_torrent_t **
|
||||
tr_torrent **
|
||||
tr_loadTorrents ( tr_handle_t * h,
|
||||
const char * destination,
|
||||
int flags,
|
||||
|
@ -250,8 +319,8 @@ tr_loadTorrents ( tr_handle_t * h,
|
|||
struct stat sb;
|
||||
DIR * odir = NULL;
|
||||
const char * torrentDir = tr_getTorrentsDirectory( );
|
||||
tr_torrent_t ** torrents;
|
||||
tr_list_t *l=NULL, *list=NULL;
|
||||
tr_torrent ** torrents;
|
||||
tr_list *l=NULL, *list=NULL;
|
||||
|
||||
if( !stat( torrentDir, &sb )
|
||||
&& S_ISDIR( sb.st_mode )
|
||||
|
@ -262,7 +331,7 @@ tr_loadTorrents ( tr_handle_t * h,
|
|||
{
|
||||
if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
|
||||
{
|
||||
tr_torrent_t * tor;
|
||||
tr_torrent * tor;
|
||||
char path[MAX_PATH_LENGTH];
|
||||
tr_buildPath( path, sizeof(path), torrentDir, d->d_name, NULL );
|
||||
tor = tr_torrentInit( h, path, destination, flags, NULL );
|
||||
|
@ -276,9 +345,9 @@ tr_loadTorrents ( tr_handle_t * h,
|
|||
closedir( odir );
|
||||
}
|
||||
|
||||
torrents = tr_new( tr_torrent_t*, n );
|
||||
torrents = tr_new( tr_torrent*, n );
|
||||
for( i=0, l=list; l!=NULL; l=l->next )
|
||||
torrents[i++] = (tr_torrent_t*) l->data;
|
||||
torrents[i++] = (tr_torrent*) l->data;
|
||||
assert( i==n );
|
||||
|
||||
tr_list_free( &list );
|
||||
|
|
|
@ -101,10 +101,29 @@ extern "C" {
|
|||
* deleting a torrent used by another. The following tags are used:
|
||||
* beos cli daemon gtk macosx
|
||||
**********************************************************************/
|
||||
typedef struct tr_handle_s tr_handle_t;
|
||||
tr_handle_t * tr_init( const char * tag );
|
||||
|
||||
typedef struct tr_tracker_info_s tr_tracker_info_t;
|
||||
typedef struct tr_handle tr_handle;
|
||||
typedef struct tr_handle tr_handle_t;
|
||||
|
||||
tr_handle * tr_init( const char * tag );
|
||||
|
||||
typedef struct tr_tracker_info tr_tracker_info;
|
||||
typedef struct tr_tracker_info tr_tracker_info_t;
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_ENCRYPTION_PREFERRED,
|
||||
TR_ENCRYPTION_REQUIRED
|
||||
}
|
||||
tr_encryption_mode;
|
||||
|
||||
tr_encryption_mode tr_getEncryptionMode( tr_handle * handle );
|
||||
|
||||
void tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_setMessageLevel
|
||||
|
@ -122,7 +141,8 @@ int tr_getMessageLevel( void );
|
|||
***********************************************************************
|
||||
* Enable or disable message queuing
|
||||
**********************************************************************/
|
||||
typedef struct tr_msg_list_s tr_msg_list_t;
|
||||
typedef struct tr_msg_list tr_msg_list;
|
||||
typedef struct tr_msg_list tr_msg_list_t;
|
||||
void tr_setMessageQueuing( int );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -130,8 +150,8 @@ void tr_setMessageQueuing( int );
|
|||
***********************************************************************
|
||||
* Return a list of queued messages
|
||||
**********************************************************************/
|
||||
tr_msg_list_t * tr_getQueuedMessages( void );
|
||||
void tr_freeMessageList( tr_msg_list_t * list );
|
||||
tr_msg_list * tr_getQueuedMessages( void );
|
||||
void tr_freeMessageList( tr_msg_list * list );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_getPrefsDirectory
|
||||
|
@ -147,7 +167,9 @@ const char * tr_getPrefsDirectory( void );
|
|||
* Sets the port to listen for incoming peer connections.
|
||||
* This can be safely called even with active torrents.
|
||||
**********************************************************************/
|
||||
void tr_setBindPort( tr_handle_t *, int );
|
||||
void tr_setBindPort( tr_handle *, int );
|
||||
|
||||
int tr_getPublicPort( const tr_handle * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_natTraversalEnable
|
||||
|
@ -155,15 +177,16 @@ void tr_setBindPort( tr_handle_t *, int );
|
|||
***********************************************************************
|
||||
* Enable or disable NAT traversal using NAT-PMP or UPnP IGD.
|
||||
**********************************************************************/
|
||||
void tr_natTraversalEnable( tr_handle_t *, int enable );
|
||||
void tr_natTraversalEnable( tr_handle *, int enable );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_handleStatus
|
||||
***********************************************************************
|
||||
* Returns some status info for the given handle.
|
||||
**********************************************************************/
|
||||
typedef struct tr_handle_status_s tr_handle_status_t;
|
||||
tr_handle_status_t * tr_handleStatus( tr_handle_t * );
|
||||
typedef struct tr_handle_status tr_handle_status;
|
||||
typedef struct tr_handle_status tr_handle_status_t;
|
||||
tr_handle_status * tr_handleStatus( tr_handle * );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -171,7 +194,7 @@ tr_handle_status_t * tr_handleStatus( tr_handle_t * );
|
|||
***********************************************************************
|
||||
* Returns the count of open torrents
|
||||
**********************************************************************/
|
||||
int tr_torrentCount( tr_handle_t * h );
|
||||
int tr_torrentCount( tr_handle * h );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -179,9 +202,10 @@ int tr_torrentCount( tr_handle_t * h );
|
|||
***********************************************************************
|
||||
* Iterates on open torrents
|
||||
**********************************************************************/
|
||||
typedef struct tr_torrent_s tr_torrent_t;
|
||||
typedef void (*tr_callback_t) ( tr_torrent_t *, void * );
|
||||
void tr_torrentIterate( tr_handle_t *, tr_callback_t, void * );
|
||||
typedef struct tr_torrent tr_torrent;
|
||||
typedef struct tr_torrent tr_torrent_t;
|
||||
typedef void (*tr_callback_t) ( tr_torrent *, void * );
|
||||
void tr_torrentIterate( tr_handle *, tr_callback_t, void * );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -196,31 +220,31 @@ typedef enum
|
|||
TR_SPEEDLIMIT_SINGLE, /* only follow the per-torrent limit */
|
||||
TR_SPEEDLIMIT_UNLIMITED /* no limits at all */
|
||||
}
|
||||
tr_speedlimit_t;
|
||||
tr_speedlimit;
|
||||
|
||||
void tr_torrentSetSpeedMode( tr_torrent_t * tor,
|
||||
int up_or_down,
|
||||
tr_speedlimit_t mode );
|
||||
void tr_torrentSetSpeedMode( tr_torrent * tor,
|
||||
int up_or_down,
|
||||
tr_speedlimit mode );
|
||||
|
||||
tr_speedlimit_t tr_torrentGetSpeedMode( const tr_torrent_t * tor,
|
||||
int up_or_down);
|
||||
tr_speedlimit tr_torrentGetSpeedMode( const tr_torrent * tor,
|
||||
int up_or_down);
|
||||
|
||||
void tr_torrentSetSpeedLimit( tr_torrent_t * tor,
|
||||
int up_or_down,
|
||||
int single_KiB_sec );
|
||||
void tr_torrentSetSpeedLimit( tr_torrent * tor,
|
||||
int up_or_down,
|
||||
int single_KiB_sec );
|
||||
|
||||
int tr_torrentGetSpeedLimit( const tr_torrent_t * tor,
|
||||
int up_or_down );
|
||||
int tr_torrentGetSpeedLimit( const tr_torrent * tor,
|
||||
int up_or_down );
|
||||
|
||||
void tr_setUseGlobalSpeedLimit( tr_handle_t * handle,
|
||||
void tr_setUseGlobalSpeedLimit( tr_handle * handle,
|
||||
int up_or_down,
|
||||
int use_flag );
|
||||
|
||||
void tr_setGlobalSpeedLimit( tr_handle_t * handle,
|
||||
void tr_setGlobalSpeedLimit( tr_handle * handle,
|
||||
int up_or_down,
|
||||
int global_KiB_sec );
|
||||
|
||||
void tr_getGlobalSpeedLimit( tr_handle_t * handle,
|
||||
void tr_getGlobalSpeedLimit( tr_handle * handle,
|
||||
int up_or_down,
|
||||
int * setme_is_enabled,
|
||||
int * setme_KiBsec );
|
||||
|
@ -239,50 +263,50 @@ enum
|
|||
typedef int8_t tr_priority_t;
|
||||
|
||||
/* set a batch of files to a particular priority. */
|
||||
void tr_torrentSetFilePriorities( tr_torrent_t * tor,
|
||||
int * files,
|
||||
int fileCount,
|
||||
tr_priority_t priority );
|
||||
void tr_torrentSetFilePriorities( tr_torrent * tor,
|
||||
int * files,
|
||||
int fileCount,
|
||||
tr_priority_t priority );
|
||||
|
||||
|
||||
/* single-file form of tr_torrentPrioritizeFiles.
|
||||
* priority must be one of TR_PRI_NORMAL, _HIGH, or _LOW */
|
||||
void tr_torrentSetFilePriority( tr_torrent_t *, int file, tr_priority_t priority );
|
||||
void tr_torrentSetFilePriority( tr_torrent *, int file, tr_priority_t priority );
|
||||
|
||||
/* returns a malloc()ed array of tor->info.fileCount items,
|
||||
* each holding a value of TR_PRI_NORMAL, _HIGH, or _LOW.
|
||||
free the array when done. */
|
||||
tr_priority_t* tr_torrentGetFilePriorities( const tr_torrent_t * );
|
||||
tr_priority_t* tr_torrentGetFilePriorities( const tr_torrent * );
|
||||
|
||||
/* single-file form of tr_torrentGetFilePriorities.
|
||||
* returns one of TR_PRI_NORMAL, _HIGH, or _LOW. */
|
||||
tr_priority_t tr_torrentGetFilePriority( const tr_torrent_t *, int file );
|
||||
tr_priority_t tr_torrentGetFilePriority( const tr_torrent *, int file );
|
||||
|
||||
/* returns true if the file's `download' flag is set */
|
||||
int tr_torrentGetFileDL( const tr_torrent_t *, int file );
|
||||
int tr_torrentGetFileDL( const tr_torrent *, int file );
|
||||
|
||||
/* set a batch of files to be downloaded or not. */
|
||||
void tr_torrentSetFileDLs ( tr_torrent_t * tor,
|
||||
void tr_torrentSetFileDLs ( tr_torrent * tor,
|
||||
int * files,
|
||||
int fileCount,
|
||||
int do_download );
|
||||
|
||||
/* single-file form of tr_torrentSetFileDLs */
|
||||
void tr_torrentSetFileDL( tr_torrent_t *, int file, int do_download );
|
||||
void tr_torrentSetFileDL( tr_torrent *, int file, int do_download );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentRates
|
||||
***********************************************************************
|
||||
* Gets the total download and upload rates
|
||||
**********************************************************************/
|
||||
void tr_torrentRates( tr_handle_t *, float *, float * );
|
||||
void tr_torrentRates( tr_handle *, float *, float * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_close
|
||||
***********************************************************************
|
||||
* Frees memory allocated by tr_init.
|
||||
**********************************************************************/
|
||||
void tr_close( tr_handle_t * );
|
||||
void tr_close( tr_handle * );
|
||||
|
||||
|
||||
|
||||
|
@ -291,10 +315,10 @@ void tr_close( tr_handle_t * );
|
|||
* This can be used at startup to kickstart all the torrents
|
||||
* from the previous session.
|
||||
*/
|
||||
tr_torrent_t ** tr_loadTorrents ( tr_handle_t * h,
|
||||
const char * destination,
|
||||
int flags,
|
||||
int * setmeCount );
|
||||
tr_torrent ** tr_loadTorrents ( tr_handle * h,
|
||||
const char * destination,
|
||||
int flags,
|
||||
int * setmeCount );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -311,13 +335,14 @@ tr_torrent_t ** tr_loadTorrents ( tr_handle_t * h,
|
|||
#define TR_EUNSUPPORTED 2
|
||||
#define TR_EDUPLICATE 3
|
||||
#define TR_EOTHER 666
|
||||
tr_torrent_t * tr_torrentInit( tr_handle_t * handle,
|
||||
const char * metainfo_filename,
|
||||
const char * destination,
|
||||
int flags,
|
||||
int * setme_error );
|
||||
tr_torrent * tr_torrentInit( tr_handle * handle,
|
||||
const char * metainfo_filename,
|
||||
const char * destination,
|
||||
int flags,
|
||||
int * setme_error );
|
||||
|
||||
typedef struct tr_info_s tr_info_t;
|
||||
typedef struct tr_info tr_info;
|
||||
typedef struct tr_info tr_info_t;
|
||||
|
||||
/**
|
||||
* Parses the specified metainfo file.
|
||||
|
@ -334,20 +359,20 @@ typedef struct tr_info_s tr_info_t;
|
|||
* it will be filled with the metadata's info. You'll need to
|
||||
* call tr_metainfoFree( setme_info ) when done with it.
|
||||
*/
|
||||
int tr_torrentParse( const tr_handle_t * handle,
|
||||
const char * metainfo_filename,
|
||||
const char * destination,
|
||||
tr_info_t * setme_info );
|
||||
int tr_torrentParse( const tr_handle * handle,
|
||||
const char * metainfo_filename,
|
||||
const char * destination,
|
||||
tr_info * setme_info );
|
||||
|
||||
/**
|
||||
* Parses the cached metainfo file that matches the given hash string.
|
||||
* See tr_torrentParse() for a description of the arguments
|
||||
*/
|
||||
int
|
||||
tr_torrentParseHash( const tr_handle_t * h,
|
||||
const char * hashStr,
|
||||
const char * destination,
|
||||
tr_info_t * setme_info );
|
||||
tr_torrentParseHash( const tr_handle * h,
|
||||
const char * hashStr,
|
||||
const char * destination,
|
||||
tr_info * setme_info );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -356,10 +381,10 @@ tr_torrentParseHash( const tr_handle_t * h,
|
|||
* Like tr_torrentInit, except the actual torrent data is passed in
|
||||
* instead of the filename.
|
||||
**********************************************************************/
|
||||
tr_torrent_t * tr_torrentInitData( tr_handle_t *,
|
||||
const uint8_t * data, size_t size,
|
||||
const char * destination,
|
||||
int flags, int * error );
|
||||
tr_torrent * tr_torrentInitData( tr_handle *,
|
||||
const uint8_t * data, size_t size,
|
||||
const char * destination,
|
||||
int flags, int * error );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentInitSaved
|
||||
|
@ -368,10 +393,10 @@ tr_torrent_t * tr_torrentInitData( tr_handle_t *,
|
|||
* the hash string of a saved torrent file instead of a filename. There
|
||||
* are currently no valid flags for this function.
|
||||
**********************************************************************/
|
||||
tr_torrent_t * tr_torrentInitSaved( tr_handle_t *,
|
||||
const char * hashStr,
|
||||
const char * destination,
|
||||
int flags, int * error );
|
||||
tr_torrent * tr_torrentInitSaved( tr_handle *,
|
||||
const char * hashStr,
|
||||
const char * destination,
|
||||
int flags, int * error );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentDisablePex
|
||||
|
@ -380,9 +405,9 @@ tr_torrent_t * tr_torrentInitSaved( tr_handle_t *,
|
|||
* enabled by default, except for private torrents where pex is
|
||||
* disabled and cannot be enabled.
|
||||
**********************************************************************/
|
||||
void tr_torrentDisablePex( tr_torrent_t *, int disable );
|
||||
void tr_torrentDisablePex( tr_torrent *, int disable );
|
||||
|
||||
const tr_info_t * tr_torrentInfo( const tr_torrent_t * );
|
||||
const tr_info * tr_torrentInfo( const tr_torrent * );
|
||||
|
||||
#if 0
|
||||
/***********************************************************************
|
||||
|
@ -394,11 +419,11 @@ const tr_info_t * tr_torrentInfo( const tr_torrent_t * );
|
|||
* replied with some error. tr_torrentScrape may block up to 20 seconds
|
||||
* before returning.
|
||||
**********************************************************************/
|
||||
int tr_torrentScrape( tr_torrent_t *, int * s, int * l, int * d );
|
||||
int tr_torrentScrape( tr_torrent *, int * s, int * l, int * d );
|
||||
#endif
|
||||
|
||||
void tr_torrentSetFolder( tr_torrent_t *, const char * );
|
||||
const char * tr_torrentGetFolder( const tr_torrent_t * );
|
||||
void tr_torrentSetFolder( tr_torrent *, const char * );
|
||||
const char * tr_torrentGetFolder( const tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentStart
|
||||
|
@ -406,7 +431,7 @@ const char * tr_torrentGetFolder( const tr_torrent_t * );
|
|||
* Starts downloading. The download is launched in a seperate thread,
|
||||
* therefore tr_torrentStart returns immediately.
|
||||
**********************************************************************/
|
||||
void tr_torrentStart( tr_torrent_t * );
|
||||
void tr_torrentStart( tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentStop
|
||||
|
@ -419,7 +444,7 @@ void tr_torrentStart( tr_torrent_t * );
|
|||
* - by tr_torrentClose if you choose to remove the torrent without
|
||||
* waiting any further.
|
||||
**********************************************************************/
|
||||
void tr_torrentStop( tr_torrent_t * );
|
||||
void tr_torrentStop( tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_getComplete, tr_getIncomplete and tr_getPartial
|
||||
|
@ -427,9 +452,9 @@ void tr_torrentStop( tr_torrent_t * );
|
|||
* The first call after a torrent changed state returns 1. Returns 0
|
||||
* in other cases.
|
||||
**********************************************************************/
|
||||
int tr_getIncomplete( tr_torrent_t * tor );
|
||||
int tr_getDone( tr_torrent_t * tor );
|
||||
int tr_getComplete( tr_torrent_t * tor );
|
||||
int tr_getIncomplete( tr_torrent * tor );
|
||||
int tr_getDone( tr_torrent * tor );
|
||||
int tr_getComplete( tr_torrent * tor );
|
||||
|
||||
|
||||
/**
|
||||
|
@ -445,33 +470,36 @@ int tr_getComplete( tr_torrent_t * tor );
|
|||
* tr_torrentCanManualUpdate().
|
||||
*/
|
||||
|
||||
void tr_manualUpdate( tr_torrent_t * );
|
||||
void tr_manualUpdate( tr_torrent * );
|
||||
|
||||
int tr_torrentCanManualUpdate( const tr_torrent_t * );
|
||||
int tr_torrentCanManualUpdate( const tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentStat
|
||||
***********************************************************************
|
||||
* Returns a pointer to an tr_stat_t structure with updated information
|
||||
* Returns a pointer to an tr_stat structure with updated information
|
||||
* on the torrent. The structure belongs to libtransmission (do not
|
||||
* free it) and is guaranteed to be unchanged until the next call to
|
||||
* tr_torrentStat.
|
||||
* The interface should call this function every second or so in order
|
||||
* to update itself.
|
||||
**********************************************************************/
|
||||
typedef struct tr_stat_s tr_stat_t;
|
||||
const tr_stat_t * tr_torrentStat( tr_torrent_t * );
|
||||
typedef struct tr_stat tr_stat;
|
||||
typedef struct tr_stat tr_stat_t;
|
||||
const tr_stat * tr_torrentStat( tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentPeers
|
||||
***********************************************************************/
|
||||
typedef struct tr_peer_stat_s tr_peer_stat_t;
|
||||
tr_peer_stat_t * tr_torrentPeers( const tr_torrent_t *, int * peerCount );
|
||||
void tr_torrentPeersFree( tr_peer_stat_t *, int peerCount );
|
||||
typedef struct tr_peer_stat tr_peer_stat;
|
||||
typedef struct tr_peer_stat tr_peer_stat_t;
|
||||
tr_peer_stat * tr_torrentPeers( const tr_torrent *, int * peerCount );
|
||||
void tr_torrentPeersFree( tr_peer_stat *, int peerCount );
|
||||
|
||||
typedef struct tr_file_stat_s tr_file_stat_t;
|
||||
tr_file_stat_t * tr_torrentFiles( const tr_torrent_t *, int * fileCount );
|
||||
void tr_torrentFilesFree( tr_file_stat_t *, int fileCount );
|
||||
typedef struct tr_file_stat tr_file_stat;
|
||||
typedef struct tr_file_stat tr_file_stat_t;
|
||||
tr_file_stat * tr_torrentFiles( const tr_torrent *, int * fileCount );
|
||||
void tr_torrentFilesFree( tr_file_stat *, int fileCount );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -482,9 +510,9 @@ void tr_torrentFilesFree( tr_file_stat_t *, int fileCount );
|
|||
* to either -1 if we have the piece, otherwise it is set to the number
|
||||
* of connected peers who have the piece.
|
||||
**********************************************************************/
|
||||
void tr_torrentAvailability( const tr_torrent_t *, int8_t * tab, int size );
|
||||
void tr_torrentAvailability( const tr_torrent *, int8_t * tab, int size );
|
||||
|
||||
void tr_torrentAmountFinished( const tr_torrent_t * tor, float * tab, int size );
|
||||
void tr_torrentAmountFinished( const tr_torrent * tor, float * tab, int size );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentRemoveSaved
|
||||
|
@ -492,9 +520,9 @@ void tr_torrentAmountFinished( const tr_torrent_t * tor, float * tab, int size )
|
|||
* Removes the saved copy of a torrent file for torrents which the
|
||||
* TR_FLAG_SAVE flag is set.
|
||||
**********************************************************************/
|
||||
void tr_torrentRemoveSaved( tr_torrent_t * );
|
||||
void tr_torrentRemoveSaved( tr_torrent * );
|
||||
|
||||
void tr_torrentRecheck( tr_torrent_t * );
|
||||
void tr_torrentRecheck( tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_torrentClose
|
||||
|
@ -502,13 +530,13 @@ void tr_torrentRecheck( tr_torrent_t * );
|
|||
* Frees memory allocated by tr_torrentInit. If the torrent was running,
|
||||
* it is stopped first.
|
||||
**********************************************************************/
|
||||
void tr_torrentClose( tr_torrent_t * );
|
||||
void tr_torrentClose( tr_torrent * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_info_s
|
||||
* tr_info
|
||||
**********************************************************************/
|
||||
|
||||
typedef struct tr_file_s
|
||||
typedef struct tr_file
|
||||
{
|
||||
uint64_t length; /* Length of the file, in bytes */
|
||||
char name[MAX_PATH_LENGTH]; /* Path to the file */
|
||||
|
@ -518,17 +546,17 @@ typedef struct tr_file_s
|
|||
int lastPiece; /* ...lastPiece] to dl this file */
|
||||
uint64_t offset; /* file begins at the torrent's nth byte */
|
||||
}
|
||||
tr_file_t;
|
||||
tr_file;
|
||||
|
||||
typedef struct tr_piece_s
|
||||
typedef struct tr_piece
|
||||
{
|
||||
uint8_t hash[SHA_DIGEST_LENGTH]; /* pieces hash */
|
||||
int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
|
||||
int8_t dnd; /* nonzero if the piece shouldn't be downloaded */
|
||||
}
|
||||
tr_piece_t;
|
||||
tr_piece;
|
||||
|
||||
struct tr_info_s
|
||||
struct tr_info
|
||||
{
|
||||
/* Path to torrent */
|
||||
char torrent[MAX_PATH_LENGTH];
|
||||
|
@ -547,7 +575,7 @@ struct tr_info_s
|
|||
/* Tracker info */
|
||||
struct
|
||||
{
|
||||
tr_tracker_info_t * list;
|
||||
tr_tracker_info * list;
|
||||
int count;
|
||||
} * trackerList;
|
||||
int trackerTiers;
|
||||
|
@ -562,12 +590,12 @@ struct tr_info_s
|
|||
int pieceSize;
|
||||
int pieceCount;
|
||||
uint64_t totalSize;
|
||||
tr_piece_t * pieces;
|
||||
tr_piece * pieces;
|
||||
|
||||
/* Files info */
|
||||
int multifile;
|
||||
int fileCount;
|
||||
tr_file_t * files;
|
||||
tr_file * files;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
|
@ -598,9 +626,9 @@ typedef enum
|
|||
cp_status_t;
|
||||
|
||||
/***********************************************************************
|
||||
* tr_stat_s
|
||||
* tr_stat
|
||||
**********************************************************************/
|
||||
struct tr_stat_s
|
||||
struct tr_stat
|
||||
{
|
||||
torrent_status_t status;
|
||||
cp_status_t cpStatus;
|
||||
|
@ -608,7 +636,7 @@ struct tr_stat_s
|
|||
int error;
|
||||
char errorString[128];
|
||||
|
||||
const tr_tracker_info_t * tracker;
|
||||
const tr_tracker_info * tracker;
|
||||
|
||||
float recheckProgress;
|
||||
float percentComplete;
|
||||
|
@ -639,38 +667,40 @@ struct tr_stat_s
|
|||
uint64_t activityDate;
|
||||
};
|
||||
|
||||
struct tr_file_stat_s
|
||||
struct tr_file_stat
|
||||
{
|
||||
uint64_t bytesCompleted;
|
||||
float progress;
|
||||
cp_status_t completionStatus;
|
||||
};
|
||||
|
||||
struct tr_peer_stat_s
|
||||
struct tr_peer_stat
|
||||
{
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
const char * client;
|
||||
|
||||
int isConnected;
|
||||
int from;
|
||||
float progress;
|
||||
int port;
|
||||
unsigned int isConnected : 1;
|
||||
unsigned int isEncrypted : 1;
|
||||
unsigned int isDownloading : 1;
|
||||
unsigned int isUploading : 1;
|
||||
|
||||
uint8_t from;
|
||||
uint16_t port;
|
||||
|
||||
int isDownloading;
|
||||
int isUploading;
|
||||
float downloadFromRate;
|
||||
float uploadToRate;
|
||||
float progress;
|
||||
float downloadFromRate;
|
||||
float uploadToRate;
|
||||
};
|
||||
|
||||
struct tr_msg_list_s
|
||||
struct tr_msg_list
|
||||
{
|
||||
int level;
|
||||
time_t when;
|
||||
char * message;
|
||||
struct tr_msg_list_s * next;
|
||||
int level;
|
||||
time_t when;
|
||||
char * message;
|
||||
struct tr_msg_list * next;
|
||||
};
|
||||
|
||||
struct tr_tracker_info_s
|
||||
struct tr_tracker_info
|
||||
{
|
||||
char * address;
|
||||
int port;
|
||||
|
@ -678,7 +708,7 @@ struct tr_tracker_info_s
|
|||
char * scrape;
|
||||
};
|
||||
|
||||
struct tr_handle_status_s
|
||||
struct tr_handle_status
|
||||
{
|
||||
#define TR_NAT_TRAVERSAL_MAPPING 1
|
||||
#define TR_NAT_TRAVERSAL_MAPPED 2
|
||||
|
|
|
@ -16,21 +16,18 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/queue.h> /* for evhttp */
|
||||
#include <sys/types.h> /* for evhttp */
|
||||
|
||||
#ifdef WIN32
|
||||
#include <fcntl.h>
|
||||
#define pipe(f) _pipe(f, 1000, _O_BINARY)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <event.h>
|
||||
#include <evdns.h>
|
||||
#include <evhttp.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "list.h"
|
||||
#include "platform.h"
|
||||
#include "trevent.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* #define DEBUG */
|
||||
|
@ -44,96 +41,137 @@
|
|||
****
|
||||
***/
|
||||
|
||||
typedef struct tr_event_handle_s
|
||||
typedef struct tr_event_handle
|
||||
{
|
||||
int fds[2];
|
||||
tr_lock_t * lock;
|
||||
tr_lock * lock;
|
||||
tr_handle_t * h;
|
||||
tr_thread_t * thread;
|
||||
tr_thread * thread;
|
||||
tr_list * commands;
|
||||
struct event_base * base;
|
||||
struct event pipeEvent;
|
||||
struct event pulse;
|
||||
struct timeval pulseInterval;
|
||||
uint8_t die;
|
||||
|
||||
int timerCount;
|
||||
}
|
||||
tr_event_handle_t;
|
||||
tr_event_handle;
|
||||
|
||||
#ifdef DEBUG
|
||||
static int reads = 0;
|
||||
static int writes = 0;
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
readFromPipe( int fd, short eventType UNUSED, void * unused UNUSED )
|
||||
enum mode
|
||||
{
|
||||
char ch;
|
||||
int ret;
|
||||
struct event * event;
|
||||
struct timeval interval;
|
||||
TR_EV_EVHTTP_MAKE_REQUEST,
|
||||
TR_EV_BUFFEREVENT_SET,
|
||||
TR_EV_BUFFEREVENT_WRITE,
|
||||
TR_EV_BUFFEREVENT_FREE,
|
||||
TR_EV_TIMER_ADD,
|
||||
TR_EV_TIMER_DEL,
|
||||
TR_EV_EXEC
|
||||
};
|
||||
|
||||
typedef int timer_func(void*);
|
||||
|
||||
struct tr_timer
|
||||
{
|
||||
struct event event;
|
||||
struct timeval tv;
|
||||
timer_func * func;
|
||||
void * user_data;
|
||||
struct tr_event_handle * eh;
|
||||
uint8_t inCallback;
|
||||
};
|
||||
|
||||
struct tr_event_command
|
||||
{
|
||||
int mode;
|
||||
|
||||
struct tr_timer * timer;
|
||||
|
||||
struct evhttp_connection * evcon;
|
||||
struct evhttp_request * req;
|
||||
enum evhttp_cmd_type type;
|
||||
enum evhttp_cmd_type evtype;
|
||||
char * uri;
|
||||
|
||||
struct bufferevent * bufev;
|
||||
short enable;
|
||||
short disable;
|
||||
char * buf;
|
||||
size_t buflen;
|
||||
struct bufferevent * bufev;
|
||||
short mode;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf( stderr, "reading...reads: [%d] writes: [%d]\n", ++reads, writes );
|
||||
#endif
|
||||
void (*func)( void* );
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
ch = '\0';
|
||||
do {
|
||||
ret = read( fd, &ch, 1 );
|
||||
} while ( ret<0 && errno==EAGAIN );
|
||||
static void
|
||||
pumpList( int i UNUSED, short s UNUSED, void * veh )
|
||||
{
|
||||
tr_event_handle * eh = veh;
|
||||
|
||||
if( ret < 0 )
|
||||
while( !eh->die )
|
||||
{
|
||||
tr_err( "Couldn't read from libevent pipe: %s", strerror(errno) );
|
||||
struct tr_event_command * cmd;
|
||||
|
||||
/* get the next command */
|
||||
tr_lockLock( eh->lock );
|
||||
cmd = tr_list_pop_front( &eh->commands );
|
||||
tr_lockUnlock( eh->lock );
|
||||
if( cmd == NULL )
|
||||
break;
|
||||
|
||||
/* process the command */
|
||||
switch( cmd->mode )
|
||||
{
|
||||
case TR_EV_TIMER_ADD:
|
||||
timeout_add( &cmd->timer->event, &cmd->timer->tv );
|
||||
++eh->timerCount;
|
||||
break;
|
||||
|
||||
case TR_EV_TIMER_DEL:
|
||||
event_del( &cmd->timer->event );
|
||||
tr_free( cmd->timer );
|
||||
--eh->timerCount;
|
||||
break;
|
||||
|
||||
case TR_EV_EVHTTP_MAKE_REQUEST:
|
||||
evhttp_make_request( cmd->evcon, cmd->req, cmd->evtype, cmd->uri );
|
||||
tr_free( cmd->uri );
|
||||
break;
|
||||
|
||||
case TR_EV_BUFFEREVENT_SET:
|
||||
bufferevent_enable( cmd->bufev, cmd->enable );
|
||||
bufferevent_disable( cmd->bufev, cmd->disable );
|
||||
break;
|
||||
|
||||
case TR_EV_BUFFEREVENT_WRITE:
|
||||
bufferevent_write( cmd->bufev, cmd->buf, cmd->buflen );
|
||||
tr_free( cmd->buf );
|
||||
break;
|
||||
|
||||
case TR_EV_BUFFEREVENT_FREE:
|
||||
bufferevent_free( cmd->bufev );
|
||||
break;
|
||||
|
||||
case TR_EV_EXEC:
|
||||
(cmd->func)( cmd->user_data );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 && "unhandled command type!" );
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
tr_free( cmd );
|
||||
}
|
||||
else switch( ch )
|
||||
{
|
||||
case 'd': /* event_del */
|
||||
read( fd, &event, sizeof(struct event*) );
|
||||
event_del( event );
|
||||
tr_free( event );
|
||||
break;
|
||||
|
||||
case 'e': /* event_add */
|
||||
read( fd, &event, sizeof(struct event*) );
|
||||
read( fd, &interval, sizeof(struct timeval) );
|
||||
event_add( event, &interval );
|
||||
break;
|
||||
|
||||
case 'h': /* http_make_request */
|
||||
ret = read( fd, &evcon, sizeof(struct evhttp_connection*) );
|
||||
read( fd, &req, sizeof(struct evhttp_request*) );
|
||||
read( fd, &type, sizeof(enum evhttp_cmd_type) );
|
||||
read( fd, &uri, sizeof(char*) );
|
||||
evhttp_make_request( evcon, req, type, uri );
|
||||
tr_free( uri );
|
||||
break;
|
||||
|
||||
case 'm': /* set bufferevent mode */
|
||||
read( fd, &bufev, sizeof(struct evhttp_request*) );
|
||||
mode = 0;
|
||||
read( fd, &mode, sizeof(short) );
|
||||
bufferevent_enable( bufev, mode );
|
||||
mode = 0;
|
||||
read( fd, &mode, sizeof(short) );
|
||||
bufferevent_disable( bufev, mode );
|
||||
fprintf( stderr, "after enable/disable, the mode is %hd\n", bufev->enabled );
|
||||
break;
|
||||
|
||||
case 'w': /* bufferevent_write */
|
||||
read( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
read( fd, &buf, sizeof(char*) );
|
||||
read( fd, &buflen, sizeof(size_t) );
|
||||
bufferevent_write( bufev, buf, buflen );
|
||||
tr_free( buf );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 && "unhandled event pipe condition!" );
|
||||
if( !eh->die )
|
||||
timeout_add( &eh->pulse, &eh->pulseInterval );
|
||||
else {
|
||||
assert( eh->timerCount == 0 );
|
||||
evdns_shutdown( FALSE );
|
||||
event_del( &eh->pulse );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,92 +195,69 @@ logFunc( int severity, const char * message )
|
|||
static void
|
||||
libeventThreadFunc( void * veh )
|
||||
{
|
||||
tr_event_handle_t * eh = (tr_event_handle_t *) veh;
|
||||
tr_event_handle * eh = (tr_event_handle *) veh;
|
||||
tr_dbg( "Starting libevent thread" );
|
||||
|
||||
eh->base = event_init( );
|
||||
event_set_log_callback( logFunc );
|
||||
#ifndef WIN32
|
||||
/* Don't exit when writing on a broken socket */
|
||||
signal( SIGPIPE, SIG_IGN );
|
||||
#endif
|
||||
|
||||
/* listen to the pipe's read fd */
|
||||
event_set( &eh->pipeEvent, eh->fds[0], EV_READ|EV_PERSIST, readFromPipe, NULL );
|
||||
event_add( &eh->pipeEvent, NULL );
|
||||
eh->base = event_init( );
|
||||
//event_set_log_callback( logFunc );
|
||||
evdns_init( );
|
||||
timeout_set( &eh->pulse, pumpList, veh );
|
||||
timeout_add( &eh->pulse, &eh->pulseInterval );
|
||||
eh->h->events = eh;
|
||||
|
||||
event_dispatch( );
|
||||
fprintf( stderr, "w00t!!!!!!!!!!!!!!!!!!!\n" );
|
||||
|
||||
event_del( &eh->pipeEvent );
|
||||
tr_lockFree( eh->lock );
|
||||
event_base_free( eh->base );
|
||||
tr_free( eh );
|
||||
|
||||
eh->h->events = NULL;
|
||||
|
||||
tr_free( eh );
|
||||
tr_dbg( "Closing libevent thread" );
|
||||
}
|
||||
|
||||
void
|
||||
tr_eventInit( tr_handle_t * handle )
|
||||
{
|
||||
tr_event_handle_t * eh;
|
||||
tr_event_handle * eh;
|
||||
|
||||
eh = tr_new0( tr_event_handle_t, 1 );
|
||||
eh = tr_new0( tr_event_handle, 1 );
|
||||
eh->lock = tr_lockNew( );
|
||||
pipe( eh->fds );
|
||||
eh->h = handle;
|
||||
handle->events = eh;
|
||||
eh->pulseInterval = timevalMsec( 20 );
|
||||
eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
|
||||
}
|
||||
|
||||
void
|
||||
tr_eventClose( tr_handle_t * handle )
|
||||
{
|
||||
tr_event_handle_t * eh = handle->events;
|
||||
tr_event_handle * eh = handle->events;
|
||||
|
||||
event_base_loopexit( eh->base, NULL );
|
||||
tr_lockLock( eh->lock );
|
||||
tr_list_foreach( eh->commands, tr_free );
|
||||
tr_list_free( &eh->commands );
|
||||
eh->die = TRUE;
|
||||
tr_lockUnlock( eh->lock );
|
||||
|
||||
//event_base_loopexit( eh->base, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
tr_event_add( tr_handle_t * handle,
|
||||
struct event * event,
|
||||
struct timeval * interval )
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
pushList( struct tr_event_handle * eh, struct tr_event_command * command )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
event_add( event, interval );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'e';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: event.ev_arg is %p", event->ev_arg );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
write( fd, interval, sizeof(struct timeval) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_event_del( tr_handle_t * handle,
|
||||
struct event * event )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
event_del( event );
|
||||
tr_free( event );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'd';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing event to pipe: del event %p", event );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &event, sizeof(struct event*) );
|
||||
tr_lockUnlock( lock );
|
||||
}
|
||||
tr_lockLock( eh->lock );
|
||||
tr_list_append( &eh->commands, command );
|
||||
tr_lockUnlock( eh->lock );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -252,25 +267,17 @@ tr_evhttp_make_request (tr_handle_t * handle,
|
|||
enum evhttp_cmd_type type,
|
||||
char * uri)
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) ) {
|
||||
evhttp_make_request( evcon, req, type, uri );
|
||||
tr_free( uri );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'h';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing HTTP req to pipe: req.cb_arg is %p", req->cb_arg );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &evcon, sizeof(struct evhttp_connection*) );
|
||||
write( fd, &req, sizeof(struct evhttp_request*) );
|
||||
write( fd, &type, sizeof(enum evhttp_cmd_type) );
|
||||
write( fd, &uri, sizeof(char*) );
|
||||
tr_lockUnlock( lock );
|
||||
} else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_EVHTTP_MAKE_REQUEST;
|
||||
cmd->evcon = evcon;
|
||||
cmd->req = req;
|
||||
cmd->evtype = type;
|
||||
cmd->uri = uri;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,48 +288,170 @@ tr_bufferevent_write( tr_handle_t * handle,
|
|||
size_t buflen )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
bufferevent_write( bufev, (void*)buf, buflen );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'w';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
char * local = tr_strndup( buf, buflen );
|
||||
|
||||
tr_lockLock( lock );
|
||||
tr_dbg( "writing bufferevent_write pipe" );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
write( fd, &local, sizeof(char*) );
|
||||
write( fd, &buflen, sizeof(size_t) );
|
||||
tr_lockUnlock( lock );
|
||||
else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_BUFFEREVENT_WRITE;
|
||||
cmd->bufev = bufev;
|
||||
cmd->buf = tr_strndup( buf, buflen );
|
||||
cmd->buflen = buflen;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tr_setBufferEventMode( struct tr_handle_s * handle,
|
||||
tr_setBufferEventMode( struct tr_handle * handle,
|
||||
struct bufferevent * bufev,
|
||||
short mode_enable,
|
||||
short mode_disable )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) ) {
|
||||
bufferevent_enable( bufev, mode_enable );
|
||||
bufferevent_disable( bufev, mode_disable );
|
||||
}
|
||||
else
|
||||
{
|
||||
const char ch = 'm';
|
||||
int fd = handle->events->fds[1];
|
||||
tr_lock_t * lock = handle->events->lock;
|
||||
|
||||
tr_lockLock( lock );
|
||||
write( fd, &ch, 1 );
|
||||
write( fd, &bufev, sizeof(struct bufferevent*) );
|
||||
write( fd, &mode_enable, sizeof(short) );
|
||||
write( fd, &mode_disable, sizeof(short) );
|
||||
tr_lockUnlock( lock );
|
||||
} else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_BUFFEREVENT_SET;
|
||||
cmd->bufev = bufev;
|
||||
cmd->enable = mode_enable;
|
||||
cmd->disable = mode_disable;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static int
|
||||
timerCompareFunc( const void * va, const void * vb )
|
||||
{
|
||||
const struct tr_event_command * a = va;
|
||||
const struct tr_timer * b = vb;
|
||||
return a->timer == b ? 0 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
timerCallback( int fd UNUSED, short event UNUSED, void * vtimer )
|
||||
{
|
||||
int more;
|
||||
struct tr_timer * timer = vtimer;
|
||||
void * del;
|
||||
|
||||
del = tr_list_remove( &timer->eh->commands, timer, timerCompareFunc );
|
||||
|
||||
if( del != NULL ) /* there's a TIMER_DEL command queued for this timer... */
|
||||
more = FALSE;
|
||||
else {
|
||||
timer->inCallback = 1;
|
||||
more = (*timer->func)( timer->user_data );
|
||||
timer->inCallback = 0;
|
||||
}
|
||||
|
||||
if( more )
|
||||
timeout_add( &timer->event, &timer->tv );
|
||||
else
|
||||
tr_timerFree( &timer );
|
||||
}
|
||||
|
||||
void
|
||||
tr_timerFree( tr_timer ** ptimer )
|
||||
{
|
||||
tr_timer * timer;
|
||||
|
||||
/* zero out the argument passed in */
|
||||
assert( ptimer );
|
||||
timer = *ptimer;
|
||||
*ptimer = NULL;
|
||||
|
||||
/* destroy the timer directly or via the command queue */
|
||||
if( timer!=NULL && !timer->inCallback ) {
|
||||
if( tr_amInThread( timer->eh->thread ) ) {
|
||||
--timer->eh->timerCount;
|
||||
event_del( &timer->event );
|
||||
tr_free( timer );
|
||||
} else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_TIMER_DEL;
|
||||
cmd->timer = timer;
|
||||
pushList( timer->eh, cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr_timer*
|
||||
tr_timerNew( struct tr_handle * handle,
|
||||
timer_func func,
|
||||
void * user_data,
|
||||
int timeout_milliseconds )
|
||||
{
|
||||
tr_timer * timer = tr_new0( tr_timer, 1 );
|
||||
timer->tv = timevalMsec( timeout_milliseconds );
|
||||
timer->func = func;
|
||||
timer->user_data = user_data;
|
||||
timer->eh = handle->events;
|
||||
timeout_set( &timer->event, timerCallback, timer );
|
||||
|
||||
if( tr_amInThread( handle->events->thread ) ) {
|
||||
timeout_add( &timer->event, &timer->tv );
|
||||
++handle->events->timerCount;
|
||||
} else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_TIMER_ADD;
|
||||
cmd->timer = timer;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
void
|
||||
tr_runInEventThread( struct tr_handle * handle,
|
||||
void func( void* ),
|
||||
void * user_data )
|
||||
{
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
(func)( user_data );
|
||||
else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_EXEC;
|
||||
cmd->func = func;
|
||||
cmd->user_data = user_data;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static int
|
||||
bufCompareFunc( const void * va, const void * vb )
|
||||
{
|
||||
const struct tr_event_command * a = va;
|
||||
const struct bufferevent * b = vb;
|
||||
return a->bufev == b ? 0 : 1;
|
||||
}
|
||||
|
||||
void
|
||||
tr_bufferevent_free( struct tr_handle * handle,
|
||||
struct bufferevent * bufev )
|
||||
{
|
||||
void * v;
|
||||
tr_event_handle * eh = handle->events;
|
||||
|
||||
/* purge pending commands from the list */
|
||||
tr_lockLock( eh->lock );
|
||||
while(( v = tr_list_remove( &eh->commands, bufev, bufCompareFunc ) ))
|
||||
tr_free( v );
|
||||
tr_lockUnlock( eh->lock );
|
||||
|
||||
if( tr_amInThread( handle->events->thread ) )
|
||||
bufferevent_free( bufev );
|
||||
else {
|
||||
struct tr_event_command * cmd = tr_new0( struct tr_event_command, 1 );
|
||||
cmd->mode = TR_EV_BUFFEREVENT_FREE;
|
||||
cmd->bufev = bufev;
|
||||
pushList( handle->events, cmd );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
/**
|
||||
**/
|
||||
|
||||
void tr_eventInit( struct tr_handle_s * tr_handle );
|
||||
void tr_eventInit( struct tr_handle * tr_handle );
|
||||
|
||||
void tr_eventClose( struct tr_handle_s * tr_handle );
|
||||
void tr_eventClose( struct tr_handle * tr_handle );
|
||||
|
||||
/**
|
||||
**/
|
||||
|
@ -30,27 +30,49 @@ struct evhttp_request;
|
|||
struct evhttp_connection;
|
||||
struct bufferevent;
|
||||
|
||||
void tr_event_add( struct tr_handle_s * tr_handle,
|
||||
struct event * event,
|
||||
struct timeval * interval );
|
||||
|
||||
void tr_event_del( struct tr_handle_s * tr_handle,
|
||||
struct event * event );
|
||||
|
||||
void tr_evhttp_make_request (struct tr_handle_s * tr_handle,
|
||||
void tr_evhttp_make_request (struct tr_handle * tr_handle,
|
||||
struct evhttp_connection * evcon,
|
||||
struct evhttp_request * req,
|
||||
enum evhttp_cmd_type type,
|
||||
char * uri);
|
||||
|
||||
void tr_bufferevent_write( struct tr_handle_s * tr_handle,
|
||||
void tr_bufferevent_write( struct tr_handle * tr_handle,
|
||||
struct bufferevent * bufferEvent,
|
||||
const void * buf,
|
||||
size_t buflen );
|
||||
|
||||
void tr_setBufferEventMode( struct tr_handle_s * tr_handle,
|
||||
void tr_bufferevent_free( struct tr_handle * handle,
|
||||
struct bufferevent * bufev );
|
||||
|
||||
|
||||
void tr_setBufferEventMode( struct tr_handle * tr_handle,
|
||||
struct bufferevent * bufferEvent,
|
||||
short mode_enable,
|
||||
short mode_disable );
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
typedef struct tr_timer tr_timer;
|
||||
|
||||
/**
|
||||
* Calls timer_func(user_data) after the specified interval.
|
||||
* The timer is freed if timer_func returns zero.
|
||||
* Otherwise, it's called again after the same interval.
|
||||
*/
|
||||
tr_timer* tr_timerNew( struct tr_handle * handle,
|
||||
int func( void * user_data ),
|
||||
void * user_data,
|
||||
int timeout_milliseconds );
|
||||
|
||||
/**
|
||||
* Frees a timer and sets the timer pointer to NULL.
|
||||
*/
|
||||
void tr_timerFree( tr_timer ** timer );
|
||||
|
||||
void tr_runInEventThread( struct tr_handle * handle,
|
||||
void func( void* ),
|
||||
void * user_data );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -210,6 +210,7 @@ tr_upnpInit( void )
|
|||
vlog = fopen( path, "a" );
|
||||
stupid_api = time( NULL );
|
||||
fprintf( vlog, "opened log at %s\n\n", ctime( &stupid_api ) );
|
||||
fflush( vlog );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -306,10 +307,9 @@ tr_upnpClose( tr_upnp_t * upnp )
|
|||
#ifdef VERBOSE_LOG
|
||||
if( NULL != vlog )
|
||||
{
|
||||
fflush( vlog );
|
||||
fclose( vlog );
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -403,6 +403,7 @@ sendSSDP( int fd )
|
|||
fprintf( vlog, "send ssdp message, %i bytes:\n", len );
|
||||
fwrite( buf, 1, len, vlog );
|
||||
fputs( "\n\n", vlog );
|
||||
fflush( vlog );
|
||||
#endif
|
||||
|
||||
if( 0 > sendto( fd, buf, len, 0,
|
||||
|
@ -524,6 +525,7 @@ recvSSDP( int fd, char * buf, int * len )
|
|||
fprintf( vlog, "receive ssdp message, %i bytes:\n", *len );
|
||||
fwrite( buf, 1, *len, vlog );
|
||||
fputs( "\n\n", vlog );
|
||||
fflush( vlog );
|
||||
#endif
|
||||
return TR_NET_OK;
|
||||
}
|
||||
|
@ -964,6 +966,7 @@ devicePulseGetHttp( struct upnp_dev * dev )
|
|||
fprintf( vlog, "\n\nsend http message, %i bytes (body):\n", len );
|
||||
fwrite( body, 1, len, vlog );
|
||||
fputs( "\n\n", vlog );
|
||||
fflush( vlog );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1007,6 +1010,7 @@ devicePulseHttp( struct upnp_dev * dev,
|
|||
fprintf( vlog, "receive http message, %i bytes:\n", hlen );
|
||||
fwrite( headers, 1, hlen, vlog );
|
||||
fputs( "\n\n", vlog );
|
||||
fflush( vlog );
|
||||
#endif
|
||||
code = tr_httpResponseCode( headers, hlen );
|
||||
if( SOAP_METHOD_NOT_ALLOWED == code && !dev->soapretry )
|
||||
|
|
|
@ -49,11 +49,11 @@
|
|||
|
||||
#define SPRINTF_BUFSIZE 100
|
||||
|
||||
static tr_lock_t * messageLock = NULL;
|
||||
static int messageLevel = 0;
|
||||
static int messageQueuing = FALSE;
|
||||
static tr_msg_list_t * messageQueue = NULL;
|
||||
static tr_msg_list_t ** messageQueueTail = &messageQueue;
|
||||
static tr_lock * messageLock = NULL;
|
||||
static int messageLevel = 0;
|
||||
static int messageQueuing = FALSE;
|
||||
static tr_msg_list * messageQueue = NULL;
|
||||
static tr_msg_list ** messageQueueTail = &messageQueue;
|
||||
|
||||
void tr_msgInit( void )
|
||||
{
|
||||
|
@ -89,9 +89,9 @@ void tr_setMessageQueuing( int enabled )
|
|||
tr_lockUnlock( messageLock );
|
||||
}
|
||||
|
||||
tr_msg_list_t * tr_getQueuedMessages( void )
|
||||
tr_msg_list * tr_getQueuedMessages( void )
|
||||
{
|
||||
tr_msg_list_t * ret;
|
||||
tr_msg_list * ret;
|
||||
|
||||
assert( NULL != messageLock );
|
||||
tr_lockLock( messageLock );
|
||||
|
@ -103,9 +103,9 @@ tr_msg_list_t * tr_getQueuedMessages( void )
|
|||
return ret;
|
||||
}
|
||||
|
||||
void tr_freeMessageList( tr_msg_list_t * list )
|
||||
void tr_freeMessageList( tr_msg_list * list )
|
||||
{
|
||||
tr_msg_list_t * next;
|
||||
tr_msg_list * next;
|
||||
|
||||
while( NULL != list )
|
||||
{
|
||||
|
@ -118,8 +118,8 @@ void tr_freeMessageList( tr_msg_list_t * list )
|
|||
|
||||
void tr_msg( int level, char * msg, ... )
|
||||
{
|
||||
va_list args1, args2;
|
||||
tr_msg_list_t * newmsg;
|
||||
va_list args1, args2;
|
||||
tr_msg_list * newmsg;
|
||||
int len1, len2;
|
||||
|
||||
assert( NULL != messageLock );
|
||||
|
@ -185,6 +185,65 @@ int tr_rand( int sup )
|
|||
return rand() % sup;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
void
|
||||
tr_set_compare( const void * va, size_t aCount,
|
||||
const void * vb, size_t bCount,
|
||||
int compare( const void * a, const void * b ),
|
||||
size_t elementSize,
|
||||
tr_set_func in_a_cb,
|
||||
tr_set_func in_b_cb,
|
||||
tr_set_func in_both_cb,
|
||||
void * userData )
|
||||
{
|
||||
const uint8_t * a = (const uint8_t *) va;
|
||||
const uint8_t * b = (const uint8_t *) vb;
|
||||
const uint8_t * aend = a + elementSize*aCount;
|
||||
const uint8_t * bend = b + elementSize*bCount;
|
||||
|
||||
while( a!=aend || b!=bend )
|
||||
{
|
||||
if( a==aend )
|
||||
{
|
||||
(*in_b_cb)( (void*)b, userData );
|
||||
b += elementSize;
|
||||
}
|
||||
else if ( b==bend )
|
||||
{
|
||||
(*in_a_cb)( (void*)a, userData );
|
||||
a += elementSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int val = (*compare)( a, b );
|
||||
|
||||
if( !val )
|
||||
{
|
||||
(*in_both_cb)( (void*)a, userData );
|
||||
a += elementSize;
|
||||
b += elementSize;
|
||||
}
|
||||
else if( val < 0 )
|
||||
{
|
||||
(*in_a_cb)( (void*)a, userData );
|
||||
a += elementSize;
|
||||
}
|
||||
else if( val > 0 )
|
||||
{
|
||||
(*in_b_cb)( (void*)b, userData );
|
||||
b += elementSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
|
||||
#if 0
|
||||
void*
|
||||
|
@ -237,6 +296,46 @@ void * tr_memmem ( const void *vbig, size_t big_len,
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
int
|
||||
tr_compareUint8 ( uint8_t a, uint8_t b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_compareUint16( uint16_t a, uint16_t b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_compareUint32( uint32_t a, uint32_t b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_compareUint64( uint64_t a, uint64_t b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
struct timeval
|
||||
timevalSec ( int seconds )
|
||||
{
|
||||
|
@ -566,14 +665,14 @@ void tr_free( void * p )
|
|||
****/
|
||||
|
||||
/* note that the argument is how many bits are needed, not bytes */
|
||||
tr_bitfield_t*
|
||||
tr_bitfield*
|
||||
tr_bitfieldNew( size_t bitcount )
|
||||
{
|
||||
tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
|
||||
tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
|
||||
if( NULL == ret )
|
||||
return NULL;
|
||||
|
||||
ret->len = ( bitcount + 7u ) / 8u;
|
||||
ret->len = (bitcount+7u) / 8u;
|
||||
ret->bits = calloc( ret->len, 1 );
|
||||
if( NULL == ret->bits ) {
|
||||
free( ret );
|
||||
|
@ -583,17 +682,17 @@ tr_bitfieldNew( size_t bitcount )
|
|||
return ret;
|
||||
}
|
||||
|
||||
tr_bitfield_t*
|
||||
tr_bitfieldDup( const tr_bitfield_t * in )
|
||||
tr_bitfield*
|
||||
tr_bitfieldDup( const tr_bitfield * in )
|
||||
{
|
||||
tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
|
||||
tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
|
||||
ret->len = in->len;
|
||||
ret->bits = malloc( ret->len );
|
||||
memcpy( ret->bits, in->bits, ret->len );
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tr_bitfieldFree( tr_bitfield_t * bitfield )
|
||||
void tr_bitfieldFree( tr_bitfield * bitfield )
|
||||
{
|
||||
if( bitfield )
|
||||
{
|
||||
|
@ -603,13 +702,13 @@ void tr_bitfieldFree( tr_bitfield_t * bitfield )
|
|||
}
|
||||
|
||||
void
|
||||
tr_bitfieldClear( tr_bitfield_t * bitfield )
|
||||
tr_bitfieldClear( tr_bitfield * bitfield )
|
||||
{
|
||||
memset( bitfield->bits, 0, bitfield->len );
|
||||
}
|
||||
|
||||
int
|
||||
tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
|
||||
tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -624,7 +723,7 @@ tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
|
|||
#define BIT(nth) (1<<(7-(nth%8)))
|
||||
|
||||
void
|
||||
tr_bitfieldAdd( tr_bitfield_t * bitfield, size_t nth )
|
||||
tr_bitfieldAdd( tr_bitfield * bitfield, size_t nth )
|
||||
{
|
||||
assert( bitfield != NULL );
|
||||
assert( BIN(nth) < bitfield->len );
|
||||
|
@ -632,9 +731,9 @@ tr_bitfieldAdd( tr_bitfield_t * bitfield, size_t nth )
|
|||
}
|
||||
|
||||
void
|
||||
tr_bitfieldAddRange( tr_bitfield_t * bitfield,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
tr_bitfieldAddRange( tr_bitfield * bitfield,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
{
|
||||
/* TODO: there are faster ways to do this */
|
||||
unsigned int i;
|
||||
|
@ -643,8 +742,8 @@ tr_bitfieldAddRange( tr_bitfield_t * bitfield,
|
|||
}
|
||||
|
||||
void
|
||||
tr_bitfieldRem( tr_bitfield_t * bitfield,
|
||||
size_t nth )
|
||||
tr_bitfieldRem( tr_bitfield * bitfield,
|
||||
size_t nth )
|
||||
{
|
||||
if( bitfield != NULL )
|
||||
{
|
||||
|
@ -655,9 +754,9 @@ tr_bitfieldRem( tr_bitfield_t * bitfield,
|
|||
}
|
||||
|
||||
void
|
||||
tr_bitfieldRemRange ( tr_bitfield_t * b,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
tr_bitfieldRemRange ( tr_bitfield * b,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
{
|
||||
/* TODO: there are faster ways to do this */
|
||||
unsigned int i;
|
||||
|
@ -665,8 +764,8 @@ tr_bitfieldRemRange ( tr_bitfield_t * b,
|
|||
tr_bitfieldRem( b, i );
|
||||
}
|
||||
|
||||
tr_bitfield_t*
|
||||
tr_bitfieldNegate( tr_bitfield_t * b )
|
||||
tr_bitfield*
|
||||
tr_bitfieldNegate( tr_bitfield * b )
|
||||
{
|
||||
uint8_t *it;
|
||||
const uint8_t *end;
|
||||
|
@ -677,8 +776,8 @@ tr_bitfieldNegate( tr_bitfield_t * b )
|
|||
return b;
|
||||
}
|
||||
|
||||
tr_bitfield_t*
|
||||
tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
|
||||
tr_bitfield*
|
||||
tr_bitfieldAnd( tr_bitfield * a, const tr_bitfield * b )
|
||||
{
|
||||
uint8_t *ait;
|
||||
const uint8_t *aend, *bit;
|
||||
|
@ -692,7 +791,7 @@ tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
|
|||
}
|
||||
|
||||
size_t
|
||||
tr_bitfieldCountTrueBits( const tr_bitfield_t* b )
|
||||
tr_bitfieldCountTrueBits( const tr_bitfield* b )
|
||||
{
|
||||
size_t ret = 0;
|
||||
const uint8_t *it, *end;
|
||||
|
|
|
@ -138,28 +138,50 @@ char* tr_strndup( const char * str, int len );
|
|||
****
|
||||
***/
|
||||
|
||||
typedef struct tr_bitfield_s
|
||||
typedef void (tr_set_func)(void * element, void * userData );
|
||||
|
||||
void tr_set_compare( const void * a, size_t aCount,
|
||||
const void * b, size_t bCount,
|
||||
int compare( const void * a, const void * b ),
|
||||
size_t elementSize,
|
||||
tr_set_func in_a_cb,
|
||||
tr_set_func in_b_cb,
|
||||
tr_set_func in_both_cb,
|
||||
void * userData );
|
||||
|
||||
int tr_compareUint8 ( uint8_t a, uint8_t b );
|
||||
int tr_compareUint16( uint16_t a, uint16_t b );
|
||||
int tr_compareUint32( uint32_t a, uint32_t b );
|
||||
int tr_compareUint64( uint64_t a, uint64_t b );
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
struct tr_bitfield
|
||||
{
|
||||
uint8_t * bits;
|
||||
size_t len;
|
||||
}
|
||||
tr_bitfield_t;
|
||||
};
|
||||
|
||||
tr_bitfield_t* tr_bitfieldNew( size_t bitcount );
|
||||
tr_bitfield_t* tr_bitfieldDup( const tr_bitfield_t* );
|
||||
void tr_bitfieldFree( tr_bitfield_t*);
|
||||
typedef struct tr_bitfield tr_bitfield;
|
||||
typedef struct tr_bitfield tr_bitfield_t;
|
||||
|
||||
void tr_bitfieldClear( tr_bitfield_t* );
|
||||
void tr_bitfieldAdd( tr_bitfield_t*, size_t bit );
|
||||
void tr_bitfieldRem( tr_bitfield_t*, size_t bit );
|
||||
void tr_bitfieldAddRange( tr_bitfield_t *, size_t begin, size_t end );
|
||||
void tr_bitfieldRemRange ( tr_bitfield_t*, size_t begin, size_t end );
|
||||
tr_bitfield* tr_bitfieldNew( size_t bitcount );
|
||||
tr_bitfield* tr_bitfieldDup( const tr_bitfield* );
|
||||
void tr_bitfieldFree( tr_bitfield*);
|
||||
|
||||
int tr_bitfieldIsEmpty( const tr_bitfield_t* );
|
||||
size_t tr_bitfieldCountTrueBits( const tr_bitfield_t* );
|
||||
void tr_bitfieldClear( tr_bitfield* );
|
||||
void tr_bitfieldAdd( tr_bitfield*, size_t bit );
|
||||
void tr_bitfieldRem( tr_bitfield*, size_t bit );
|
||||
void tr_bitfieldAddRange( tr_bitfield *, size_t begin, size_t end );
|
||||
void tr_bitfieldRemRange ( tr_bitfield*, size_t begin, size_t end );
|
||||
|
||||
tr_bitfield_t* tr_bitfieldNegate( tr_bitfield_t* );
|
||||
tr_bitfield_t* tr_bitfieldAnd( tr_bitfield_t*, const tr_bitfield_t* );
|
||||
int tr_bitfieldIsEmpty( const tr_bitfield* );
|
||||
size_t tr_bitfieldCountTrueBits( const tr_bitfield* );
|
||||
|
||||
tr_bitfield* tr_bitfieldNegate( tr_bitfield* );
|
||||
tr_bitfield* tr_bitfieldAnd( tr_bitfield*, const tr_bitfield* );
|
||||
|
||||
#define tr_bitfieldHas(bitfield,nth) \
|
||||
( ( bitfield ) && ( (bitfield)->bits[(nth)>>3] & 128 >>( (nth) & 7 ) ) )
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
#
|
||||
# $Id$
|
||||
|
||||
# convention: -TR MAJOR MINOR MAINT BETA - (each a single char)
|
||||
# BETA: "Z" for beta, "0" for stable
|
||||
# these should be the only two lines you need to change
|
||||
PEERID_PREFIX="-TR082Z-"
|
||||
USERAGENT_PREFIX="0.82+"
|
||||
PEERID_PREFIX="-TR080Z-"
|
||||
USERAGENT_PREFIX="0.80+"
|
||||
|
||||
|
||||
SVN_REVISION=`find ./ -name "*\.[ch]" -o -name "*\.cpp" -o -name "*\.po" | \
|
||||
|
|
Loading…
Reference in New Issue