Should recv() result must be equal to buffer length? - c++

int resp = recv(s, buf, len, flags);
if(resp == 18) {
char data[18];
strcpy(data, buf);
...
}
I expect strlen(data) to be equal 18, but it isn`t. What did I miss?

If your data contains a zero-byte \0, then strlen will only give you the length of the string up to the terminator. If data does not have a terminator, then strlen will continue searching through whatever memory it happens to be at. This is commonly used in buffer overflow attacks.

I think what Joe is trying to say is your code isn't bullet-proof, starting with the number bytes read and copying the data into the data array.
int resp = recv(s, buf, len, flags);
if(resp > 0)
{
// ! This code assumse that all the data will fit into 18 bytes.
char data[18];
memset(data, 0, sizeof(data));
// ! As Joe warned above, this code assumes there's a null terminating
// ! character in the buf you received.
strcpy(data, buf); // consider memcpy if binary data (i.e. not strings)
}

Related

serial port connection - ReadFile always return 4 bytes read

I'm trying to read by ReadFile but always get that its read 4 bytes, doesn't mutter how long was the string.
UART* uart = (UART*)lpParam;
char TempChar; //Temporary character used for reading
char SerialBuffer[256];//Buffer for storing Rxed Data
DWORD NoBytesRead;
int i = 0;
do
{
NoBytesRead = 0;
ReadFile(uart->connHandle, //Handle of the Serial port
&SerialBuffer, //Temporary character
sizeof(256),//Size of TempChar
&NoBytesRead, //Number of bytes read
NULL);
//SerialBuffer[i] = TempChar;// Store Tempchar into buffer
i++;
if (NoBytesRead > 0)
{
char* strMsg = (char*)malloc(sizeof(256 * sizeof(char)));
SerialBuffer[NoBytesRead] = '\0';
TRACE("read %d- %s\n", NoBytesRead,SerialBuffer);
strcpy_s(strMsg, 256,SerialBuffer);
ControllerPublishMsg(uart->controller, SerialBuffer);
}
SerialBuffer[0] = '\0';
In case i send string "hh" to connection I'm get output "read 4- hh".
The string is 2 bytes long, but NoBytesRead = 4.
thanks.
sizeof(256) defaults to sizeof(int) this is four bytes. replace sizeof(256) by 256. Also replace sizeof(256 * sizeof(char)) by (256 * sizeof(char)).
Think about the statement
sizeof(256)
that you pass as a buffer size.
That expression evaluates to the same thing as
sizeof(int)
which probably evaluates to 4 on your platform. You'd need to hand over the literal value 256 or better sizeof SerialBuffer to ReadFile.
And you got the same error in your malloc arguments.
Why you are receiving 4 characters when you (think you) are sending only 2 is impossible to see without the code on the sender side. In case ReadFile returns 4, it most probably received 4 characters. Due to the messed up buffer size argument, it will however not be able to receive more than 4 characters.
You are misusing sizeof.
When calling ReadFile(), you are using sizeof(256) as the number of bytes to read. A numeric literal is an int by default, so you are really using sizeof(int), which is 4 bytes on your compiler. Get rid of the sizeof and just use 256 by itself:
ReadFile(uart->connHandle, //Handle of the Serial port
&SerialBuffer, //Temporary character
256,//Size of TempChar
&NoBytesRead, //Number of bytes read
NULL);
Or better, get rid of the 256 and use sizeof(SerialBuffer) instead, since it is a static array with a fixed size known at compile time:
ReadFile(uart->connHandle, //Handle of the Serial port
&SerialBuffer, //Temporary character
sizeof(SerialBuffer),//Size of TempChar
&NoBytesRead, //Number of bytes read
NULL);
You are making a similar mistake when calling malloc(). sizeof(char) is always 1, so you are really calling sizeof(256) again. So again, you can get rid of sizeof and just use 256 by itself:
char* strMsg = (char*) malloc(256 * sizeof(char));
// or just: char* strMsg = (char*) malloc(256);
Although, you are not actually using strMsg for anything (and you are leaking it), so you should just get rid of it completely.
Try something more like this:
UART* uart = (UART*)lpParam;
char SerialBuffer[257];//Buffer for storing Rxed Data
DWORD NoBytesRead;
do
{
NoBytesRead = 0;
ReadFile(uart->connHandle, //Handle of the Serial port
SerialBuffer, //Temporary buffer
sizeof(SerialBuffer)-1,//Size of buffer minus null-terminator
&NoBytesRead, //Number of bytes read
NULL);
if (NoBytesRead > 0)
{
SerialBuffer[NoBytesRead] = '\0';
TRACE("read %u- %s\n", NoBytesRead, SerialBuffer);
ControllerPublishMsg(uart->controller, SerialBuffer);
}

Data representation loss when converting c_string to string and back to c_string

I have a binary file I want to transmit and basically I was wondering if I converted the c_string into a string, whether that would have an effect on the end result, because I sent a c_string after using read() and made sure it read for binary files and not text file, but then I put it in a string and converted back to c_string. If that's no good, is there a simple way to get it back to binary form?
FILE *file = fopen(filename, "ab");
int size = 0;
do{
size = recvfrom(s, buffer, 128, 0, (LPSOCKADDR) &sa_in, &senderSize);
if(size > 0)
{
fwrite(buffer, sizeof(char), size, file);
}
}while(size > 0);
c_string(binary) turns into string and then turns back into c_string.
FILE *file = fopen(filename, "ab");
int size = 0;
do{
size = recvfrom(s, buffer, 128, 0, (LPSOCKADDR) &sa_in, &senderSize);
if(size > 0)
{
string bufferstring(buffer);
strcpy(buffer, bufferstring);
fwrite(buffer, sizeof(char), size, file);
}
}while(size > 0);
Doing this:
string bufferstring(buffer);
means to use a null-terminated string as the input. The data in buffer is probably not a null-terminated string of exactly length 127. If it's shorter you have data loss, and if there is no null terminator in buffer then you cause undefined behaviour.
The next line, strcpy(buffer, bufferstring); doesn't even compile; std::string cannot be used as argument to strcpy.
After that you write from buffera which isn't even defined.
Was there some problem with your first version of code that makes you want to change it?
Binary data may have NULs mixed in, so the line
string bufferstring(buffer);
may truncate the data. This line:
strcpy(buffer, bufferstring);
has the same problem of truncation, and also, you need to call std::string::c_str() to get the char * representation. Use memcpy() to avoid truncation.
Lastly, I don't like the do...while() pattern.
while((size = recvfrom(s, buffer, 128, 0, (LPSOCKADDR) &sa_in, &senderSize)) > 0) {
string bufferstring(buffer, size);
memcpy(buffer, bufferstring.c_str(), bufferstring.size());
fwrite(buffer, sizeof(char), size, file);
}

Display the first characters of an unsigned char*

I have the following code (I stripped down the useless parts):
unsigned char* decrypted= (unsigned char *) malloc(500);
bufSize = operations.RSADecrypt(newEncrypted, bufSize, key, decrypted);
printf("Test: %s", decrypted);
And I would like to display only the bufSize first characters of decrypted because actually it displays a lot of nonsense characters!
You can use the "%.*s" format specifier:
printf("Test: %.*s", bufSize, decrypted);
which instructs printf() to write the first bufSize characters from decrypted.
You can limit the length with the format specifier:
printf ("Test: %-20.20s", decrypted);
For a version using a variable bufSize:
printf ("Test: %-*.*s", bufSize, bufSize, decrypted);
Note that this forces the length to exactly that many characters, padded with spaces on the right if need be. If you want a shorter string to be shorter in the output (irrelebant in your case if the string is, as indicated, always longer than what you want output), you can use:
printf ("Test: %.*s", bufSize, decrypted);
If you are 'allowed' to modify the decrypted string. You can simply add a terminator to it:
decrypted[bufSize] = 0;
So printf() will only print the buffer contents.
If you are not allowed to add a custom char to the decrypted buffer you need to copy the contents to a temporary buffer and use that buffer in your printf():
unsigned char* tmp = (unsigned char *) malloc(bufSize + 1);
strncpy(tmp, decrypted, bufSize);
tmp[bufSize] = 0;
I don't like that you said the pointer contained nonsense. Its not nonsense, its residual memory. There is a good chance you expect and want this area to be set to zero. Try the following, where calloc sets the malloc bits to zero.
unsigned char* decrypted= (unsigned char *) calloc(500,sizeof(char));
bufSize = operations.RSADecrypt(newEncrypted, bufSize, key, decrypted);
printf("Test: %s", decrypted);

How to read an input from a client via socket in Linux in C++?

My goal is create an app client server, written in C++.
When the server read an input from the client, should process the string and give an output.
Basically, I have a simply echo server that send the same message.
But if the user types a special string (like "quit"), the program have to do something else.
My problem is that this one dont happend, because the comparison between strings is not working... I dunno why!
Here a simple code:
while(1) {
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0);
send(client, buffer, num, 0);
char hello[6] ="hello";
if(strcmp(hello,buffer)==0) {
send(client, "hello dude! ", 12, 0);
}
buffer[num] = '\0';
if (buffer[num-1] == '\n')
buffer[num-1] = '\0';
std::cout << buffer;
strcpy(buffer, "");
}
Why the comparison is not working?
I have tried many solutions...but all failed :(
Your data in buf may not be NULL-terminated, because buf contains random data if not initialized. You only know the content of the first num bytes. Therefore you also have to check how much data you've received before comparing the strings:
const char hello[6] ="hello";
size_t hello_sz = sizeof hello - 1;
if(num == hello_sz && memcmp(hello, buffer, hello_sz) == 0) { ...
As a side note, this protocol will be fragile unless you delimit your messages, so in the event of fragmented reads (receive "hel" on first read, "lo" on the second) you can tell where one message starts and another one ends.
strcmp requires null terminated strings. The buffer you read to might have non-null characters after the received message.
Either right before the read do:
ZeroMemory(buffer, BUFSIZE); //or your compiler defined equivalent
Or right after the read
buffer[num] = '\0';
This will ensure that there is a terminating null at the end of the received message and the comparison should work.
A string is defined to be an array of chars upto and including the terminating \0 byte. Initially your buffer contains arbitrary bytes, and is not even guaranteed to contain a string. You have to set buffer[num] = '\0' to make it a string.
That of course means that recv should not read sizeof buffer bytes but one byte less.

Reading socket reply in loop

I have:
char buf[320];
read(soc, buf, sizeof(buf));
//print buf;
However, sometimes the reply is much bigger then 320 characters, so I'm trying to run the read in a loop to avoid taking up too much memory space. I tried read(soc, buf, sizeof(buf)) but that only prints the same first x characters over again. How would I print the leftover characters that did not fit into the first 320 characters in a loop?
Thanks
Change your loop to something like:
int numread;
while(1) {
if ((numread = read(soc, buf, sizeof(buf) - 1)) == -1) {
perror("read");
exit(1);
}
if (numread == 0)
break;
buf[numread] = '\0';
printf("Reply: %s\n", buf);
}
for the reasons Nikola states.
Every time you call read( s, buf, buf_size ) the kernel copies min( buf_size, bytes_available ) into the buf, where bytes_available is the number of bytes already received and waiting in socket receive buffer. The read(2) system call returns the number of bytes placed into application buffer, or -1 on error, or 0 to signal EOF, i.e. a close(2) of the socket on the sending end. Thus when you reuse the buffer, only part of it might be overwritten with new data. Also note that -1 evaluates to true in C and C++. This is probably the case you are hitting.
printf(3) expects zero-terminated string for the %s format specifier. The bytes read from the socket might not contain the '\0' byte, thus letting printf(3) print till it finds zero further down somewhere. This might lead to buffer overrun.
The points here are:
Always check the value returned from read(2)
If you print strings read from a socket - always zero-terminate them manually.
Hope this helps.