tDescribe all functions - libeech - bittorrent library
 (HTM) git clone git://z3bra.org/libeech.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit fad1cd5caca4176138b2378e02f18c782ecd886f
 (DIR) parent e308b69b6b819eed9e2e29cab389ce4879c61d8b
 (HTM) Author: z3bra <contactatz3bradotorg>
       Date:   Thu,  5 Jul 2018 09:02:35 +0200
       
       Describe all functions
       
       Diffstat:
         M libeech.c                           |     250 +++++++++++++++++++++++++------
       
       1 file changed, 201 insertions(+), 49 deletions(-)
       ---
 (DIR) diff --git a/libeech.c b/libeech.c
       t@@ -66,26 +66,31 @@ static struct peer * delpeer(struct peer *, struct peer *);
        static int peercnt(struct peer *);
        
        /* handle peer wire protocol (PWP) messages */
       +static ssize_t pwprecv(struct peer *);
       +static ssize_t pwpsend(struct peer *, char *, size_t);
       +
       +/* send, receive and verify handshakes */
        static ssize_t pwptxhs(struct torrent *, struct peer *);
        static ssize_t pwprxhs(struct peer *);
        static int pwphsck(struct torrent *, char *, long);
        
       -static ssize_t pwprecv(struct peer *);
       -static ssize_t pwpsend(struct peer *, char *, size_t);
       -
       +/* send different PWP messages */
        static ssize_t pwptxst(struct peer *, int);
        static ssize_t pwptxhv(struct peer *, long);
        static ssize_t pwptxbf(struct torrent *, struct peer *);
        static ssize_t pwptxrq(struct torrent *, struct peer *);
        
       +/* receive different PWP messages */
        static int pwprxst(struct peer *, int);
        static int pwprxhv(struct peer *, size_t, char *);
        static int pwprxbf(struct peer *, size_t, char *);
        static int pwprxrq(struct torrent *, struct peer *, size_t, char *);
        static int pwprxpc(struct torrent *, struct peer *, size_t, char *);
        
       +/* handle all received PWP messages */
        static int pwprxcb(struct torrent *, struct peer *, int, size_t, char *);
        
       +/* functions to run when a peer can receive or has sent bytes over the wire */
        static int pwptx(struct torrent *, struct peer *);
        static int pwprx(struct torrent *, struct peer *);
        
       t@@ -93,12 +98,15 @@ static int pwprx(struct torrent *, struct peer *);
        static int netconn(char *, int);
        static int netloop(struct torrent *, int);
        
       +
       +/* check wether a specific bit is set or not in a byte */
        static int
        bit(char *bits, long off)
        {
                return !!(bits[off / 8] & (1 << (7 - off%8)));
        }
        
       +/* set a bit in a byte to one */
        static char *
        setbit(char *bits, long off)
        {
       t@@ -106,6 +114,7 @@ setbit(char *bits, long off)
                return bits;
        }
        
       +/* set a bit in a byte to zero */
        static char *
        clrbit(char *bits, long off)
        {
       t@@ -113,6 +122,7 @@ clrbit(char *bits, long off)
                return bits;
        }
        
       +/* generate a random peer ID */
        static char *
        peerid()
        {
       t@@ -153,6 +163,15 @@ torrentsize(struct torrent *t)
                return sz;
        }
        
       +/*
       + * Read file(s) from torrent file, and store their path/size in a struct
       + *
       + * TODO: Remove this function entirely, and create helpers to fetch
       + * these info directly from the torrent file.
       + * torrent->files would thus be a `struct be` pointing to either "file"
       + * or "files" attribute in the torrent, removing one more malloc()
       + * in the library.
       + */
        static long
        torrentfiles(struct torrent *t)
        {
       t@@ -194,6 +213,8 @@ torrentfiles(struct torrent *t)
        
                return n;
        }
       +
       +/* Verify that all mandatory keys of a torrent are present */
        static int
        chktorrent(struct be *b)
        {
       t@@ -242,6 +263,7 @@ chktorrent(struct be *b)
                return 0;
        }
        
       +/* read a piece from a metafile (named after the SHA1 infohash) */
        static long
        readpiece(struct torrent *t, struct piece *p, long n)
        {
       t@@ -266,6 +288,7 @@ readpiece(struct torrent *t, struct piece *p, long n)
                return p->sz;
        }
        
       +/* write a piece to a metafile (named after the SHA1 infohash) */
        static long
        writepiece(struct torrent *t, struct piece *p)
        {
       t@@ -299,6 +322,7 @@ writepiece(struct torrent *t, struct piece *p)
                return 0;
        }
        
       +/* Verify that a piece matches its SHA1 hash */
        static int
        chkpiece(struct torrent *t, struct piece *p, long n)
        {
       t@@ -308,6 +332,13 @@ chkpiece(struct torrent *t, struct piece *p, long n)
                return memcmp(t->ph + n*20, hash, 20);
        }
        
       +/*
       + * Create a new peer struct, and add it to the list of peers
       + *
       + * TODO: Remove the malloc() and have the caller pass the `struct peer`
       + * to add as an argument.
       + * Memory tracking of those peers is on the caller responsibility.
       + */
        static struct peer *
        addpeer(struct peer *pl, char *host, int port)
        {
       t@@ -330,6 +361,7 @@ addpeer(struct peer *pl, char *host, int port)
                return p;
        }
        
       +/* Find a peer by its host + port */
        static struct peer *
        getpeer(struct peer *pl, char *host, int port)
        {
       t@@ -342,6 +374,13 @@ getpeer(struct peer *pl, char *host, int port)
                return NULL;
        }
        
       +/*
       + * Remove a peer from the struct
       + *
       + * TODO: Do not free() the peer to delete, and return a pointer to
       + * it instead.
       + * Memory tracking of those peers is on the caller responsibility.
       + */
        static struct peer *
        delpeer(struct peer *pl, struct peer *p)
        {
       t@@ -358,57 +397,37 @@ delpeer(struct peer *pl, struct peer *p)
                return pl;
        }
        
       +/* Count the number of peers currently added to this torrent */
        static int
        peercnt(struct peer *pl)
        {
                return (pl ? 1 + peercnt(pl->next) : 0);
        }
        
       -static ssize_t
       -pwptxhs(struct torrent *t, struct peer *p)
       -{
       -        char m[68];
       -
       -        m[0] = 19;
       -        memcpy(m + 1, "BitTorrent protocol", 19);
       -        memset(m + 20, 0, 8);
       -        memcpy(m + 28, t->ih, 20);
       -        memcpy(m + 48, t->id, 20);
       -
       -        return pwpsend(p, m, 68);
       -}
       -
       -static ssize_t
       -pwprxhs(struct peer *p)
       -{
       -        ssize_t r;
       -
       -        while ((r = recv(p->fd, p->rxbuf, 68 - p->rxbufsz, 0)) > 0)
       -                p->rxbufsz += r;
       -
       -        if (r < 0)
       -                return -1;
        
       -        return p->rxbufsz;
       -}
       -
       -static int
       -pwphsck(struct torrent *t, char *hs, long l)
       -{
       -        if (l != 68)
       -                return -1;
       -        if (hs[0] != 19)
       -                return -1;
       -        if (memcmp(hs+1, "BitTorrent protocol", 19))
       -                return -1;
       -        if (memcmp(hs+28, t->ih, 20))
       -                return -1;
       -        if (!memcmp(hs+48, t->id, 20))
       -                return -1;
       +/*
       + * PWP (Peer Wire Protocol) message management
       + *
       + * Standard PWP messages: [LENGTH][TYPE][PAYLOAD]
       + * Length: 4 bytes bigendian; Size of the type + payload
       + * Type is a single byte
       + * Payload is variable and is length - 1
       + */
        
       -        return 0;
       -}
        
       +/*
       + * Wrapper to recv() syscall. We first PEEK 4 bytes in the messages,
       + * to retrieve its length.
       + * Once we have it, we read this amount of bytes + 4 (the initial size)
       + * from the socket.  Reading bytes is done in a buffer tied to the peer,
       + * so that if we cannot read the whole message yet, the remaining parts
       + * will be read on the next iteration.
       + *
       + * The function returns the numbers of bytes missing in the message,
       + * or -1 in case of errors.
       + * When it returns 0, it means the message is fully read and can be
       + * parsed.
       + */
        static ssize_t
        pwprecv(struct peer *p)
        {
       t@@ -436,6 +455,10 @@ pwprecv(struct peer *p)
                return l - p->rxbufsz;
        }
        
       +/*
       + * Wrapper to the send() syscall. It will loop to send the full message,
       + * until everything is sent, or an error occurs.
       + */
        static ssize_t
        pwpsend(struct peer *p, char *m, size_t sz)
        {
       t@@ -454,12 +477,81 @@ pwpsend(struct peer *p, char *m, size_t sz)
        }
        
        /*
       - * Standard PWP messages: [LENGTH][TYPE][PAYLOAD]
       - * Length: 4 bytes bigendian; Size of the type + payload
       - * Type is a single byte
       - * Payload is variable and is length - 1
       + * Create and send a handshake message. From the Bittorrent spec:
       + *
       + * > A handshake is a string of bytes with the following structure:
       + * > 
       + * > ----------------------------------------------------------------
       + * > | Name Length | Protocol Name | Reserved | Info Hash | Peer ID |
       + * > ----------------------------------------------------------------
       + *
       + * Name length: size of the "Protocol Name" attribute
       + * Protocol name: "Bittorrent protocol", as of BitTorrent Protocol revision 1.33 (BTP/1.0)
       + * Reserved: Used to list supported extensions to the protocol
       + * Info hash: SHA1 hash of the full "info" key from the torrent
       + * Peer ID: Our own ID, used for identification (or not at all)
       + */
       +static ssize_t
       +pwptxhs(struct torrent *t, struct peer *p)
       +{
       +        char m[68];
       +
       +        m[0] = 19;
       +        memcpy(m + 1, "BitTorrent protocol", 19);
       +        memset(m + 20, 0, 8);
       +        memcpy(m + 28, t->ih, 20);
       +        memcpy(m + 48, t->id, 20);
       +
       +        return pwpsend(p, m, 68);
       +}
       +
       +/*
       + * Wrapper to the recv() syscall to receive handshakes
       + * Handshake messages size is fixed in BTP/1.0 to 68 bytes.
       + * We cannot receive it as a standard PWP message.
         */
       +static ssize_t
       +pwprxhs(struct peer *p)
       +{
       +        ssize_t r;
       +
       +        while ((r = recv(p->fd, p->rxbuf, 68 - p->rxbufsz, 0)) > 0)
       +                p->rxbufsz += r;
       +
       +        if (r < 0)
       +                return -1;
       +
       +        return p->rxbufsz;
       +}
       +
       +/* Verify that a handshake is valid according to a torrent */
       +static int
       +pwphsck(struct torrent *t, char *hs, long l)
       +{
       +        if (l != 68)
       +                return -1;
       +        if (hs[0] != 19)
       +                return -1;
       +        if (memcmp(hs+1, "BitTorrent protocol", 19))
       +                return -1;
       +        if (memcmp(hs+28, t->ih, 20))
       +                return -1;
       +        if (!memcmp(hs+48, t->id, 20))
       +                return -1;
       +
       +        return 0;
       +}
        
       +/*
       + * Send a change of status PWP message.
       + * These messages have no payload and can be sent the same way.
       + *
       + *         0: CHOKE
       + *         1: UNCHOKE
       + *         2: INTERESTED
       + *         3: UNINTERESTED
       + *
       + */
        static ssize_t
        pwptxst(struct peer *p, int t)
        {
       t@@ -476,6 +568,7 @@ pwptxst(struct peer *p, int t)
                return pwpsend(p, m, 5);
        }
        
       +/* Send a HAVE PWP message */
        static ssize_t
        pwptxhv(struct peer *p, long n)
        {
       t@@ -495,6 +588,10 @@ pwptxhv(struct peer *p, long n)
                return pwpsend(p, m, 9);
        }
        
       +/*
       + * Send a BITFIELD message with our full bitfield (no cheating with HAVE
       + * messages here)
       + */
        static ssize_t
        pwptxbf(struct torrent *t, struct peer *p)
        {
       t@@ -517,6 +614,20 @@ pwptxbf(struct torrent *t, struct peer *p)
                return pwpsend(p, m, l + 5);
        }
        
       +/*
       + * Send a REQUEST PWP message for all blocks in a piece.
       + *
       + * We request only once piece at a time to a peer. The piece currently
       + * being requested is saved in the peer struct. A piece number of -1
       + * means that the peer is not requesting any piece.
       + * A piece number of t->npiece means that no piece can be requested to
       + * the peer (no new piece available).
       + *
       + * The function will send a REQUEST messages for all the blocks in the
       + * piece, then return.
       + *
       + * TODO: Implement a function to select a piece from different algorithms
       + */
        static ssize_t
        pwptxrq(struct torrent *t, struct peer *p)
        {
       t@@ -564,6 +675,7 @@ pwptxrq(struct torrent *t, struct peer *p)
                return 0;
        }
        
       +/* Receive and treat a change of status from the peer */
        static int
        pwprxst(struct peer *p, int type)
        {
       t@@ -584,6 +696,7 @@ pwprxst(struct peer *p, int type)
                return 0;
        }
        
       +/* Receive and treat a HAVE message from the peer */
        static int
        pwprxhv(struct peer *p, size_t sz, char *pl)
        {
       t@@ -594,6 +707,7 @@ pwprxhv(struct peer *p, size_t sz, char *pl)
                return 0;
        }
        
       +/* Receive and save the BITFIELD sent by a peer */
        static int
        pwprxbf(struct peer *p, size_t sz, char *pl)
        {
       t@@ -601,12 +715,23 @@ pwprxbf(struct peer *p, size_t sz, char *pl)
                return 0;
        }
        
       +/* Receive a block REQUEST from a peer */
        static int
        pwprxrq(struct torrent *t, struct peer *p, size_t sz, char *pl)
        {
                return 0;
        }
        
       +/*
       + * Receive a PIECE block from a peer
       + *
       + * After receiving a block, we'll verify if the piece matches its SHA1 hash.
       + * If it does, we write the piece to a metafile named after the hexadecimal
       + * version of the info hash.
       + *
       + * TODO: Keep track of received blocks, so we can discard a piece if we
       + * receive all blocks, but the hash doesn't match what we expect.
       + */
        static int
        pwprxpc(struct torrent *t, struct peer *p, size_t sz, char *pl)
        {
       t@@ -630,6 +755,10 @@ pwprxpc(struct torrent *t, struct peer *p, size_t sz, char *pl)
                return 0;
        }
        
       +/*
       + * PWP message received callback
       + * This function will run the appropriate function based on the message type
       + */
        static int
        pwprxcb(struct torrent *t, struct peer *p, int type, size_t sz, char *pl)
        {
       t@@ -658,6 +787,7 @@ pwprxcb(struct torrent *t, struct peer *p, int type, size_t sz, char *pl)
                return 0;
        }
        
       +/* Logic to send messages when peer is ready */
        static int
        pwptx(struct torrent *t, struct peer *p)
        {
       t@@ -681,6 +811,7 @@ pwptx(struct torrent *t, struct peer *p)
                return 0;
        }
        
       +/* Logic to receive messages when peer sent data */
        static int
        pwprx(struct torrent *t, struct peer *p)
        {
       t@@ -702,6 +833,7 @@ pwprx(struct torrent *t, struct peer *p)
                return 0;
        }
        
       +/* Initiate connection with a peer */
        static int
        netconn(char *host, int port)
        {
       t@@ -733,6 +865,7 @@ netconn(char *host, int port)
                return fd;
        }
        
       +/* Poll() all peers for read/write readiness on each iteration */
        static int
        netloop(struct torrent *t, int timeout)
        {
       t@@ -777,6 +910,16 @@ netloop(struct torrent *t, int timeout)
                return npeer;
        }
        
       +
       +/*
       + * Library function call
       + */
       +
       +/*
       + * Load a torrent in a torrent struct
       + *
       + * RETURN VALUE: returns 0 if the torrent is loaded, -1 otherwise
       + */
        int
        glch_loadtorrent(struct torrent *t, char *b, size_t s)
        {
       t@@ -823,6 +966,11 @@ glch_loadtorrent(struct torrent *t, char *b, size_t s)
                return 1;
        }
        
       +/*
       + * Connect to a remote peer
       + *
       + * RETURN VALUE: returns 0 if connection is established, -1 otherwise
       + */
        int
        glch_addpeer(struct torrent *t, char *host, int port)
        {
       t@@ -844,6 +992,10 @@ glch_addpeer(struct torrent *t, char *host, int port)
                return 0;
        }
        
       +/*
       + * Perform one network iteration with all the peers, or timeout if
       + * noone replies
       + */
        int
        glch_leech(struct torrent *t, int timeout)
        {