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......
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;