Random characters when reading from pipe - c++

In the following code :
...
char *message = "This is the message!";
...
printf("Writing to file descriptor FD[%i] \n", fd[1]);
write( fd[1], message, strlen(message));
printf("Reading from file descriptor FD[%i] \n", fd[0]);
read( fd[0], buffer, strlen(message));
printf("Message from FD[%i] : \"%s\" .\n", fd[0], buffer);
I get the following output :
"This is the message!���" .
But if I remove the "!" from my message, the output doesn't have random characters... Any idea why I get these 3 random characters to appear?

When you write your message of length strlen(whatever), that does not include the terminating NUL character. Hence what comes out at the other end is not a C string but rather just a collection of characters.
What follows that collection of characters in memory depends entirely upon what was there before you read them from the pipe. Since it's not a C string (except by possible accident if the memory location following just happened to already contain a NUL), you should not be passing it to printf with an unbounded %s format specifier.
You have two possibilities here. The first is to send the NUL character along with the data with something like:
write (fd[1], message, strlen(message) + 1);
or (probably better) use the return value from read which tells you how many bytes were read, something like:
int sz = read (fd[0], buffer, sizeof(buffer));
// should probably check sz here as well.
printf ("Message from FD[%i] : \"%*s\" .\n", fd[0], sz, buffer);

Related

Winsock - read integer from Java client in C++

I have a client-server application, with the server part written in C++ (Winsock) and the client part in Java.
When sending data from the client, I first send its length followed by the actual data. For sending the length, this is the code:
clientSender.print(text.length());
where clientSender is of type PrintWriter.
On the server side, the code that reads this is
int iDataLength;
if(recv(client, (char *)&iDataLength, sizeof(iDataLength), 0) != SOCKET_ERROR)
//do something
I tried printing the value of iDataLength within the if and it always turns out to be some random large integer. If I change iDataLength's type to char, I get the correct value. However, the actual value could well exceed a char's capacity.
What is the correct way to read an integer passed over a socket in C++ ?
I think the problem is that PrintWriter is writing text and you are trying to read a binary number.
Here is what PrintWriter does with the integer it sends:
http://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#print%28int%29
Prints an integer. The string produced by String.valueOf(int) is
translated into bytes according to the platform's default character
encoding, and these bytes are written in exactly the manner of the
write(int) method.
Try something like this:
#include <sys/socket.h>
#include <cstring> // for std::strerror()
// ... stuff
char buf[1024]; // buffer to receive text
int len;
if((len = recv(client, buf, sizeof(buf), 0)) == -1)
{
std::cerr << "ERROR: " << std::strerror(errno) << std::endl;
return 1;
}
std::string s(buf, len);
int iDataLength = std::stoi(s); // convert text back to integer
// use iDataLength here (after sanity checks)
Are you sure the endianness is not the issue? (Maybe Java encodes it as big endian and you read it as little endian).
Besides, you might need to implement receivall function (similar to sendall - as here). To make sure you receive exact number of bytes specified - because recv may receive fewer bytes than it was told to.
You have a confusion between numeric values and their ASCII representation.
When in Java you write clientSender.print(text.length()); you are actually writing an ascii string - if length is 15, you will send characters 1 (code ASCII 0x31) and 5 (code ASCII 0x35)
So you must either :
send a binary length in a portable way (in C or C++ you have hton and ntoh, but unsure in Java)
add a separator (newline) after the textual length from Java side and decode that in C++ :
char buffer[1024]; // a size big enough to read the packet
int iDataLength, l;
l = recv(client, (char *)&iDataLength, sizeof(iDataLength), 0);
if (l != SOCKET_ERROR) {
buffer[l] = 0;
iDataLength = sscanf(buffer, "%d", &iDataLength);
char *ptr = strchr(buffer, '\n');
if (ptr == NULL) {
// should never happen : peer does not respect protocol
...
}
ptr += 1; // ptr now points after the length
//do something
}
Java part should be : clientSender.println(text.length());
EDIT :
From Remy Lebeau's comment, There is no 1-to-1 relationship between sends and reads in TCP. recv() can and does return arbitrary amounts of data, so you cannot assume that a single recv() will read the entire line of text.
Above code should not do a simple recv but be ready to concatenate multiple reads to find the separator (left as exercise for the reader :-) )

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.

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.