tMerge hsrecv() and pwprecv() together - libeech - bittorrent library
(HTM) git clone git://z3bra.org/libeech.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 8afdae6d82a60416d382d93de7d59d18b5adb488
(DIR) parent 93a726cdb20ad6b3b46f0cda4d7436cc262f5d9f
(HTM) Author: Willy Goiffon <dev@z3bra.org>
Date: Tue, 24 Mar 2020 12:53:49 +0100
Merge hsrecv() and pwprecv() together
Diffstat:
M libeech.c | 64 ++++++++++++++++++++-----------
1 file changed, 42 insertions(+), 22 deletions(-)
---
(DIR) diff --git a/libeech.c b/libeech.c
t@@ -404,38 +404,58 @@ peercnt(struct peer *pl)
* 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
+ * > A PWP message has the following structure:
+ * >
+ * > -----------------------------------------
+ * > | Message Length | Message ID | Payload |
+ * > -----------------------------------------
+ *
+ * Message Length: 4 bytes bigendian; size is (ID + payload)
+ * Message ID is a single byte
* Payload is variable and is length - 1
*/
-
/*
- * 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.
+ * Wrapper to the recv() syscall to bufferize input. The received message
+ * content and size is stored in the peer's buffer.
+ * Until the read bytes count matches the expected message length,
+ * we keep reading from socket on each call.
*
* 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.
+ *
+ * Expected message length depends on the context. Until the peer's
+ * handshake is received, expected length will be the one of a full
+ * handshake: fixed to 68 bytes in BTP/1.0.
+ *
+ * After handshake is received (status available in the peer's struct),
+ * we peek 4 bytes from the PWP message, 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.
*/
- ssize_t
+ssize_t
pwprecv(struct peer *p)
{
ssize_t l, r;
- if (!p->rxbufsz) {
- /* read the first 4 bytes to get message length */
- if ((r = recv(p->fd, p->rxbuf, 4, MSG_PEEK)) < 4)
+ /* defaults to handshake length */
+ l = 68;
+
+ /*
+ * handshake is received, treat incoming bytes as a standard
+ * PWP message
+ */
+ if (p->state & HANDSHAKERCVD) {
+ /* peek at first 4 bytes and compute full message length */
+ if (!p->rxbufsz && (r = recv(p->fd, p->rxbuf, 4, MSG_PEEK)) < 4)
return -1;
- }
- /* expected message length */
- l = ntohl(U32(p->rxbuf)) + 4;
+ l = ntohl(U32(p->rxbuf)) + 4;
+ }
if (l > MSGSIZ || l < 5)
return -1;
t@@ -493,7 +513,7 @@ hsck(struct torrent *t, char *hs, long l)
* 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 |
* > ----------------------------------------------------------------
t@@ -967,13 +987,13 @@ int
pwprx(struct torrent *t, struct peer *p)
{
int type;
- ssize_t r;
- /* First message from peer should be the handshake */
- r = (p->state & HANDSHAKERCVD) ? pwprecv(p) : hsrecv(p);
-
- if (!r) {
+ /* receive message from peer */
+ if (!pwprecv(p)) {
+ /* assume first message to be a handshake */
type = (p->state & HANDSHAKERCVD) ? p->rxbuf[4] : HANDSHAKE;
+
+ /* run appropriate callback given message type */
callbacks(t, p, type, p->rxbufsz - 5, p->rxbuf+5);
memset(p->rxbuf, 0, MSGSIZ);
p->rxbufsz = 0;