How do I use the winhttp api with "transfer-encoding: chunked" - c++

I'm trying to send some data to a web service which requires the "Transfer-encoding: chunked" header. It works fine with a normal POST request.
But as soon as I add the header, I always get:
The content could not be delivered due to the following condition:
Received invalid request from client
This is the part where the request is sent:
std::vector<std::wstring> m_headers;
m_headers.push_back(TEXT("Transfer-encoding: chunked"));
std::wstring m_verb(TEXT("POST"));
std::vector<unsigned __int8> m_payload;
HINTERNET m_connectionHandle = WinHttpConnect(m_http->getSessionHandle(), hostName.c_str(), m_urlParts.nPort, 0);
if (!m_connectionHandle) {
std::cout << "InternetConnect failed: " << GetLastError() << std::endl;
return;
}
__int32 requestFlags = WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH;
HINTERNET m_requestHandle = WinHttpOpenRequest(m_connectionHandle, m_verb.c_str(), (path + extra).c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, requestFlags);
if(!m_requestHandle) {
std::cout << "HttpOpenRequest failed: " << GetLastError() << std::endl;
return;
}
for(auto header : m_headers) {
if(!WinHttpAddRequestHeaders(m_requestHandle, (header + TEXT("\r\n")).c_str(), -1, WINHTTP_ADDREQ_FLAG_ADD)) {
std::cout << "WinHttpAddRequestHeaders failed: " << GetLastError() << std::endl;
return;
}
}
if(!WinHttpSendRequest(m_requestHandle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, (DWORD_PTR)this)) {
std::cout << "HttpSendRequest failed: " << GetLastError() << std::endl;
return;
}
unsigned chunkSize = 1024;
unsigned chunkCount = m_payload.size() / chunkSize;
char chunksizeString[128];
for (unsigned i = 0; i <= chunkCount; i++) {
unsigned actualChunkSize = std::min<unsigned>(chunkSize, m_payload.size() - i * chunkSize);
sprintf_s(chunksizeString, "%d\r\n", actualChunkSize);
if (!WinHttpWriteData(m_requestHandle, chunksizeString, strlen(chunksizeString), (LPDWORD)&m_totalBytesWritten)) {
std::cout << "HttpWriteData failed: " << GetLastError() << std::endl;
return;
}
if (!WinHttpWriteData(m_requestHandle, m_payload.data() + i * chunkSize, actualChunkSize, (LPDWORD)&m_totalBytesWritten)) {
std::cout << "HttpWriteData failed: " << GetLastError() << std::endl;
return;
}
}
// terminate chunked transfer
if (!WinHttpWriteData(m_requestHandle, "0\r\n", strlen("0\r\n"), (LPDWORD)&m_totalBytesWritten)) {
std::cout << "HttpWriteData failed: " << GetLastError() << std::endl;
return;
}
if(!WinHttpReceiveResponse(m_requestHandle, NULL)) {
std::wcout << "HttpReceiveResponse failed: " << GetLastError() << std::endl;
return;
}
I had to copy it from different files, so I hope I got all the important variable definitions. Right now I only use it synchronously since I thought it easier to debug.
As it works with normal POST requests (where I just use WinHttpSendRequest with the payload) I'm guessing it must have to do with the way I use WinHttpSendRequest & WinHttpWriteData, I just don't see how else it should be used.
Any help is appreciated!

You need to split data into chunks manually like this:
int chunkSize = 512; // can be anything
char chunkSizeString[128]; // large enough string buffer
for (int i=0; i<chunksCount; ++i) {
int actualChunkSize = chunkSize; // may be less when passing the last chunk of data (if that's not a multiple of chunkSize)
sprintf(chunkSizeString, "%d\r\n", actualChunkSize);
WinHttpWriteData(m_requestHandle, chunkSizeString, strlen(chunkSizeString), (LPDWORD)&m_totalBytesWritten);
WinHttpWriteData(m_requestHandle, m_payload.data() + i*chunkSize, actualChunkSize, (LPDWORD)&m_totalBytesWritten);
}
WinHttpWriteData(m_requestHandle, "0\r\n", strlen("0\r\n"), (LPDWORD)&m_totalBytesWritten); // the last zero chunk, end of transmission

Thanks to the link provided by #anton-malyshev I was able to find the solution, I just replaced all calls to WinHttpWriteData above with this:
/* Chunk header */
char chunksizeString[64];
sprintf_s(chunksizeString, "%X\r\n", m_payload.size());
if (!WinHttpWriteData(m_requestHandle, chunksizeString, strlen(chunksizeString), (LPDWORD)&m_totalBytesWritten)) {
std::wcout << "WinHttpWriteData chunk header failed: " << getHttpErrorMessage(GetLastError()) << std::endl;
return;
}
/* Chunk body */
if (!WinHttpWriteData(m_requestHandle, m_payload.data(), m_payload.size(), (LPDWORD)&m_totalBytesWritten)) {
std::wcout << "WinHttpWriteData chunk body failed: " << getHttpErrorMessage(GetLastError()) << std::endl;
return;
}
/* Chunk footer */
if (!WinHttpWriteData(m_requestHandle, "\r\n", 2, (LPDWORD)&m_totalBytesWritten)) {
std::wcout << "WinHttpWriteDatachunk footer failed: " << getHttpErrorMessage(GetLastError()) << std::endl;
return;
}
/* Terminate chunk transfer */
if (!WinHttpWriteData(m_requestHandle, "0\r\n\r\n", 5, (LPDWORD)&m_totalBytesWritten)) {
std::wcout << "WinHttpWriteData chunk termination failed: " << getHttpErrorMessage(GetLastError()) << std::endl;
return;
}

Related

UDP Packets coming in with wrong formatting

I'm currently working to get some software that is currently running on windows ported over to ubuntu. One aspect of this software handles udp packets with the location of some of our assets using SFML. For some reason after moving OS's the packets are coming in as U� (always with the � symbol.) is this a posix problem? Here is the code I was using:
int32_t
SocketUdpClient::recv(std::string *data)
{
sf::Socket::Status recvStatus = sf::Socket::Error;
if( m_bOpen && data != NULL )
{
char buf[4096];
std::size_t bytesRead;
sf::IpAddress senderIp;
uint16_t senderPort;
recvStatus = m_socket.receive( buf, 4096, bytesRead, senderIp, senderPort );
if (recvStatus == sf::Socket::Done)
{
std::cout << "Received " << bytesRead << " bytes from " << senderIp << " on port " << senderPort << std::endl;
std::cout << buf <<std::endl;
m_senderIp = senderIp.toString();
if (m_listenAll)
{
m_peerIp = senderIp.toString();
printf("SocketUdpClient::recvfrom m_senderIp = %s, m_peerIp = %s\n", m_senderIp.c_str(), m_peerIp.c_str());
}
if (m_senderIp.compare(m_peerIp) == 0)
{
*data = std::string(buf, bytesRead);
return bytesRead;
//return senderIp.toString();
}
}
else if (recvStatus == sf::Socket::NotReady)
{
return 0;
}
}
return -1;
}
Change this:
recvStatus = m_socket.receive( buf, 4096, bytesRead, senderIp, senderPort );
if (recvStatus == sf::Socket::Done)
{
std::cout << "Received " << bytesRead << " bytes from " << senderIp << " on port " << senderPort << std::endl;
std::cout << buf <<std::endl;
To this:
bytesRead = 0; // always a good idea
recvStatus = m_socket.receive( buf, 4095 /* 1 less than buffer size*/, bytesRead, senderIp, senderPort );
if (recvStatus == sf::Socket::Done)
{
std::cout << "Received " << bytesRead << " bytes from " << senderIp << " on port " << senderPort << std::endl;
buf[bytesRead] = '\0'; // null terminate
std::cout << buf <<std::endl;

pipe() and fork() example: basic_string::M_construct null not valid

Another try with getting parallel processes to work. Please excuse the amount of code but every attempt to shorten it makes the error vanish.
What I tested so far:
sending int from parent to child, from child to parent, and from parent to child and then back: works
processing a list of int: send from parent to child, modify and back to parent: works
more data: int + string, from parent to child, modify and back to parent: works
a list of data the same way: works
But when I run the same function that works a second time it always fail.
This is the function that creates the child process:
//parent sends binary data from list to child which sends back modified data
bool processParallel6(std::vector<std::pair<int, std::string>> & data)
{
//define pipe
int parent2Child[2];
int child2Parent[2];
//create pipe
pipe(parent2Child);
pipe(child2Parent);
//fork
pid_t child = fork();
if(child == 0) //child process
{
//close not needed end of pipe
close(parent2Child[1]);
close(child2Parent[0]);
for(;;)
{
struct pollfd pfd;
pfd.fd = parent2Child[0];
pfd.events = POLLIN;
//wait until data is available at the pipe
cout << "c: poll ..." << endl;
if(poll(&pfd, 1, -1) < 0)
{
cout << "c: poll: " << strerror(errno) << endl;
exit(-1);
}
cout << "c: poll says there are data" << endl;
if((pfd.revents&POLLIN) == POLLIN)
{
int data;
std::string text;
if(!readData3(parent2Child[0], data, text))
exit(-2);
cout << "c: data received: " << data << " " << text << endl;
if(data == -1)
break;
if(!writeData3(child2Parent[1], data * 2, text + text))
exit(-3);
cout << "c: sent data to parent: " << 2 * data << " " << text + text << endl;
}
}
close(parent2Child[0]);
close(child2Parent[1]);
exit(0);
}
else //parent process
{
//close not needed end of pipe
close(parent2Child[0]);
close(child2Parent[1]);
//send data to child
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
//read result from child
for(;;)
{
struct pollfd pfd;
pfd.fd = child2Parent[0];
pfd.events = POLLIN;
//wait until data is available at the pipe
cout << "p: poll ..." << endl;
if(poll(&pfd, 1, -1) < 0)
{
cout << "p poll: " << strerror(errno) << endl;
return false;
}
cout << "p: poll says there are data" << endl;
if((pfd.revents&POLLIN) == POLLIN)
{
int data;
std::string text;
if(!readData3(child2Parent[0], data, text))
return false;
cout << "p: data received: " << data << " " << text << endl;
}
if(data.empty())
break;
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
}
//send stop data
if(!writeData3(parent2Child[1], -1, "notext"))
return false;
cout << "p: sent stop data " << endl;
//wait for child to end
wait(nullptr);
//close all pipes
close(parent2Child[1]);
close(child2Parent[0]);
}
return true;
}
For reading and writing data I use this two functions:
bool readData3(int fd, int & number, std::string & text)
{
char numberBuf[sizeof(int)];
int bytesRead = read(fd, numberBuf, sizeof(int));
if(bytesRead > 0)
{
number = *(int *)numberBuf;
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
char sizeBuf[sizeof(int)];
int size = -1;
bytesRead = read(fd, sizeBuf, sizeof(int));
if(bytesRead > 0)
{
size = *(int *)sizeBuf;
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
char textBuf[size];
bytesRead = read(fd, textBuf, size);
if(bytesRead > 0)
{
text = std::string(textBuf);
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
return true;
}
bool writeData3(int fd, const int number, const std::string text)
{
int bytesWritten = write(fd, &number, sizeof(int));
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
int size = text.size() + 1;
bytesWritten = write(fd, &size, sizeof(int));
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
bytesWritten = write(fd, text.c_str(), size);
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
return true;
}
Finally I run it like this:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <bitset>
#include <memory>
#include <poll.h>
#include <cstring>
using namespace std;
int main(int /*argc*/, char* /*argv*/[])
{
std::vector<std::pair<int, std::string>> data;
data.push_back(std::make_pair(1, "one"));
data.push_back(std::make_pair(2, "two"));
cout << "6a ########################################################" << endl << flush;
processParallel6(data);
cout << "6b ########################################################" << endl << flush;
processParallel6(data);
return 0;
}
This is the output:
6a ###############################################
p: wrote data: 2 two
p: poll ...
c: poll ...
c: poll says there are data
c: data received: 2 two
p: poll says there are data
p: data received: 4 twotwo
p: wrote data: 1 one
p: poll ...
c: sent data to parent: 4 twotwo
c: poll ...
c: poll says there are data
c: data received: 1 one
p: poll says there are data
p: data received: 2 oneone
p: sent stop data
c: sent data to parent: 2 oneone
c: poll ...
c: poll says there are data
c: data received: -1 notext
6b ###################################################
c: poll ...
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
c: poll says there are data
c: poll ...
c: poll says there are data
c: poll ...
The last 4 lines are repeated a thousands of times. This output comes most of the times, but sometimes I have seen a std::bad_alloc error. When I try strace it crashes too, but when it runs I have seen directly after the second run of processParallel6() a line with mmap, ENOEM and 'Cannot allocate memory'
What happens here? Why is it working the first time, but not the second time?
You attempting to copy an invalid std::string reference.
std::terminate is getting called in the constructor of std::string. The constructor is implicitly called in processParallel6 when calling writeData3:
bool writeData3(int fd, const int number, const std::string text)
...
//send data to child
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
You are expecting that data.back().second is a valid string reference, but nothing in the code ensures that is the case.
You construct data and place two entries in it:
data.push_back(std::make_pair(1, "one"));
data.push_back(std::make_pair(2, "two"));
In the first call to processParallel6 you run the following block of code twice:
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
At this point data is empty. You cannot make another call to processParallel6 because it expects that data contains at least one element.

list/vector iterator not incrementable

So I have an issue trying to iterate through my container in c++ with visual studio Community 2015.
I'm trying to write a server/client on windows using select() and I get the error:
vector iterator not incrementable
I'm not calling a vector::erase() or such, although I do use a vector::push_back()
void MGKServer::mainLoop()
{
MGKServerSocket *mgk;
std::vector<User *> users;
int actual = 0;
char buffer[1024];
mgk = new WindowsServerSocket();
mgk->init("127.0.0.1", 4242, "TCP");
int sock = mgk->getSock();
std::cout << "sock is: " << mgk->getSock() << std::endl;
while (1)
{
this->setFd(sock, &users); // FD_ZERO(&_readfd) and FD_SET for each user's socket and the server socket
std::cout << "there is currently " << users.size() << " user(s) connected" << std::endl;
if (select(FD_SETSIZE + 1, &this->_readfd, NULL, NULL, NULL) == -1)
exit(errno);
// When a user connects
if (FD_ISSET(sock, &this->_readfd))
{
// addNewUser creates a pointer to an object User , set his socket to the given one and push it in the vector
if (this->addNewUser(sock, &users) == -1)
std::cout << "Can't add newUser" << std::endl;
}
// When a user sends a message to the server
else
{
int debug = 0;
std::vector<User *>::iterator it = users.begin();
while (it != users.end())
{
if (it == users.end())
std::cout << "Test if something went wrong with iterations" << std::endl;
if (FD_ISSET((*it)->getSocket(), &this->_readfd))
{
// RecvUser will just call recv with the client socket and store the message in buffer.
int c = mgk->recvUser((*it)->getSocket(), buffer);
// Means the user disconnected so i close his socket
if (c == 0)
{
std::cout << "user with socket: " << (*it)->getSocket() << "disconnected" << std::endl;
closesocket((*it)->getSocket());
}
// Means he sends an instruction
else
std::cout << "ok" << std::endl;
}
std::cout << "Debug = " << debug << std::endl;
++debug;
it++; // <- This small line seems to be the problem
}
std::cout << "Out of For loop" << std::endl;
}
std::cout << "found something on socket" << std::endl;
}
}
here is what i do in addNewUser:
int MGKServer::addNewUser(int socket, std::vector<User *> *users)
{
std::cout << "----NEW USER----" << std::endl;
SOCKADDR_IN usin = { 0 };
User *u;
int size;
int usock;
size = sizeof(usin);
std::cout << "New user is trying to connect, socket is: ";
usock = accept(socket, (SOCKADDR *)&usin, &size);
if (usock == SOCKET_ERROR)
{
std::cout << "socket error occured" << std::endl;
return (-1);
}
std::cout << usock << std::endl;
FD_SET(usock, &this->_readfd);
u = new User();
u->setSocket(usock);
users->push_back(u);
return (0);
}
My object User only contains a socket with get&set methods for now.
My MGKServerSocket is just an abstration for windows/linux socket. It contain basic function for initializing my socket and send & recv data to users.
So at first I had a list container but I've got the same error. So I switched to try with vector instead but nothing changed.
In the beginning, I also used a for loop instead of my current while loop but, once again, nothing changed.
I know that there's already many questions for this error, but they usually use erase, insert inside the for loop or create the iterator when the list is empty which I don't. So my question is, why do I get this error ?

Connecting to an IRC server, getting Ping timeout without receiving PING message

I'm trying my hands at network programming for the first time, implementing a small IRC bot using the SFML network functionality.
The connection gets established, but from there on I can't do much else. Trying to receive any data from the server yields nothing, until I get the "Ping timeout" message after a few seconds.
Removing all or some of the receive() calls in the loginOnIRC function doesn't do any good.
Trying to connect via telnet with the exact same messages works. Here I get a PING message right after sending my NICK message.
Am I missing something?
My code is as follows
#include <iostream>
#include <string>
#include <SFML/Network.hpp>
#define ARRAY_LEN(x) (sizeof(x)/sizeof(*x))
void receive(sf::TcpSocket* sck)
{
char rcvData[100];
memset(rcvData, 0, ARRAY_LEN(rcvData));
std::size_t received;
if (sck->receive(rcvData, ARRAY_LEN(rcvData), received) != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << rcvData << std::endl;
}
int establishConnection(sf::TcpSocket* sck)
{
sf::Socket::Status status = sck->connect("irc.euirc.net", 6667, sf::seconds(5.0f));
if (status != sf::Socket::Done)
{
std::cout << "Error on connect!" << std::endl;
return 1;
}
std::cout << "Connect was successful!" << std::endl;
return 0;
}
int loginOnIRC(sf::TcpSocket* sck)
{
receive(sck); // We get a Ping timeout here
std::string data{ "NICK NimBot" };
if(sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "USER NimBot * * :Nimelrians Bot";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
receive(sck);
data = "JOIN #nimbottest";
if (sck->send(data.c_str(), data.length()) != sf::Socket::Done)
{
std::cout << "Error on sending " << data << std::endl;
return 1;
}
return 0;
}
int main()
{
sf::TcpSocket sck{};
establishConnection(&sck); // works
loginOnIRC(&sck);
while(true)
{
char data[100];
memset(data, 0, ARRAY_LEN(data));
std::size_t received;
sf::Socket::Status rcvStatus = sck.receive(data, ARRAY_LEN(data), received);
if (rcvStatus != sf::Socket::Done)
{
std::cout << "oops" << std::endl;
if (rcvStatus == sf::Socket::Disconnected)
{
break;
}
}
std::cout << "Received " << received << " bytes" << std::endl;
std::cout << data << std::endl;
}
return 0;
}

WriteProcessMemory C++

Just pasted what was necessary, the memory addresses aren't being written to even though my logging shows that WriteProcessMemory() was successful. Also, I've double checked that i have the correct memory addresses as well. Thank You for help.
char* offsets[][3] = {
{ "0x3E264", "0", "char[1]" },
{ "0x45848", "Auto-Mine", "char[10]" },
{ "0x458C0", "Auto-Build", "char[10]" },
//to be continued...
};
HANDLE scHandle = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, ID);
if (scHandle == NULL) {
log << "ERROR: OpenProcess() returned " << GetLastError() << endl;
return false;
}
DWORD bytesOut;
for (int a = 0; a < 9; a++) {
if (WriteProcessMemory(scHandle, (LPVOID)(wDetectorBaseAddress + (int)strtol(offsets[a][0], NULL, 0)), offsets[a][1], strlen(offsets[a][1]) + 1, &bytesOut))
{
log << "WriteProcessMemory() to address " << wDetectorBaseAddress << " + " << (int)strtol(offsets[a][0], NULL, 0) << " = " << wDetectorBaseAddress + (int)strtol(offsets[a][0], NULL, 0) << " with '" << offsets[a][1] << "'; " << bytesOut << " bytes were written" << endl;
}
else
{
log << "ERROR: WriteProcessMemory() returned " << GetLastError() << endl;
return false;
}
}
CloseHandle(scHandle);
You need to call VirtualProtect with PAGE_EXECUTE_READWRITE before you can write to the process's memory. After writing, you need to restore the original protection.
Another thing is, how exactly do you know those addresses are always the same? Can you confirm that it never changes?
Note: You MIGHT also have to call FlushInstructionCache after writing.