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