Domanda

I'm trying to connect to a UDP tracker server using the code below, but I'm not getting any responses from the tracker...

I gleaned what I could from this link: http://xbtt.sourceforge.net/udp_tracker_protocol.html

and I thought I got it...but apparently not. The code executes fine and then hangs at the call to RecvFrom. So I'm guessing I'm either not sending the correct data, or I'm sending it to the wrong place.....

struct ConnectionIdRequest_t {

    uint64_t connectionId;
    uint32_t action;
    int32_t transactionId;
} typedef ConnectionIdRequest;

const bool UdpTorrentTrackerComm::initiateConnection(const int amountUploaded, 
const int amountDownloaded, 
const int amountLeft) {

    struct sockaddr_in serverAddress, clientAddress;
    struct hostent * host;
    struct in_addr address;

    //Setup dummy client address
    clientAddress.sin_family = AF_INET;
    clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    clientAddress.sin_port = htons(0);

    //Setup server address
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(portNumber);

    //SETUP in_addr server address
    //If we have an IP
    if (trackerAddress) {

        if (isIp4Address(*trackerAddress)) {

            //retrieve hostname from ip address 
            if (inet_aton(trackerAddress->c_str(), &address)) {

                host = gethostbyaddr((const char *) &address, sizeof(address), AF_INET);
                trackerHostname = new std::string(host->h_name);
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {
        //retrieve ip address from hostname
        host = gethostbyname(trackerHostname->c_str());
        address.s_addr = ((struct in_addr *) host->h_addr_list)->s_addr;
        trackerAddress = new std::string(inet_ntoa(address));
    }
std::cout << *trackerAddress << std::endl;
    //Convert trackerAddress to network format
    if(!inet_aton(trackerAddress->c_str(), &serverAddress.sin_addr)) {
        return false;
    }

    int sockFd = -1;
    //Add IPv6 in the future
    if ((sockFd = Socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        return false;
    }

    //Bind my address to the socket
    if (Bind(sockFd, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) == - 1) {
        return false;
    }

    std::cout << "SendTo\n";
    ConnectionIdRequest * idRequest = createConnectionIdRequest();
    if (SendTo(sockFd, idRequest, sizeof(*idRequest), 0, 
        (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) {
        return false;
    }
    timeRequestSent = clock();
std::cout << "Sent: " << idRequest->connectionId << "|||" << idRequest->action << "|||" << idRequest->transactionId << std::endl;
    std::cout << "RecvFrom\n";
    char buffer[3000];
    socklen_t serverAddressLength = sizeof(serverAddress);
    while(true) {
        if (RecvFrom(sockFd, buffer, 3000, 0, 
            (struct sockaddr *) &serverAddress, &serverAddressLength) == - 1) {
            break;
            std::cout << "breaking...\n";
        }
    }
    std::cout << "The buffer is: " << buffer << std::endl;
    Close(sockFd);

    return true;
}

ConnectionIdRequest * UdpTorrentTrackerComm::createConnectionIdRequest() {

    ConnectionIdRequest * idRequest = new ConnectionIdRequest;
    generatePeerId();
    idRequest->connectionId = htonll(0x41727101980);
    idRequest->action = htonl(CONNECT);
    idRequest->transactionId = htonl(*peerId);

    return idRequest;
}

EDIT: Alright I made the one change that Arvid suggested, but that didn't help any. I'm going through and making sure I'm converting all the bytes being sent are in network byte order...Maybe I'm missing something......

È stato utile?

Soluzione 2

I ended up getting it to work. The problem was mostly that I was not converting all of the values I needed to be converting to big endian (network ordering), along with using outdated functions, (gethostbyname etc).

If you'd like more details just comment.

This is the code that works for me to establish a link with the tracker server:

NOTE: serverAddress and clientAddress are class fields of type: struct sockaddr_in

const bool UdpTorrentTrackerComm::initiateConnection() {

    //Setup dummy client address
    clientAddress.sin_family = AF_INET;
    clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    clientAddress.sin_port = htons(51413);

    //Setup server address
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(portNumber);

    //SETUP in_addr server address
    //If we have an IP
    if (trackerAddress) {

        if (isIp4Address(*trackerAddress)) {

            //Convert human readable trackerAddress to network byte order ip address and place in serverAddress.sin_addr
            if (inet_pton(AF_INET, trackerAddress->c_str(), &(serverAddress.sin_addr))) {

                //retrieve hostname and service type from ip address        
                char hostBuffer[100], serviceBuffer[100];
                getnameinfo((struct sockaddr *) &serverAddress, sizeof(serverAddress), 
                    hostBuffer, sizeof(hostBuffer), 
                    serviceBuffer, sizeof(serviceBuffer), 
                    NI_NAMEREQD | NI_DGRAM);

                trackerHostname = new std::string(hostBuffer);
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {

        //Setup structs to be used in getaddrinfo
        struct addrinfo hints;
        struct addrinfo * result, * resultPointer;
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_flags = 0;
        hints.ai_protocol = 0;

        //Convert port number to string to pass to getaddrinfo
        std::stringstream ss;
        ss << portNumber;
        std::string portNumberString = ss.str();

        //retrieve ip address from hostname--------
        if (GetAddrInfo(trackerHostname->c_str(), portNumberString.c_str(), &hints, &result) != 0) {
            return false;
        }

        //Iterate over results for IP address V4 (ADD V6 later!)
        char ipBuffer[INET_ADDRSTRLEN];
        for (resultPointer = result; resultPointer != NULL; resultPointer = resultPointer->ai_next) {

            //If we have an IPv4 address
            if (resultPointer->ai_family == AF_INET) {

                //convert to presentation format and store in ipBuffer
                inet_ntop(AF_INET, &((struct sockaddr_in *) resultPointer->ai_addr)->sin_addr, ipBuffer, INET_ADDRSTRLEN);
            }
        }
        //Free result
        freeaddrinfo(result);

        //Convert ipBuffer to std::string and store in trackerAddress field
        trackerAddress = new std::string(ipBuffer);

        //Convert trackerAddress to network format
        if(!inet_pton(AF_INET, trackerAddress->c_str(), &serverAddress.sin_addr)) {
            return false;
        }

    }

    int sockFd = -1;
    //Add IPv6 in the future
    if ((sockFd = Socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        return false;
    }

    //Bind my address to the socket
    if (Bind(sockFd, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) == - 1) {
        return false;
    }

    //Send a request to the tracker
    ConnectionIdRequest * idRequest = createConnectionIdRequest();
    if (SendTo(sockFd, idRequest, sizeof(*idRequest), 0, 
        (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) {
        return false;
    }
    timeRequestSent = clock();

    //Re-send until timeout.....
    ConnectionIdResponse idResponse;
    socklen_t serverAddressLength = sizeof(serverAddress);
    while((timeRequestSent - clock()) / 1000 < SECONDS_UNTIL_TIMEOUT) {

        //Response received!
        if (RecvFrom(sockFd, &idResponse, sizeof(idResponse), 0, 
            (struct sockaddr *) &serverAddress, &serverAddressLength) > 0) {
            break;
        }
    }

    //Set class fields that will persist
    activeSocket = sockFd;
    connectionId = ntohll(idResponse.connectionId);

    delete idRequest;

    return true;
}

Where the two structs, ConnectionIdResponse and ConnectionIdRequest are defined as:

    /* Struct used to send a request for a connectionId to the tracker server.*/
struct ConnectionIdRequest_t {

    uint64_t connectionId;
    uint32_t action;
    uint32_t transactionId;
} typedef ConnectionIdRequest;

/* Struct used in receipt of a request for a connectionId from the tracker server. */
struct ConnectionIdResponse_t {
    uint32_t action;
    uint32_t transactionId;
    uint64_t connectionId;
} typedef ConnectionIdResponse;

Altri suggerimenti

it looks like you're conflating transaction ID and peer ID. They are different. The transaction ID is the cookie you send in order to match returning packets to the correct request.

It also looks like you're not initializing the connectionID. You have to set it to the magic 64 bit number in the initial connect message. 0x41727101980

You can find an alternative protocol description here.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top