Discover Peers: Bittorent in C

I’m stuck on Stage #FI9, where we have to discover peers

I’ve tried a lot of bit manipulation. I also did research to see if there was a way to handle big endian in C. I saw htons() and ntohs(), but I struggle to understand how that quite works.

Here are my logs:
When I run locally:

sinmi@Sinmi:~/codecrafters-bittorrent-c$ gcc -g -o main app/*.c -lcrypto -lcurl -lssl -lm
sinmi@Sinmi:~/codecrafters-bittorrent-c$ ./main peers app/sample.torrent
165.232.41.73:51556
165.232.38.164:51493
165.232.35.114:51476

I suspect that this is wrong, because the ports of the last 2 ip address does not match what is expected from sample.torrent. However, I do not know what else to do because I am stuck

Here are the logs when I run on codecrafters

remote: [tester::#FI9] Running tests for Stage #FI9 (Discover peers)
remote: [tester::#FI9] Running ./your_bittorrent.sh peers /tmp/torrents1964150527/test.torrent
remote: [tester::#FI9] Tracker started on address 127.0.0.1:32791...
remote: [tester::#FI9]
remote: [your_program] 188.119.61.177:65505
remote: [your_program] 185.107.13.235:54542
remote: [your_program] 88.99.2.101:65505
remote: [tester::#FI9] Expected stdout to contain "188.119.61.177:6881", got: "188.119.61.177:65505\n185.107.13.235:54542\n88.99.2.101:65505\n"
remote: [tester::#FI9] Test failed

And here’s a snippet of my code:


Peers *get_peers(TrackerResp *response){
    Peers *all_peers = malloc(sizeof(Peers));

    // create a copy of response and find how many peers exist
    char haystack[1024];
    strcpy(haystack, response->data);
    char *temp = strstr(haystack, "peers");
    temp += strlen("peers");

    // find out where peers start from in Tracker rESP
    char *peers = NULL;
    int peer_size = strtol(temp, &peers, 10);
    peers += 1; // skip the ':'

    // init peers struct.
    all_peers->num_peers = peer_size / 6; // due to the compact
    all_peers->peer = malloc(peer_size * sizeof(char *));
    temp = peers;
    int idx = 0;

    for (int i = 0; i < all_peers->num_peers; i++)
    {   
        // construct ip address and port number
        uint8_t octet_1 =  temp[idx]  & 0xFF;
        uint8_t octet_2 =  temp[idx + 1]  & 0xFF;
        uint8_t octet_3 =  temp[idx + 2]  & 0xFF;
        uint8_t octet_4 =  temp[idx + 3] & 0xFF;
        uint16_t port =  (temp[idx + 4] << 8 | temp[idx + 5]);

        // size required to store ip address and port
        char temp_buf[1024];
        int total = snprintf(temp_buf, 1024, 
                            "%d.%d.%d.%d:%d", 
                            octet_1, octet_2, octet_3, octet_4, port);
        
        // save peer
        char *peer_ip = malloc(total + 1);
        strncpy(peer_ip, temp_buf, total);
        peer_ip[total] = '\0';
        all_peers->peer[i] = peer_ip;
        idx += 6;
    }

    return all_peers;
}

The idea nehind calculating the port is that I need 2 bytes after the first 4 bytes. Given that each 8 bit is 1 byte, I figured the big endian implementation would be to put the 5th byte as upper 8 bits, and 6th byte as lower 8bits to give 16 bits in all, to represent the port.

At first, I though it was because snprintf writes null to a buffer by default, maybe that messed up my bit positioning, but I double checked, anmd that is not the case

Is my understanding wrong? If full code is needed, please let me know and I will post it

Hi sinmi-hub,
You’re right, the port needs to be interpreted as an unsigned, 16 bit big endian binary number.

Does using this make a difference?
uint16_t port = ((uint8_t)temp[idx + 4] << 8) | (uint8_t)temp[idx + 5];

This ensures that both bytes are treated as unsigned and combined in big-endian order.

Hello @sarp
Thanks for responding. I still seem to be having the same problem

Here is a recent test that I ran

6881 is the port we were supposed to use when sending GET request, but I doubt it has anything to do with response.

For the most part, i seem to be able to parse ip address, but not port

i also printed out the values before combining…is it possible thatt the sample.torrent maybe different from what was posted in description?

   //------------------------------------------------------------------
        // Extract the port from the next two bytes
        uint8_t port_msb = temp[idx + 4] & 0xFF; // Most significant byte of the port
        uint8_t port_lsb = temp[idx + 5] & 0xFF; // Least significant byte of the port

        // Print the raw bytes to verify correctness
        printf("Port bytes: 0x%02X 0x%02X\n", port_msb, port_lsb);
        // Combine the two bytes to form the port
        uint16_t port1 = (port_msb << 8) | port_lsb;

        // Step 2: Debug the result of port construction
        printf("Constructed Port: %d\n", port1);
        //---------------------------------------------------------


Since the value is binary, i cant tell for sure if this is what sample.torrent has. If i knew, then i could probaby know by how much bits I am off

I should also state that I used curl library to send the request, rather than do it manually of creating sockets and all. Is it possible that while parsing the response, something happended?

The values you’ve shared for sample.torrent look correct:

165.232.41.73:51556
165.232.38.164:51493
165.232.35.114:51476

Course description seems to be out of date, sorry about that! I’ve updated it to avoid future confusion, thanks for reporting.

I see. I am glad that is resolved.

Although, I am still failing the tests. Could you please help me with this?

The test requires 3 ip addresses, but the expected stdout is not reflected in possible answer

I am sincerely confused as to how the ports sent in the GET requests is not what the tests is looking for, especially because it works for sample.torrent

I understand that people have passed these stages, so i know the error is on my part

Resolved

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.