recv() strings of unknown encoding from sockets in c++ - c++

I'm writing some piece of client code which will connect to a server and issue it an ID - "16 byte string", and in return it will get back the same 16 byte string. I could also get unsolicited requests from this server telling me it's ID, and I'll have to send the same thing back to him as well.
When I create the string and send it,it works fine, as I am able to completely parse the reply I get and print out, and it's exactly what I sent. However, for the unsolicited request part - I am unable to read the string that is sent to me.
Here is a part of my code ..
string my_send_string = "123" ;
char my_send_buffer[16] ;
char my_reply[256] ;
memset(my_send_buffer,'\0', 16) ;
strncpy(my_send_buffer,my_send_string.c_str(),my_send_string.size()) ;
numBytes = send(sock_fd,my_send_buffer,16,0);
// verified that numBytes is indeed 16 ..
numBytes = recv(sock_fd, my_reply, 16, 0) ;
// verified that numBytes recvd is indeed 16 ..
printf("Original Send Reply: %s\n",my_reply ); // This prints 123, as I expect.
memset(my_reply,'\0', 16) ;
numBytes = recv(sock_fd, my_reply, 16, 0) ;
// verified that numBytes is 16.
printf("Unsolicited Request:%s\n",my_reply ); // This prints ?a?p??˝س?8?
....
I think I'm encoding the received string incorrectly here - any tips on how I can fix this ? In the example above, I tried to just send it once, but if i send the string 10 times with different string ID's, I always get back the ID I send, so it's not just a one time thing.

Related

Why does this function loop forever?

I have this function that takes a SOCKET and a file name to the output file, then it tries to receive and output the data to a file, when compiling and running the code it works fine but the program does not exit and the output file (file.txt) contains some unreadable garbage text
the rest of the code work fine and tested, I am sure the problem is in this file but can't tell what and where
int recv_file(SOCKET soc, const char * fname)
{
FILE * ptr;
char buffer[MAX];
unsigned long long int x = 0;
if (fopen_s(&ptr, fname , "wb") != 0)
{
printf("Failed to receive file \n");
return 1;
}
do
{
c = recv(soc, buffer, MAX, 0);
printf("recv count : %d\n",c);
// here was -> fwrite(buffer, 1, sizeof(buffer), ptr);
fwrite(buffer, 1, c, ptr);
}
while ( c > 0);
printf("Total received : %lld\n", x);
fclose(ptr);
return 0;
}
as an output it prints only one line recv count : 65
I tried to use closesocket(soc);WSACleanup(); but this does not solve the problem
for the server, I tested with netcat and python socketserver and had same behavior for both
also the last printf right after the do-while does not get printed to the screen
Data from network can come in chuncks
recv returns negative value on errors that what break handles (stops loop).
recv returns number of bytes received.
fwrite should write number of bytes equal to those which has been received, so it should be:
fwrite(buffer, 1, c, ptr);
Passing there sizeof(buff) will record trash in a file (content form previous read or memory trash).
Now question is what sender does when there is no data. If nothing recv will block waiting for new data. If sender closes tcp connection then respective error should be reported by recv and loop should be ended.
If you are fetching data form some HTTP server then most probably server assumes that client will close connection. Server just waits for next request.
Note also that depending on SOCKET configuration recv can be blocking or not. So depending on that recv may return 0 on success when in fact there will be new data in future.

Sending Large Base64 String over TCP Socket

I am trying to send a Base64 encoded image from TCP client using GO and TCP server in C++.
Here is the code snippet for C++ Receiver
std::string recieve(int bufferSize=1024,const char *eom_flag = "<EOF>"){
char buffer[bufferSize];
std::string output;
int iResult;
char *eom;
do{
iResult = recv(client, buffer, sizeof(buffer), 0);
//If End OF MESSAGE flag is found.
eom = strstr(buffer,eom_flag);
//If socket is waiting , do dot append the json, keep on waiting.
if(iResult == 0){
continue;
}
output+=buffer;
//Erase null character, if exist.
output.erase(std::find(output.begin(), output.end(), '\0'), output.end());
//is socket connection is broken or end of message is reached.
}while(iResult > -1 and eom == NULL);
//Trim <EOF>
std::size_t eom_pos = output.rfind(eom_flag);
return output.substr(0,eom_pos);}
Idea is to receive the message until End of Message is found, thereafter continue to listen for another message on the same TCP connection.
Golang TCP client code snippet.
//Making connection
connection, _ := net.Dial("tcp", "localhost"+":"+PortNumber)
if _, err := fmt.Fprintf(connection, B64img+"<EOF>"); err != nil {
log.Println(err)
panic(err)
}
Tried approaches:
Increasing the buffer size in the C++ receiver.
Removing the null character from the end of the string in the C++ receiver.
Observations:
Length of string sent by the client is fixed, while the length of the string after receive function is larger and
random. Example: Go client string length is 25243. For the same string, length after receive when i
run send and receive in the loop is 25243, 26743, 53092, 41389, 42849.
On Saving the received string in a file, I see <0x7f> <0x02> character in the string.
I am using winsock2.h for c++ socket.
You are treating the received data as a C string - a sequence of bytes ending with a 0 byte - which is not correct.
recv receives some bytes and puts them in buffer. Let's say it received 200 bytes.
You then do strstr(buffer,eom_flag);. strstr doesn't know that 200 bytes were received. strstr starts from the beginning of the buffer, and keeps looking until it finds either , or a 0 byte. There is a chance that it might find a in the other 824 bytes of the buffer, even though you didn't receive one.
Then you do output += buffer;. This also treats the buffer as if it ends with a 0 byte. This will look through the whole buffer (not just the first 200 bytes) to find a 0 byte. It will then add everything up to that point into output. Again, it might find a 0 byte in the last 824 bytes of the buffer, and add too much data. It might not find a 0 byte in the buffer at all, and then it will keep on adding extra data from other variables that are stored next to buffer in memory. Or it might find a 0 byte in the first 200 bytes, and stop there (but only if you sent a 0 byte).
What you should do is pay attention to the number of bytes received (which is iResult) and add that many bytes to the output. You could use:
output.insert(output.end(), buffer, buffer+iResult);
Also (as Phillipe Thomassigny has pointed out in a comment), the "" might not be received all at once. You might receive "" separately. You should check whether output has an "" instead of checking whether buffer has an "". (The performance implications of this are left as an exercise to the reader)
By the way, this line doesn't do anything at the moment:
output.erase(std::find(output.begin(), output.end(), '\0'), output.end());
because '\0' never gets added to output, because with output += buffer;, a '\0' tells it where to stop adding.

Sending and receiving messages between client and server program giving me unexpected result

This is my server program code :
...
listen(s , 3);
//Accept and incoming connection
cout<<"\n\nWaiting for incoming connections... ";
int c = sizeof(sockaddr_in);
Socket newSocket = accept(s , (struct sockaddr *)&client, &c);
if (newSocket == INVALID_SOCKET)
{
cout<<"\nAccept failed with error code : "<<WSAGetLastError();
}
// Since both server and client are now connected, it's time to send and receive players' name
string me;
char other[30];
fi.close(); fi.open("data.dat");
fi>>me; fi.close();
recv(newSocket,other,strlen(other),0);
send(newSocket,me.c_str(),me.length(),0);
cout<<me<<endl<<other;
This is client program code:
Socket s;
//Connect to server
if (connect(s , (sockaddr *)&server , sizeof(server)) < 0)
{
cout<<"\nConnection error.";
_getch();
return 1;
}
//reading name and sending it to server
string me;
char other[30];
ifstream fi("cdata.dat");
fi>>me; fi.close();
send(s,me.c_str(),me.length(),0);
recv(s,other,strlen(other),0);
cout<<me<<endl<<other;
Suppose data.dat contains the word Hero
And cdata.dat contains the word 'Zero'
Now server side output is (ignoring other lines):
Hero
Zero%$#5^sdj
Client side output is (ignoring other lines):
Zero
He
What is the problem?
You are using the function strlen incorrectly here. This determines the length of a c-string by searching for the 1st occurrence of the character \0 (the null terminator). Given that you do not initialise your other array, this value will be random, rather than 30 as you presumably expect.
You can change your code to explicitly state the number 30 as the maximum number of bytes to receive. You can also explicitly send the null terminator by adding 1 to your sent string length. So the server code becomes:
recv(newSocket,other,30,0);
send(newSocket,me.c_str(),me.length()+1,0);
And the client code becomes:
send(s,me.c_str(),me.length()+1,0);
recv(s,other,30,0);
Better still to change the hardcoded 30 to some integer constant, both in the other declaration and in the recv usage above.
your 'other' array is of length 30, but you do not clip the length of that array by the return value of recv which is the number of bytes that were read.
additionally strlen of the other array is dangerous because it's not a null terminated string but a constant size array, you should use the length of this array instead of strlen.
I believe if you do the same in client it will fix that as well. the other array could contain a random null byte when uninitialized which will give an odd strlen value you don't expect.

Error while sending encrypted data with Boost::asio::async_send_to

I am developing an encrypted version of a realtime communication application. The issue I have is, that the encrypted data pakets sent to the receiver are faulty. An example from the error log: (hex encoded data, the original data is pure byte code).
sent: 262C1688215232656B5235B691826A21C51D37A99413050BAEADB81D8892493FC0DB519250199F5BE73E18F2703946593C4F6CEA396A168B3313FA689DE84F380606ED3C322F2ADFC561B9F1571E29DF5870B59D2FCF497E01D9CD5DFCED743559C3EE5B00678966C8D73EA3A5CD810BB848309CDF0F955F949FDBA618C401DA70A10C36063261C5DBAB0FC0F1
received: 262C1688215232656B5235B691826A21C51D37A99413050BAEADB81D8892493FC0DB519250199F5BE73E18F2703946593C4F6CEA396A168B3313FA689DE84F380606ED3C322F2ADFC561B9F1571E29DF5870B59D2FCF497E01D9CD5DFCED743559C3EE5B00CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD
This is the call of the send-method:
string encSendBuffer = sj->cipherAgent->encrypt(sj->dFC->sendBuffer, sj->dFC->sendBytes);
char* newSendBuffer = new char[encSendBuffer.length() + 1];
strcpy(newSendBuffer, encSendBuffer.c_str());
sj->dFC->s->async_send_to(boost::asio::buffer(newSendBuffer, encSendBuffer.length()),
*sj->dFC->f,
boost::bind(&sender::sendHandler, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
)
sj->dFC->s is a UDP-Socket and sj->dFC->f is an UDP Endpoint.
The error code of the sendHandler is always system: 0
This is how I do the encryption using the Crypto++ library: (extract)
string cipherEngine::encrypt(char* input, int length)
{
string cipher = "";
CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, keyLength, iv);
ArraySource as((byte*)input, length, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
)
);
return cipher;
}
UPDATE: Code of the receive function:
void receiver::receive(){
int maxLength = 4096;
sj->dFC->s->async_receive_from(boost::asio::buffer(input,maxLength),
senderEndpoint,
boost::bind(&receiver::handleReceiveFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
After the Data is received, it is stored in the char buffer input and decrypted in the handleReceiveFrom function.
Without encryption everything is fine. The number of bytes that are sended is always correct, on receiver side too. The length of de "CD"- blocks are quite random. I already checked the encryption and the decrypted data is the same as the original plain text.
Does any know where this behavior comes from?
The key here is that the erroneous data begins after the first null (0x00) value in your encrypted data array. The following line:
strcpy(newSendBuffer, encSendBuffer.c_str());
...looks like it's only copying up to the data until that null byte into newSendBuffer. The send function is sending that buffer contents just fine; the buffer just doesn't have the data you expect. You'll need to load newSendBuffer in a different way, not using strcpy(), that can handle null bytes. Try std::memcpy().
Thank you Joachim Pileborg and Jack O'Reilly! You are right indeed.
I changed my code from strcpy(newSendBuffer, encSendBuffer.c_str());
to
for (int i = 0; i < encSendBuffer.length(); i++)
{
newSendBuffer[i] = encSendBuffer.at(i);
}
on sender and receiver side. It actually solved the problem. It is quite naive code but it does what it should.
std::memcpy() seems to be much more elegant and i will try it out.

Unusual HTTP Response in Basic C++ Socket Programming

I've got a basic HTTP client set up in C++, which works ok so far. It's for a school assignment, so there's lots more to do, but I'm having a problem.
I use the recv() function in a while loop, to repeatedly add pieces of the response to my response buffer, and then output that buffer each time. The problem is, at the end of each piece of the response, the HTTP Request is getting tacked on as well.
For example, the response will be a chunk of the page's source code, followed by "GET / HTTP/1.1...", followed by the next chunk, and then the "GET..." again, and so on.
Here's my relevant code:
// Prepare request
char request[] = "HEAD /index.html HTTP/1.1\r\nHOST: www.google.com\r\nCONNECTION: close\r\n\r\n";
// Send request
len = send(sockfd, request, sizeof(request), 0);
// Write/output response
while (recv(sockfd, buf, sizeof(buf), 0) != 0)
{
// Read & output response
printf("%s", buf);
}
The buffer isn't null terminated, which is required for strings in C++. When you see the "extra GET", you are seeing memory that you shouldn't be because the stdlib tried to print your buffer, but never found a '\0' character.
A quick fix is to force the buffer to be terminated:
int n = 1;
while (n > 0) {
n = recv(sockfd, buf, sizeof(buf), 0);
if (n > 0) {
// null terminate the buffer so that we can print it
buf[n] = '\0';
// output response
printf("%s", buf);
}
}
I suspect it's because your buf is allocated in memory just below your request. When you call printf on the buffer, printf will print as much as it can before finding a NUL character (which marks the end of the string). If there isn't one, it'll go right on through into request. And generally, there won't be one, because recv is for receiving binary data and doesn't know that you want to treat its output a string.
One quick fix would be to limit the receive operation to sizeof(buf)-1, and to explicitly add the NUL terminator yourself, using the size of the returned data:
while ((nr = recv(sockfd, buf, sizeof(buf), 0)) > 0)
{
buf[nr] = 0;
...
}
Of course, for this to (marginally) safe you need to be sure that you'll always receive printable data.
recv does not add a \0 string terminator to the buffer recieved - it just works in raw binary. So your printf is running off the send of your buf buffer (and apparently ending up looking at your request buffer).
Either add a nul-terminator to the end of buf, or print the buffer one character at a time using putchar() (both of these approaches will make it necessary to store the value returned by recv()).
The recv call will not null-terminate buf; instead, it will just provide you with the raw data received from the wire. You need to save the return value of recv, and then add a null-terminating byte yourself into buf before printing it. Consequentially, you can only ask for sizeof(buf)-1 bytes.