Reputation: 37206
I am experimenting with the HTTP protocol using Winsock2. I am working on a function
int recv_data(const char *hostname, char *resp);
The function is meant to send an HTTP HEAD request to a given host and then receive a response. It allocated memory at the pointer resp and copies the response there before returning the total number of bytes received for the response.
Here is my recieve loop:
int recv_data(const char *hostname, char *resp)
{
int totalRecvd = 0;
stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
resp = new char[totalRecvd + 1];
strcpy(resp, sStream.str().c_str());
return totalRecvd);
}
All of this works just fine and all and if I output resp at this point it outputs just fine. I just have a problem if I try to output resp after the function has returned apparently. I do not believe this should be how things normally go and if I am not mistaken I believe it has something to do with me using the stringstream to temporarily store the response. I think I have read somewhere about the data that stringstream collects going out of scope.
I was hoping that I could have this function set up this way where the caller can just pass in a char* and the function will allocate the correct amount of memory (which is determined at runtime depending on the host and the number of bytes returned by recv(). Is there anyway for me to get a permanent copy from a stringstream in memory as a char array with the pointer being bad after the function returns and the stringstream goes out of scope?
[EDIT]: Here is the solution posted below incorporated into my problem, anyone looking to reuse this for Winsock2 proramming have at it, seems to work well. Will recv data from the server until the connection is closed when recv() returns 0. The solution is passing in a reference to the pointer, because the new operator changes the pointer and that change is not reflected after the function returns unless it is passed in by reference.
int recv_data(SOCKET s, char *&data)
{
int totalRecvd = 0;
std::stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
data = new char[totalRecvd + 1];
strcpy_s(data, totalRecvd, sStream.str().c_str());
data[totalRecvd] = 0;
return totalRecvd;
}
Upvotes: 0
Views: 4677
Reputation: 146940
If you alter your code to use std::string
and boost::asio
, you will no longer suffer from memory management problems.
Upvotes: 0
Reputation: 168626
resp
is a local variable in the http_req
function. Updating the value of resp
will have no effect outside of http_req
. This line:
resp = new char[totalRecvd + 1];
will have only local effect.
Try this signature:
int http_req(const char *hostname, char *&resp);
std::string http_req(const std::string& hostname) {
...
return sStream.str()
}
Upvotes: 3