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;