merge encryption branch to trunk (xcode project is still out of date)

This commit is contained in:
Mitchell Livingston 2007-09-20 16:32:01 +00:00
parent 4932e8eb0e
commit 76da1185ca
72 changed files with 6931 additions and 3052 deletions

175
doc/encryption.txt Normal file
View File

@ -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

5
doc/properties.txt Normal file
View File

@ -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\$'

53
gtk/lock-icon.h Normal file
View File

@ -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"};

View File

@ -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};

View File

@ -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 ();

View File

@ -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 \

View File

@ -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;
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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;

View File

@ -22,4 +22,4 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
char * tr_clientForId( uint8_t * );
char * tr_clientForId( const uint8_t * );

View File

@ -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;

View File

@ -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

257
libtransmission/crypto.c Normal file
View File

@ -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;
}

78
libtransmission/crypto.h Normal file
View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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 );
}
}
/***********************************************************************

897
libtransmission/handshake.c Normal file
View File

@ -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 );
}

View File

@ -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

View File

@ -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 );

View File

@ -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 );
}
}
}

View File

@ -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

View File

@ -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];
};

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

519
libtransmission/peer-io.c Normal file
View File

@ -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 );
}

178
libtransmission/peer-io.h Normal file
View File

@ -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

View File

@ -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

1064
libtransmission/peer-mgr.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

1294
libtransmission/peer-msgs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 );

View File

@ -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 * );

View File

@ -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;

View File

@ -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
{

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 );

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 * ) );
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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" );
}

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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 );
}
}

View File

@ -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

View File

@ -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 )

View File

@ -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;

View File

@ -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 ) ) )

View File

@ -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" | \