Reputation: 188
I am trying to make a HTTP request to bittorrent tracker server to get the peer list.
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> // for gethostbyname()
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
using namespace std;
struct in_addr *atoaddr( const char* address)
{
static struct hostent *host;
static struct in_addr saddr;
// First try nnn.nnn.nnn.nnn form
saddr.s_addr = inet_addr(address);
if (saddr.s_addr != -1)
return &saddr;
host = gethostbyname(address);
if( host )
return (struct in_addr *) *host->h_addr_list;
return 0;
}
int main(){
int numbytes=0;
int m_Port=80;
string m_Host="torrent.ubuntu.com";
int m_Sock;
struct hostent *host;
static struct in_addr saddr;
string buffer;
char* buf;
//HTTP request string
buffer.append("GET http://torrent.ubuntu.com:6969/announce HTTP/1.1\r\n");
buffer.append("Host: torrent.ubuntu.com\r\n");
buffer.append("Accept-Encoding: identity\r\n");
buffer.append("info_hash: %36%be%21%35%ab%cc%f4%03%2f%bb%28%bb%1b%0d%4f%da%f7%49%f8%58\r\n");
buffer.append("peer_id: ABCDEFGHIJKLMNOPQRST\r\n");
buffer.append("port: 6881\r\n");
buffer.append("compact: 1\r\n");
buffer.append("uploaded: 0\r\n");
buffer.append("downloaded: 0\r\n");
buffer.append("left: 987758592\r\n");
buffer.append("event: started\r\n");
buffer.append("\r\n");
in_addr* addr = atoaddr( m_Host.c_str() );
if( !addr )
{
cout<<"Error address\n";
return 1;
}
sockaddr_in address;
memset( (char*)&address, 0, sizeof(address) );
address.sin_family = AF_INET;
address.sin_port = htons( m_Port );
address.sin_addr.s_addr = addr->s_addr;
m_Sock = socket( AF_INET, SOCK_STREAM, 0 );
if(m_Sock<0){
cout<<"Socket error\n";
return 1;
}
if( ::connect( m_Sock, (sockaddr const*)&address, sizeof(address) ) < 0 )
{
cout<<"connect error";
return 1;
}
buf = (char*)buffer.c_str();
numbytes = buffer.length();
while( numbytes > 0 )
{
int n = ::send( m_Sock, buf, buffer.size(), 0 );
std::cout<<"\n\n--HTTP request:\n"<<buf<<std::endl;
if( n<0 )
{
cout<<"number of bytes sent <0\n";
return 1;
}
numbytes -= n;
buf += n;
}
cout<<"\ngetting response: \n";
unsigned char recvBuf[ 2048 ];
int a;
do{
a = recv( m_Sock, (char*)recvBuf, sizeof(recvBuf), 0 );
fwrite(recvBuf, 1, a, stdout);
}while(a!=0);
if(m_Sock>0)
close(m_Sock);
return 0;
}
I always get a response like:
HTTP/1.1 404 Not Found
Date: Sun, 16 Mar 2014 13:40:10 GMT
Server: Apache/2.2.22 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 294
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /announce was not found on this server.</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at bttracker.debian.org Port 6969</address>
</body></html>
I tried with POSTMAN extension from Google Chrome to make the same request and i get a response like:
d8:completei12e10:incompletei1e8:intervali1800e5:peers18:[�_�����4&N=;8��e
which is what i'm expecting to see when making the request from my C code. What am i doing wrong?
Upvotes: 1
Views: 646
Reputation: 188
I used Wireshark (thanks to an old friend advise) for getting the request sent by POSTMAN. Here is the code that worked for me:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> // for gethostbyname()
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
using namespace std;
// Try to work out address from string
// returns 0 if bad
struct in_addr *atoaddr( const char* address)
{
static struct hostent *host;
static struct in_addr saddr;
// First try nnn.nnn.nnn.nnn form
saddr.s_addr = inet_addr(address);
if (saddr.s_addr != -1)
return &saddr;
host = gethostbyname(address);
if( host )
return (struct in_addr *) *host->h_addr_list;
return 0;
}
int main(){
int numbytes=0;
int m_Port=6969;
string m_Host="torrent.ubuntu.com";
int m_Sock;
struct hostent *host;
static struct in_addr saddr;
string buffer;
char* buf;
// HTTP request string
// buffer.append("GET /announce HTTP/1.1\r\n");
// buffer.append("Host: torrent.ubuntu.com:6969\r\n");
// buffer.append("Accept-Encoding: identity\r\n");
// buffer.append("info_hash: %36%be%21%35%ab%cc%f4%03%2f%bb%28%bb%1b%0d%4f%da%f7%49%f8%58\r\n");
// buffer.append("peer_id: ABCDEFGHIJKLMNOPQRST\r\n");
// buffer.append("port: 6881\r\n");
// buffer.append("uploaded: 0\r\n");
// buffer.append("downloaded: 0\r\n");
// buffer.append("left: 987758592\r\n");
// buffer.append("compact: 1\r\n");
// buffer.append("event: started\r\n");
buffer.append("GET /announce?info_hash=%36%be%21%35%ab%cc%f4%03%2f%bb%28%bb%1b%0d%4f%da%f7%49%f8%58&"
"peer_id=ABCDEFGHIJKLMNOPQRST&"
"port=6881&"
"compact=1&"
"uploaded=0&"
"downloaded=0&"
"left=987758592&"
"event=started HTTP/1.1\r\n");
buffer.append("\r\n");
in_addr* addr = atoaddr( m_Host.c_str() );
if( !addr )
{
cout<<"Error address\n";
return 1;
}
sockaddr_in address;
memset( (char*)&address, 0, sizeof(address) );
address.sin_family = AF_INET;
address.sin_port = htons( m_Port );
address.sin_addr.s_addr = addr->s_addr;
m_Sock = socket( AF_INET, SOCK_STREAM, 0 );
if(m_Sock<0){
cout<<"Socket error\n";
return 1;
}
if( ::connect( m_Sock, (sockaddr const*)&address, sizeof(address) ) < 0 )
{
cout<<"connect error";
return 1;
}
buf = (char*)buffer.c_str();
numbytes = buffer.length();
while( numbytes > 0 )
{
int n = ::send( m_Sock, buf, buffer.size(), 0 );
std::cout<<"\n\n--HTTP request:\n"<<buf<<std::endl;
if( n<0 )
{
cout<<"number of bytes sent <0\n";
return 1;
}
numbytes -= n;
buf += n;
}
cout<<"\ngetting response: \n";
unsigned char recvBuf[ 2048 ];
int a;
do{
a = recv( m_Sock, (char*)recvBuf, sizeof(recvBuf), 0 );
fwrite(recvBuf, 1, a, stdout);
}while(a!=0);
cout<<"\n";
if(m_Sock>0)
close(m_Sock);
return 0;
}
Upvotes: 0
Reputation: 1975
I believe your code fails because you made a small mistake: instead of connecting your socket to port 80, you should be connecting to port 6969 and then send a GET /announce
query, instead of sending full URL in the GET
method.
Upvotes: 1