I'm writing simple server/client in c, where server temporary stores message from client and retrieve it when client request it.
The problem is when client receives message from server, the buffer acts kinda weird.
All i did is read as much as receive from server and print it on the screen, but somehow buffer was overwrited more than maximum size of buffer
in client
while((byteRead = recv(ssock, buffer, MAXBUF, 0)) > 0)
{
if(byteRead <= 0)
break;
printf("%s", buffer);
}
where MAXBUF is 256. It keep contains some garbages so i examined the string size in buffer
and surprisingly
printf("%d READ vs %d buffer strlen \n", byteRead, strlen(buffer))
show me that byteRead is 256 but string length of buffer is 262.
Any idea??
P.s on server side, it reads file correctly and send it onto socket.
recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one).
You must use byteRead to determine the length of the string. Add a null terminator if you want to use a function like printf, but ensure your buffer has the space for it even on a maximum-size read.
The problem here is that buffer is not NULL-terminated by recv(). In fact, recv only puts the raw socket data into the buffer. If it recieves 256 bytes of data, whatever comes after that might be null characters (e.g. as it is on your server) or it might be something else (as it is on your client). It's an artifact of program execution, not of how you programmed it.
The easiest and fastest way to fix this:
Allocate buffer with size MAXBUF + 1. The +1 will be for an extra NULL character.
Immediately before the printf, add a null character at buffer[bytesRead].
So all-told:
buffer = malloc((MAXBUF + 1) * sizeof(char)); // NEW
while((byteRead = recv(ssock, buffer, MAXBUF, 0)) > 0)
{
if(byteRead <= 0)
break;
else {
buffer[bytesRead] = '\0'; // NEW
printf("%s", buffer);
}
}
Yes.
strlen() looks for the nearest NULL terminator, as in a conventional C string.
recv() has nothing to do with null terminator and would not add one. So, the strlen call is wrong and may even crash your program by unauthorized read.
Related
I was running into a problem i couldnt really solve so I restarted.
I had a problem with Data encapsulation or more specific with no encapsulation. So after I figured out, that encapsulation is useful, I started rewriting the code.
Now I run into a different Problem. Somehow my send and recv calls are not working as I want them to be.
Here is the part where I send:
char to_send[] = "hello. I am the Data.";
// get size of data
int len = strlen(to_send);
char slen[len];
sprintf(slen,"%d",len);
printf("%s\n",slen);
// send size of data
if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}
// send data
if(send(comm_fd,to_send,len,0)<0){perror("Error on send"); exit(1);}
And here Part where I recv:
// getting size of bytes to recv
char buf[1000];
bzero(buf,1000);
int rec = recv(comm_fd, buf, 100,0);
printf("rec\n: %i",rec);
printf("buf\n: %s\n", buf);
int buffsize;
buffsize = atoi(buf);
bzero(buf,1000);
printf("buffsize: %i\n",buffsize);
// recv the bytes
bzero(buf,1000);
rec = recv(comm_fd, buf, buffsize,0);
printf("rec\n: %i",rec);
printf("%s",buf);
So my problem now is: I can recv the size of the next Data and print it. But the Data itself is not showing up.
Can someone help me? I think I'm doing major things wrong (I'm new to C and to Network programming)
Thanks in advance
Two things with that first send call:
if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}
Here you send len number of bytes, but len is the length of to_send and not the length of slen. You will most likely send data from outside the initialized parts of slen which leads to undefined behavior
The second problem is that you send the length of to_send as a variable-length string, so the received doesn't actually know how much to receive. In your case you could actually (and probably do) receive the length and the string in a single recv call. At least if you're using TCP (streaming) sockets.
Both of these problems can be solved by making slen a fixed-size array, big enough to hold the largest numbers you can think of (ten digits is usually enough), and then send this fixed-length array using sizeof slen .
Perhaps something like this:
// Ten digits, plus string terminator
char slen[10 + 1];
// Prefix length with zeroes, and don't overflow the buffer
snprintf(slen, sizeof(slen), "%010d", strlen(to_send));
// Send the whole array, including terminator
send(comm_fd, slen, sizeof slen, 0);
Then on the receiving side, you could do
// Ten digits, plus string terminator
char slen[10 + 1];
// Receive the whole string, including terminator
recv(comm_fd, slen, sizeof(slen), 0);
// Convert to a number
size_t len = strtoul(slen, NULL, 10);
// Now receive `len` bytes
Note that I have no error checking, which you should have.
I wrote a program that copy content from a file to another but when I used fread() to read data from a file and put into buffer it turn out it have more data than the text file
Here's my code
char *buffer;
int size;
FILE *fp1;
fp1 = fopen(src, "r");
if (fp1 == NULL) {
err = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
fprintf(stderr, "Error opening file: %s\n", strerror( err ));
return 0;
}else{
fseek(fp1, 0, SEEK_END);
size = ftell(fp1);
buffer = (char *) malloc(size +1 );
printf("data in Buffer : %s\n",buffer);
printf("size : %d\n",size);
fseek(fp1, 0, SEEK_SET);
fread(buffer,size,1,fp1);
strcat(buffer,"\0");
printf("data in Buffer after fread(): %s\n",buffer);
int a = strlen(buffer);
printf("strlen in Buffer : %d\n",a);
fclose(fp1);
}
FILE *fp2;
fp2 = fopen("disk1.img", "a");
if (fp2 == NULL) {
err = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
fprintf(stderr, "Error opening file: %s\n", strerror( err ));
}else{
rewind(fp2);
printf("data in Buffer before write to destination : %s\n",buffer);
fclose(fp2);
}
source file contain
test kub test ah hahaha 5
Result
data in Buffer : �
size : 26
data in Buffer after fread(): test kub test
ah hahaha 5
U*
strlen in Buffer : 30
data in Buffer before write to destination : test kub test
ah hahaha 5
U*
The file size is 26 bytes I specify 26 bytes in fread() but in turns out buffer contain 30 characters
I use fread() because I have to write data in specific position in destination file also I added "\0" after fread() because I though it could help but it didn't work
**This is second time I face this problem.First time I specific amount of byte when read data from buffer to solve this problem but now I want to know
Why buffer keep more data than the source file and How to fix it.
--------------------Update----------------------------
I read all comment then
I followed user2225104 suggestion and It worked !
I replaced strcat(buffer,"\0"); with buffer[size] = '\0';
Thank you all for your answer it makes me know c programming better.
Result
data in Buffer : 0u
size : 26
data in Buffer after fread(): test kub test
ah hahaha 5
strlen in Buffer : 26
data in Buffer before write to destination : test kub test
ah hahaha 5
The problem is your attempt to 0-terminate and turn the block of chars into a c-string.
strcat(buffer,"\0");
only works if the first string is already 0-terminated. If it were, you would not need it. As you say yourself, your supposed string length is larger than your buffer. So you read some random 0 value behind your buffers end and then overwrite memory 1 byte behind it with your strcat() operation.
buffer[size] = '\0';
This way to do it does not assume buffer is a 0-terminated string and will not hamper with memory outside buffer.
On a side note, malloc() can return NULL. Best make it a habit to ALWAYS check the results of heap operation functions, just as checking results on file operations (e.g. fopen()). Basically anything which can go wrong at run-time and is not an invariant should be checked.
There's two kinds of strings in the programming world:
the Pascal kind of string (used by managed languages like C# and Java), where the size of the string is stored as an integer separately
the C kind of strings, where the size is indicated by a terminating "special" character
There's pros and cons for each of them, but the most important thing is that C style strings can't hold binary data -- the terminating character chosen by C is a valid character in a file (obviously).
So instead you emulate Pascal strings and call them "buffers", basically vectors of characters of some kind, with the size stored manually. You can see it in your malloc call, and again in your fread. Then you sort of black out and forget you wrote it and stop using it, but the size is still there, it's not part of the string.
Instead of printing it with printf (which expects null terminated C strings), you should use a character buffer function like fwrite to write it, and give it the size as an argument. Instead you're printing memory past what you allocated (since it doesn't end with 0), buffer overruning yourself. Generally hackers don't need your help, if they put their mind to it, they'll do it themselves :)
As a side note, you don't need size+1 characters -- there's no terminator as explained.
It's because your code is invalid.
fread(buffer,size,1,fp1);
Here you are ignoring the count returned by fread(), which tells you how many bytes have just been read into the buffer.
strcat(buffer,"\0");
Here you are pointlessly appending a null character after the first null character in the buffer. Remove it.
printf("data in Buffer after fread(): %s\n",buffer);
Here again you are ignoring the count. Assuming you used int count = fread(...), this line should be
printf("data in Buffer after fread(): %.*s\n",count,buffer);
Then:
int a = strlen(buffer);
This line is pointless. You shouldn't assume that I/O operations result in null-terminated C strings. There's nothing anywhere that guarantees that. Instead, you should use the count again. So
printf("strlen in Buffer : %d\n",a);
should be
printf("byte count in Buffer : %d\n",count);
EDIT: It has been proven in the comments that defining the length instead should produce the same results and would not use any significant extra data. If you are looking for a way to send data between machines running your program(s), sending the length is better than reading until a terminating character. BonzaiThePenguin has some very good points you should look at.
But for educational purposes: I never found good example code that does this for standard C sockets that handles situations where the data is not all received in one packet, or multiple separate messages are contained within one packet. Simply calling recv repeatedly will not work in all cases.
This is one of those questions where I've answered it myself below, but I'm not 100% confident in my response.
It isn't 'dangerous to allow the client to specify the size of the message it is sending'. Most of the protocols in the word do that, including HTTP and SSL. It's only dangerous when implementations don't bounds-check messages properly.
The fatal flaw with your suggestion is that it doesn't work for binary data: you have to introduce an escape character so that the terminating character can appear within a message, and then of course you also need to escape the escape. All this adds processing and data copying at both ends.
Here is what I came up with. I cannot guarantee that this is perfect because I am not a professional, so if there are any mistakes, I (and anyone else looking for help) would greatly appreciate it if someone would point them out.
Context: socket is the socket, buffer is the array that stores all network input, line is the array that stores just one message extracted from buffer (which is what the rest of your program uses), length is the length of both inputted arrays, and recvLength is a pointer to an integer stored outside of the function that is meant to be 0 initially and should not be freed or modified by anything else. That is, it should persist across multiple calls to this function on the same socket. This function returns the length of the data outputted in the line array.
size_t recv_line(int socket, char* buffer, char* line, size_t length, size_t* recvLength){ //receives until '\4' (EOT character) or '\0' (null character)
size_t readHead = 0;
size_t lineIndex = 0;
char currentChar = 0;
while (1){
for (; readHead < *recvLength; readHead = readHead + 1){
currentChar = buffer[readHead];
if (currentChar=='\4' || currentChar=='\0'){ //replace with the end character(s) of your choice
if (DEBUG) printf("Received message===\n%s\n===of length %ld\n", line, lineIndex+1);
memcpy(buffer, buffer + readHead + 1, length-(readHead)); //shift the buffer down
*recvLength -= (readHead + 1); //without the +1, I had an "off by 1" error before!
return lineIndex+1; //success
}
if (readHead >= length){
if (DEBUG) printf("Client tried to overflow the input buffer. Disconnecting client.\n");
*recvLength = 0;
return 0;
}
line[lineIndex] = currentChar;
lineIndex++;
}
*recvLength = recv(socket, buffer + readHead, length, 0);
}
printf("Unknown error in recv_line!\n");
return 0;
}
Simple example usage:
int function_listening_to_network_input(int socket){
char netBuffer[2048];
char lineBuffer[2048];
size_t recvLength = 0;
while (1==1){
size_t length = recv_line(socket, netBuffer, lineBuffer, 2048, &recvLength);
// handle it…
}
return 0;
}
Note that this does not always leave line as a null-terminated string. If you want it to, it's easy to modify.
I wonder about a buffer overflow in my app.
For example I have this code:
enum { BUFSIZE = 1024};
char username[this->BUFSIZE];
memset(username,0,BUFSIZE);
char password[this->BUFSIZE];
memset(password,0,BUFSIZE);
send(client_fd, "Login: ", BUFSIZE, 0);
recv(client_fd,username,sizeof(username),0)
Can a malicious attacker type more than 1024 chars and do a bof?
send(client_fd, "Login: ", BUFSIZE, 0);
-- For this statement, send will try to send BUFSIZE bytes though your string is only "Login: ". send doesn't inherently try to understand a 'C' string. It just recognizes a byte stream. So, your statement for send is incorrect.
recv(client_fd,username,sizeof(username),0)
-- In case of recv, though you have mentioned "sizeof(username)", it doesn't mean it will return "sizeof(username)" bytes, the number of bytes returned can be found out using the return value of recv. Never try to interpret the contents of the buffer passed to recv without checking the return value of recv. But, specifying sizeof(username) ensures that recv call will not return more than sizeof(username) bytes back even if more number of bytes are present in the network buffer.
Does C allow to place a string terminator at the end of read bytes full of garbage or is it only guaranteed if the read bytes are chars ?
I need to read something like this from stdin but I do not know how many chars to read and EOF is not guaranteed:
Hello World!---full of garbage until 100th byte---
char *var = malloc(100 + 1);
read(0, var, 100); // read from stdin. Unfortunately, I do not know how many bytes to read and stdin is not guaranteed to hold an EOF. (I chose 100 as an educated guess.)
var[100] = '\0'; // Is it possible to place a terminator at the end if most of the read bytes are garbage ?
read() returns the number of characters that were actually read into the buffer (or <0 in the case of an error). Hence the following should work:
int n;
char *var = malloc(100 + 1);
n = read(0, var, 100);
if(n >= 0)
var[n] = '\0';
else
/* error */
It is possible to place a terminator at the end, but the end result might be Hello World! and a long string of garbage after that.
Bytes are always chars. If you wanted to accept only printable characters (which the garbage at the end might contain, anyway) you could read the input one character at a time and check if each byte's value is between 0x20 and 0x7E.
Although that's only guaranteed to work with ASCII strings...