Transmission框架解析

来源:互联网 发布:淘宝上伊芙丽假货多吗 编辑:程序博客网 时间:2024/06/08 19:05


Transmission框架解析

一.概述

因工作需要,接触了一下transmission, 了解了一下它的框架,但是没有做进一步的开发,此处作为笔记打个标记。

transmission是开源的bt下载工具,可以兼容linuxwindows环境;

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

}

原创粉丝点击