HTTP GET problems - http

I'm trying to send GET request to generate receiving address (Blockchain api, https://blockchain.info/ru/api/api_receive)
On the page i've generated request - "
/api/receive?method=create&cors=true&format=plain&address=1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq&shared=false&callback=http%3A%2F%2Fgoogle.com
and need to receive an answer -
{"callback_url":"http://google.com","input_address":"16ofW1jBBLbVnDQWJsyL6NKq7hKms9tDLP","destination":"1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq","fee_percent":0}"
I found sample code and trying to send request
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *host;
host = gethostbyname("www.google.com");
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
std::cout << "Connecting...\n";
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0){
std::cout << "Could not connect";
return -1;
}
std::cout << "Connected.\n";
send(Socket, "GET /api/receive?method=create&cors=true&format=plain&address=1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq&shared=false&callback=http://microsoft.com/ HTTP/1.1\r\nHost: blockchain.info\r\nConnection: close\r\n\r\n", strlen("GET /api/receive?method=create&cors=true&format=plain&address=1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq&shared=false&callback=http://microsoft.com/ HTTP/1.1\r\nHost: blockchain.info\r\nConnection: close\r\n\r\n"), 0);
char buffer[10000];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0){
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
std::cout << buffer[i];
i += 1;
}
}
closesocket(Socket);
return 1;
}
but receive 404 error. What is the problem and what is the best way to parse an answer (I need to get "input_address")? Thanks for help!

Related

Why 10049 error occurs in udp communication even though ip and port are entered correctly

DWORD WINAPI socketRead(void *lpVoid)
{
while (true)
{
// UDP socket
WSADATA data_s;
WORD version = MAKEWORD(2, 2);
// socket start
int wsok = WSAStartup(version, &data_s);
if (wsok != 0)
{
cout << "Can't start Winsock!" << wsok;
return 0;
}
else
{
cout << "start Winsock!\n";
}
// socket bind
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN serverHint = {};
memset(&serverHint, 0, sizeof(serverHint));
serverHint.sin_family = AF_INET; // IPv4
serverHint.sin_addr.S_un.S_addr = inet_addr("192.168.0.69");
serverHint.sin_port = htons(1480);
if (bind(in, (sockaddr *)&serverHint, sizeof(serverHint)) != SOCKET_ERROR)
{
cout << "bind socket!\n";
}
else
{
cout << "can't bind socket!" << WSAGetLastError() << endl;
// socket clean
int wsokE = WSACleanup();
if (wsokE != 0)
{
cout << "Can't cleanup Winsock!" << wsokE;
}
else
{
cout << "cleanup Winsock!\n";
}
// return 0;
}
}
this is my code. I want to do UDP socket communication using winsocket.
It is trying to do udp communication with another computer.
However, I keep getting error 10049 even though I wrote down the ip address and port number correctly.
The 1480 port I wrote down in the code is what I set arbitrarily. Do I need to do other processing on the computer?
When I use the same ip and port in the incoming and outgoing confirmation program called Ezterm, the values ​​come normally.
In conclusion, we want to receive data from "192.168.0.69".

C++ non-blocking TCP Server cannot send a message with more bytes than it received

I'm pretty new to network programing. I've written a simple non-blocking TCP Server using winsock2 but it behaves in a weird way that I couldn't find any example of it in previously asked questions.
My server can only send a message with as many bytes as it previously received. For example, if previously it received a "rec_msg", when I try to send "message_to_send" it only sends "message".
I don't if it has any effect but the server is encapsulated with a pure static class. Here are the function via a recieve and send message:
int TCPServer_Test::receiveMessage(){
while(1)
{
memset(recvbuf, 0, DEFAULT_BUFLEN);
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
int err = WSAGetLastError();
int counter = 0;
if (iResult > 0)
{
std::cout << "Mesaj Alindi: " << recvbuf << std::endl;
break;
}
else if(err == WSAEWOULDBLOCK)
{
Sleep(200);
continue;
}
else if (iResult == 0){
printf("Connection closing...\n");
return -1;
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
}
}
void TCPServer_Test::sendMessage(char* Source){
strncpy(recvbuf, Source, DEFAULT_BUFLEN);
iSendResult = send( ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
else if (iSendResult == 0) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
else
{
printf("Bytes sent: %d\n", iSendResult);
}
memset(recvbuf, 0, sizeof(recvbuf));
}
I would appreciate any help directly related or not.
It looks like it happens because you are using iResult variable that contains amount of data received during previous recv call when sending data instead of supplying real size of the data to be sent like this:
size_t bytes_count_to_be_send = strlen(Source);
iSendResult = send( ClientSocket, Source, bytes_count_to_be_send, 0);
Also notice that there is no real need to copy data into buffer.

TCP - Identity of timed out client

I want to know the identity of the timed out client ?
how ?
if the function that will receive data like this ..How can I know the client ID ?
your help will be greatly appreciated
Thank you :)
DWORD WINAPI Server::ClientThread(LPVOID lpParam)
{
char receivedData[BUFFER_SIZE];
ThreadData myThreadData = *(ThreadData*)lpParam;
while (1)
{
int returnValue;
// Perform a blocking recv() call
returnValue = recv(myThreadData.clientSocket, receivedData, BUFFER_SIZE, 0);
if (returnValue == 0)
break;
else if (returnValue == SOCKET_ERROR)
{
cout << "recv() failed - Error Code : " << WSAGetLastError() << endl;
}
else
{
receivedData[returnValue] = '\0';
cout << "I am the server and received " << receivedData << endl;
UnderstandComingMessage(receivedData, myThreadData);
}
}
}
I don't know what you mean by 'identity', but you can get the peer IP address and port by calling getpeername() on the socket.

Can't receive the response package by winsock2 from http server

I'm sure my program has got the ip from the server by the url.
When I send the GET request, although it was successfully send, it couldn't get the response. I'm not sure if the server had gotten my request, how should I check if the server get my request?
The connection will close after sending a request and waiting for a period of time . The "recv" function will response 0, and the buffer get nothing.
I wonder if there are any error of my "sendbuf = GET / HTTP/1.1\r\n\r\n".
Should I use 1.1 or 1.0?
char *sendbuf = "GET / HTTP/1.1\r\n\r\n";
//to get the ip from DNS server
pHostEnt = gethostbyname( "www.google.com.tw");
ppaddr = (int**)pHostEnt->h_addr_list;
sockAddr.sin_addr.s_addr = **ppaddr;
printf("%s",inet_ntoa(sockAddr.sin_addr) );
//to create the socket and connect to it
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(inet_ntoa(sockAddr.sin_addr));
serverAddress.sin_port = htons(SERVER_PORT);
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
connect(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress));
//send request
int iResult = send( serverSocket, sendbuf, (int)strlen(sendbuf), 0 );
//get response
if (bytesRead=recv(serverSocket, buf, MAX_SIZE, 0) < 0)
printf("Error with send()");
else
printf("Successfully sent html fetch response");
Using HTTP 1.1 is fine, but your request is incomplete as HTTP 1.1 requires the Host header, at the very least (in order for servers to support virtual hosts).
More importantly, you are not doing any error handling. You need to do that.
You are also not taking into account that gethostname() can return multiple IP addresses. You need to connect() to each address until one succeeds, or until you exhaust the list.
Try this:
char *sendbuf = "GET / HTTP/1.1\r\nHost: www.google.com.tw\r\n\r\n";
//to get the ip from DNS server
pHostEnt = gethostbyname( "www.google.com.tw"); // you should be using getaddrinfo() instead!
if (!pHostEnd)
{
printf("Unable to resolve www.google.com.tw\n");
return; // or whatever...
}
if (pHostEnt->h_addrtype != AF_INET)
{
printf("www.google.com.tw did not resolve to an IPv4 IP address\n");
return; // or whatever...
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
printf("Unable to create socket\n");
return; // or whatever...
}
in_addr **ppaddr = (in_addr**) pHostEnt->h_addr_list;
sockaddr_in serverAddress = {0};
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(SERVER_PORT);
bool connected = false;
int i = 0;
while (ppadd[i] != NULL)
{
// connect to server
serverAddress.sin_addr = *(ppaddr[i]);
printf("Connecting to %s\n", inet_ntoa(serverAddress.sin_addr);
if (connect(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == 0)
{
connected = true;
break;
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(serverSocket, &writefds);
timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (select(0, NULL, &writefds, NULL, &timeout) > 0)
{
connected = true;
break;
}
}
++i;
}
if (!connected)
{
printf("Unable to connect to www.google.com.tw\n");
return; // or whatever...
}
printf("Connected, sending request\n");
//send request
char *ptr = sendbuf;
int len = strlen(sendbuf);
do
{
int bytesSent = send( serverSocket, ptr, len, 0 );
if (bytesSent > 0)
{
ptr += bytesSent;
len -= bytesSent;
continue;
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(serverSocket, &writefds);
timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (select(0, NULL, &writefds, NULL, &timeout) > 0)
continue;
}
printf("Unable to send request\n");
return; // or whatever...
}
while (len > 0);
printf("Reading response\n");
//get response
do
{
int bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
if (bytesRead > 0)
{
// process buf as needed...
// make sure you are paying attention to the
// Content-Length and Transfer-Encoding headers,
// as they tell you how to read the response.
// Refer to RFC 2616 Section 4.4 for details...
contine;
}
if (bytesRead == 0)
{
printf("Disconnected");
return; // or whatever...
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(serverSocket, &readfds);
timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (select(0, &readfds, NULL, NULL, &timeout) > 0)
continue;
}
printf("Unable to read response\n");
return; // or whatever...
}
while (true);
closesocket(serverSocket);

Why recv() in winsock client cannot get any data once httpRetransmition happens?

I am trying to record the time between 'http request' package and 'http response' package.
I write an socket client using winsock. The code is below
if (send(sock, request.c_str(), request.length(), 0) != request.length())
die_with_error("send() sent a different number of bytes than expected");
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
response = "";
resp_leng= BUFFERSIZE;
http_leng= 381;
while(resp_leng==BUFFERSIZE||http_leng>0)
{
resp_leng= recv(sock, (char*)&buffer, BUFFERSIZE, 0);
http_leng= http_leng - resp_leng;
if (resp_leng>0)
response+= string(buffer).substr(0,resp_leng);
//note: download lag is not handled in this code
}
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
The code works nicely except one situation: HTTP Retransmition. I used wireshark to monitor packages and found out once there is a retransmition the code seems block on recv(), but cannot get any data from the socket buffer. I wonder why would this happen. Could somebody explain the reasons?
Any help will be appreciated.
Here is a second answer with more dynamic buffer handling and more error checking:
void send_data(SOCKET sock, void *data, unsigned int data_len)
{
unsigned char *ptr = (unsigned char*) data;
while (data_len > 0)
{
int num_to_send = (int) std::min(1024*1024, data_len);
int num_sent = send(sock, ptr, num_to_send, 0);
if (num_sent < 0)
{
if ((num_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
if (num_sent == 0)
die_with_error("socket disconnected");
ptr += num_sent;
data_len -= num_sent;
}
}
unsigned int recv_data(SOCKET sock, void *data, unsigned int data_len, bool error_on_disconnect = true)
{
unsigned char *ptr = (unsigned char*) data;
unsigned int total = 0;
while (data_len > 0)
{
int num_to_recv = (int) std::min(1024*1024, data_len);
int num_recvd = recv(sock, ptr, num_to_recv, 0);
if (num_recvd < 0)
{
if ((num_recvd == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("recv() failed");
}
if (num_recvd == 0)
{
if (error_on_disconnect)
die_with_error("socket disconnected");
break;
}
ptr += num_recvd;
datalen -= num_recvd;
total += num_recvd;
}
while (true);
return total;
}
std::string recv_line(SOCKET sock)
{
std::string line;
char c;
do
{
recv_data(sock, &c, 1);
if (c == '\r')
{
recv_data(sock, &c, 1);
if (c == '\n')
break;
line += '\r';
}
else if (c == '\n')
break;
line += c;
}
return line;
}
void recv_headers(SOCKET sock, std::vector<std::string> *hdrs)
{
do
{
std::string line = recv_line(sock);
if (line.length() == 0)
return;
if (hdrs)
hdrs->push_back(line);
}
while (true);
}
unsigned int recv_chunk_size(SOCKET sock)
{
std::string line = recv_line(sock);
size_t pos = line.find(";");
if (pos != std::string::npos)
line.erase(pos);
char *endptr;
unsigned int value = strtoul(line.c_str(), &endptr, 16);
if (*endptr != '\0')
die_with_error("bad Chunk Size received");
return value;
}
std::string find_header(const std::vector<std::string> &hrds, const std::string &hdr_name)
{
std::string value;
for(size_t i = 0; i < hdrs.size(); ++i)
{
const std::string hdr = hdrs[i];
size_t pos = hdr.find(":");
if (pos != std::string::npos)
{
if (hdr.compare(0, pos-1, name) == 0)
{
pos = hdr.find_first_not_of(" ", pos+1);
if (pos != std::string::npos)
return hdr.substr(pos);
break;
}
}
}
return "";
}
{
// send request ...
std::string request = ...;
send_data(sock, request.c_str(), request.length());
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
// get response ...
std::vector<std::string> resp_headers;
std::vector<unsigned char> resp_data;
recv_headers(sock, &resp_headers);
std::string transfer_encoding = find_header(resp_headers, "Transfer-Encoding");
if (transfer_encoding.find("chunked") != std::string::npos)
{
unsigned int chunk_len = recv_chunk_size(sock);
while (chunk_len != 0)
{
size_t offset = resp_data.size();
resp_data.resize(offset + chunk_len);
recv_data(sock, &resp_data[offset], chunk_len);
recv_line(sock);
chunk_len = recv_chunk_size(sock);
}
recv_headers(sock, NULL);
}
else
{
std::string content_length = find_header(resp_headers, "Content-Length");
if (content_length.length() != 0)
{
char *endptr;
unsigned int content_length_value = strtoul(content_length.c_str(), &endptr, 10);
if (*endptr != '\0')
die_with_error("bad Content-Length value received");
if (content_length_value > 0)
{
resp_data.resize(content_length_value);
recv_data(sock, &resp_data[0], content_length_value);
}
}
else
{
unsigned char buffer[BUFFERSIZE];
do
{
unsigned int buffer_len = recv_data(sock, buffer, BUFFERSIZE, false);
if (buffer_len == 0)
break;
size_t offset = resp_data.size();
resp_data.resize(offset + buffer_len);
memcpy(&resp_data[offset], buffer, buffer_len);
}
while (true)
}
}
::QueryPerformanceCounter(&httpResponseGot);
// process resp_data as needed
// may be compressed, encoded, etc...
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
}
You are not doing adequate error checking on the calls to send() and recv(). Try something like this instead:
char *req_ptr = request.c_str();
int req_leng = request.length();
int req_index = 0;
do
{
int req_sent = send(sock, req_ptr, req_leng, 0);
if (req_sent < 1)
{
if ((req_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
req_ptr += req_sent;
req_leng -= req_sent;
}
while (req_leng > 0);
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
std::string response;
int resp_leng = BUFFERSIZE;
int http_leng = -1;
bool http_leng_needed = true;
do
{
if (http_leng_needed)
{
std::string::size_type pos = response.find("\r\n\r\n");
if (pos != std::string::npos)
{
std::string resp_hdrs = response.substr(0, pos);
// look for a "Content-Length" header to see
// if the server sends who many bytes are
// being sent after the headers. Note that
// the server may use "Transfer-Encoding: chunked"
// instead, which has no "Content-Length" header...
//
// I will leave this as an excercise for you to figure out...
http_leng = ...;
// in case body bytes have already been received...
http_leng -= (response.length() - (pos+4));
http_leng_needed = false;
}
}
if (http_leng_needed)
resp_leng = BUFFERSIZE;
else
resp_leng = min(http_leng, BUFFERSIZE);
if (resp_leng == 0)
break;
resp_leng = recv(sock, buffer, resp_leng, 0);
if (resp_leng < 1)
{
if ((resp_leng == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
response += string(buffer, resp_leng);
if (!http_leng_needed)
http_leng -= resp_leng;
}
while ((http_leng_needed) || (http_leng > 0));
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
With this said, the "correct" way to handle HTTP in general is to read the inbound data line by line, rather than buffer by buffer, until you encounter the end of the response headers, then you can read the rest of the data buffer by buffer based on the data length indicated by the headers.

Resources