Подключение к UDP-трекеру в переполнении стека

Я пытаюсь подключиться к серверу UDP-трекера, используя приведенный ниже код, но я не получаю никаких ответов от трекера …

Я почерпнул, что мог по этой ссылке:
http://xbtt.sourceforge.net/udp_tracker_protocol.html

и я думал, что получил это … но очевидно нет. Код выполняется нормально, а затем зависает при вызове RecvFrom. Итак, я предполагаю, что я либо не отправляю правильные данные, либо отправляю их не туда …..

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

РЕДАКТИРОВАТЬ: Хорошо, я сделал одно изменение, которое предложил Арвид, но это не помогло. Я прохожу и проверяю, что я преобразовываю все отправленные байты в порядке сетевых байтов … Может быть, я что-то упустил ……

2

Решение

похоже, вы объединяете идентификатор транзакции и идентификатор партнера. Они разные. Идентификатор транзакции — это файл cookie, который вы отправляете для соответствия возвращаемых пакетов с правильным запросом.

Похоже, вы не инициализируете connectionID. Вы должны установить магический 64-битный номер в первоначальном сообщении о соединении. 0x41727101980

Вы можете найти альтернативное описание протокола Вот.

1

Другие решения

Я закончил тем, что заставил это работать. В основном проблема заключалась в том, что я не конвертировал все значения, которые мне требовались для преобразования в bigianian (упорядочение по сети), наряду с использованием устаревших функций (gethostbyname и т. Д.).

Если вы хотите получить более подробную информацию, просто прокомментируйте.

Вот код, который работает для меня, чтобы установить связь с сервером трекера:

ПРИМЕЧАНИЕ: serverAddress и clientAddress являются полями класса типа: 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;
}

Где две структуры, ConnectionIdResponse и ConnectionIdRequest определены как:

    /* 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;
1