Transmission框架解析
一.概述
因工作需要,接触了一下transmission, 了解了一下它的框架,但是没有做进一步的开发,此处作为笔记打个标记。
transmission是开源的bt下载工具,可以兼容linux和windows环境;
Bt协议可以参考网站:http://www.bittorrent.org/;
在transmission代码中使用了libevent的框架;
二.具体流程
2.1 tr_session数据结构
struct tr_session
{
……
int torrentCount;
tr_torrent* torrentList; //每创建一个tor实例都会挂载在这个链表里
……
}
2.2 tr_torrent数据结构
struct tr_torrent
{
……
tr_session * session; //tor 实例,反过来指向session
……
}
2.3 void tr_eventInit (tr_session * session)
该函数session =tr_sessionInit ("daemon", configDir, true, &settings)中被调用
2.3.1 struct tr_event_handle
typedef struct tr_event_handle
{
uint8_t die;
int fds[2]; //管道描述符
tr_lock * lock;
tr_session * session;
tr_thread * thread;
struct event_base * base;
struct event * pipeEvent;
}
2.3.2 tr_eventInit
该函数创建一个线程,该线程函数建立一个总的消息循环;
tr_eventInit (tr_session * session)
{
tr_event_handle* eh;
pipe (eh->fds) //建立管道,很重要,创建执行函数时会用它来通信
eh->thread= tr_threadNew (libeventThreadFunc, eh);
}
2.3.3 libeventThreadFunc
static void
libeventThreadFunc (void * veh)
{
struct event_base * base;
tr_event_handle * eh = veh;
#ifndef WIN32
/* Don't exit when writing on a broken socket */
signal (SIGPIPE, SIG_IGN);
#endif
/* create the libevent bases */
base = event_base_new ();
/* set the struct's fields */
eh->base = base;
eh->session->event_base = base;
eh->session->evdns_base = evdns_base_new (base, true);
eh->session->events = eh;
/* listen to thepipe's read fd */
eh->pipeEvent = event_new (base,eh->fds[0], EV_READ | EV_PERSIST, readFromPipe, veh);
//readFromPipe(),注册的函数,读取管道中的信息,执行
event_add (eh->pipeEvent, NULL);
event_set_log_callback (logFunc);
/* loop until all the events are done */
while (!eh->die)
event_base_dispatch (base); //libevent主体的循环
/* shut down the thread */
tr_lockFree (eh->lock);
event_base_free (base);
eh->session->events = NULL;
tr_free (eh);
tr_logAddDebug ("Closing libevent thread");
}
2.3.4 readFromPipe
static void
readFromPipe (evutil_socket_t fd,
short eventType,
void * veh)
{
char ch;
int ret;
tr_event_handle * eh = veh;
dbgmsg ("readFromPipe: eventType is %hd", eventType);
/* read the command type */
ch = '\0';
do
{
ret = piperead (fd, &ch, 1);
}
while (!eh->die && ret < 0 && errno == EAGAIN);
dbgmsg ("command is [%c], ret is %d, errno is %d", ch, ret,(int)errno);
switch (ch)
{
case 'r': /* run in libevent thread */
{
struct tr_run_data data;
const size_t nwant = sizeof(data);
const ssize_t ngot = piperead(fd, &data, nwant);
if (!eh->die && (ngot== (ssize_t)nwant))
{
dbgmsg ("invoking functionin libevent thread");
(data.func)(data.user_data);
}
break;
}
case '\0': /* eof */
{
dbgmsg ("pipe eofreached... removing event listener");
event_free (eh->pipeEvent);
break;
}
default:
{
assert (0 && "unhandled command type!");
break;
}
}
}
2.3.5 tr_runInEventThread
void
tr_runInEventThread (tr_session *session, /*phicomm important*/
void func (void*), void *user_data)
{
assert (tr_isSession (session));
assert (session->events != NULL);
if(tr_amInThread (session->events->thread))
{
(func)(user_data);
}
else
{
int fd;
char ch;
ssize_t res_1;
ssize_t res_2;
tr_event_handle * e = session->events;
struct tr_run_data data;
tr_lockLock (e->lock);
fd = e->fds[1];
ch = 'r';
res_1 = pipewrite (fd, &ch, 1);
data.func = func;
data.user_data = user_data;
res_2 = pipewrite (fd,&data, sizeof (data));
//将函数地址送入管道,由readFromPipe()读取后执行;
tr_lockUnlock (e->lock);
if ((res_1 == -1) || (res_2 == -1))
tr_logAddError ("Unable to write to libtransmisison event queue:%s", tr_strerror(errno));
}
}
2.4 tr_sessionInitImpl
tr_runInEventThread (session, tr_sessionInitImpl, &data);//很熟悉吧,就是上文的介绍,此处启动函数执行
Void tr_sessionInitImpl (void * vdata)
2.5 torrentInit
torrentInit (tr_torrent * tor, const tr_ctor * ctor)
一层一层的封装以后,会有
tr_runInEventThread (tor->session, torrentStartImpl, tor)
tr_peerMgrStartTorrent (tor);
ensureMgrTimersExist (s->manager);
bandwidthPulse
reconnectPulse
makeNewPeerConnections
initiateCandidateConnection
initiateConnection
2.6initiateConnection
initiateConnection (tr_peerMgr * mgr, tr_swarm * s, struct peer_atom* atom)
tr_peerIo*
tr_peerIoNewOutgoing (tr_session * session,
tr_bandwidth * parent,
consttr_address * addr,
tr_port port,
constuint8_t * torrentHash,
bool isSeed,
bool utp)
static tr_peerIo*
tr_peerIoNew (tr_session * session,// here add callback to read and write
tr_bandwidth * parent,
const tr_address* addr,
tr_port port,
constuint8_t * torrentHash,
bool isIncoming,
bool isSeed,
int socket,
struct UTPSocket* utp_socket)
{
……
if (io->socket >= 0) {
io->event_read =event_new (session->event_base,
io->socket, EV_READ, event_read_cb,io); io->event_write =event_new (session->event_base,
io->socket, EV_WRITE,event_write_cb, io);
……
}
static void
event_read_cb (evutil_socket_t fd, short event UNUSED, void * vio)
{
res = evbuffer_read(io->inbuf, fd, (int)howmuch); //从IO读取数据
if (res > 0)
{
tr_peerIoSetEnabled(io, dir, true);
/* Invoke the usercallback - must always be called last */
canReadWrapper (io); //调用回调处理,canRead()
}
else
{
}
}
void
initiateConnection (tr_peerMgr * mgr,tr_swarm * s, struct peer_atom * atom)
{
io= tr_peerIoNewOutgoing (mgr->session,//phicomm init socket
&mgr->session->bandwidth,
&atom->addr,
atom->port,
s->tor->info.hash,
s->tor->completeness == TR_SEED,
utp);
if(io == NULL)
{
tordbg (s, "peerIo not created; marking peer %s asunreachable", tr_atomAddrStr (atom));
atom->flags2 |= MYFLAG_UNREACHABLE;
atom->numFails++;
}
else
{
tr_handshake * handshake = tr_handshakeNew (io, //phicomm
mgr->session->encryptionMode,
myHandshakeDoneCB,
mgr);
//此处完成握手后会在该函数中注册canRead
}
static bool
myHandshakeDoneCB (tr_handshake * handshake,
tr_peerIo * io,
bool readAnythingFromPeer,
bool isConnected,
const uint8_t * peer_id,
void * vmanager)
{
createBitTorrentPeer (s->tor, io, atom,client);
}
static void
createBitTorrentPeer (tr_torrent * tor,
struct tr_peerIo * io,
struct peer_atom * atom,
tr_quark client)
{
peer = (tr_peer*) tr_peerMsgsNew (tor, io,peerCallbackFunc, swarm);
}
tr_peerMsgs *
tr_peerMsgsNew (struct tr_torrent * torrent,
struct tr_peerIo * io,
tr_peer_callback callback,
void * callbackData)
{
tr_peerIoSetIOFuncs (m->io, canRead,didWrite, gotError, m);
}