Read / Write through a pipe in C - c

I started today working with pipe() and fork() and exec() in C, and I now have a problem:
The main program, creates two pipes and forks. The child process does an exec() to another program that now is only a test program which reads from stdin, communicates with its parent and writes through stdout ther results. The main program is supposed to recive data, communicate with a SQLite 3 database and return data using pipes. This part of the problem is solved, the pipes are open and closed properly and there's communication.
Then the problem is, in the child process (the one which is called with exec()) in a certain point, I have this:
printf("Strid sent: %s\n", strid);
write(4,strid,sizeof(strid));
printf("Str sent: %s\n", str);
write(4,str,sizeof(str));
And the parent should be reading properly with this part:
read(select[0],strid, sizeof(strid));
printf("Strid recived: %s\n",strid);
int id = atoi(strid);
printf("Id recived: %d\n",id);
read(select[0],buffer, sizeof(buffer));
printf("Buffer recived: %s\n",buffer);
But what I recive whith those printf is:
Strid sent: 1
Str sent: start
Strid recived: 1
Id recived: 1
Buffer recived: 7� (and other strange characters)
As you can see, the problem is in the receiving of the second command (and that part is copied as is, there's no other code into it).
I have to say too that "buffer" variable, which recives str, is declared as char buffer[20] and has not been used before the read()
Thank you in advance!

After read, you need to add terminating 0 byte at the end, before printing, something like
int len = read(select[0], buffer, sizeof(buffer) - 1);
if (len < 0) {
perror("read error");
} else {
buffer[len] = 0;
printf("Buffer recived: %s\n", buffer);
}
So, imporant thing, read through man page of read, or actually man page of any function before you use it...
Alternatively, use some stdio.h function, which adds string terminating 0 themselves, probably fgets if reading line by line is ok.

pipes don't keep track of 'boundaries' between writes. So if you have multiple writes on the pipe, all the data from those writes might come back in response to a single read. So if you send a string (for example) followed by an integer, and you attempt to read the string into a buffer, it will get both the string and the following integer integer into the buffer, looking like garbage on the end of the string, and the size returned by read will be larger.
In addition, if the pipe is getting full, a write might not write all the data you asked it to -- it might write only as much as can fit for now, and you'll have to write the rest later.
so ALWAYS check the return values of your read and write calls and be prepared to deal with getting less than (or more for read) than you expect.

Related

Why won't the output of the client be printed to the screen?

I'm trying to inject remote code through sockets, but for some reason, when writing the command cd or any other command, which in turn gives me an answer through the client, the answer won't be outputted to the screen.
I've tried various ways of outputting to the screen but none of them work.
Server part which outputs:
void *ReadAndWriteSocket(void *entrypoint) {
char message[256];
char buffer[256];
while (1) {
if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) {
for(int i = 0; i < strlen(buffer) - 1; i++) {
printf("%s", buffer[i]);
}
}
}
scanf("%s", &message);
send(sockStructure.newsockfd, message, strlen(message), 0);
}
Client code:
require 'socket'
require 'open3'
def createClient(hostname, port)
s = TCPSocket.new hostname, port
while line = s.gets
if line == "exit"
s.close
elsif line[0..1] == "cd"
output = Dir.chdir(Dir.pwd + "/" + line[2..line.size].delete(" \t\n\r\0"))
s.puts(Dir.pwd)
end
stdin, stdout, stderr, wait_thr = Open3.popen3(line)
s.puts("#{stdout.read}")
end
end
createClient("127.0.0.1", 8082);
As soon as you receive even the tiniest drop of data, you block in scanf rather than trying to receive more data. You either need to support moving data in both directions at the same time (waiting for input in scanf and data in recv) at the same time or you need to be smarter about when you change the direction.
Consider the following scenario:
You call ReadAndWriteSocket.
Your call to recv gets just an "H", the very first byte of the message.
You pass that "H" to printf, but nothing gets printed because your standard output is line buffered.
You call scanf and wait forever, but nothing is coming because the user has no intention of typing anything until they see the received message.
Your code will never call recv again, too bad since the rest of the received message is waiting in the receive buffer but you're stuck in scanf.
When you have code that moves data in two directions, you must be absolutely sure that you never block waiting to receive data in one direction when the data you should be waiting for is coming in the other direction. Your code has nothing to prevent this.
Update: Problems with your new code:
void *ReadAndWriteSocket(void *entrypoint) {
char message[256];
char buffer[256];
while (1) {
if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) {
What's going on here? You can only pass a string to strlen. But buffer doesn't contain a string here (it's uninitialized on the first pass and contains an unrelated length on subsequent passes). So you're passing a nonsensical value for the length to recv.
for(int i = 0; i < strlen(buffer) - 1; i++) {
printf("%s", buffer[i]);
Two problems here: First, buffer[i] is not a string and the %s format specifier is for strings. Second, standard output is line buffered, so unless the buffer happens to contain a line, it won't show.
}
}
}
scanf("%s", &message);
Why are you waiting for user input here? What if you only received a tiny fraction of the message and didn't even receive an entire line and so haven't ouputted anything yet? How do you know the next thing you need to do is receive input from the user and not receive the rest of the message?
send(sockStructure.newsockfd, message, strlen(message), 0);
}
If you have some protocol that specifies who will send when and who will receive when and what constitutes a message and when to wait for user input, you have to write code that implements that protocol. Otherwise, you'll get stuck in scanf waiting for input when there's data in the socket's receive buffer.

read(...): Will read remember the change?

On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number.
This is the description I copy from man 2 read, I have a question to "the file position is advanced by this number" this statement.
What I want to do in my code is the following:
for (int i = 1; i < argc; i++) {
if (read(pipe_fd[i-1][0], &contribution, sizeof(int)) == -1) {
perror("reading from pipe from a child");
exit(1);
}
if (i == argc){
i = 1;
}
}
I am trying to repeatedly read data from the pipes that connect each child process to my parent process, my question to this post is: will read remember when it should continue reading when next time I call read again?
For example, suppose I am calling read(pipe_fd[1][0], &contribution, sizeof(int)), from what I understand here, I know read will read sizeof(int) bytes from the pipe, and somehow use fseek call or something like that to move sizeof(int) bytes to the next new starting position. But when I loop through, and change i back to read(pipe_fd[1][0]) again, will read remember its last starting position? (which is after the first read call, the new starting position I describe above) Or read will just assume nothing happens and read from the initial starting position instead of the new starting position?
Pipes don't have a file position, but read(2) will give you all the data written to the other end of the pipe, in the same order (first in, first out). When you call read() the next time on the same fd, you will get the data that follows what you got from the previous call on that fd. This is typically what you want, and you don't need to do anything special in between.

How to receive full text in a text file into server in c?

I tried to implement the STOR command with text files. In the server I have code that receives files as string into the receive_buffer. Is there a way I could receive the string as a whole string into the buffer?
while (true)
{
if (active == 0)
{
bytes = recv(ns_data, receive_buffer, strlen(receive_buffer), 0);
}
else
{
recv(s_data_act, receive_buffer, strlen(receive_buffer), 0);
printf("len: %d\n", strlen(receive_buffer));
printf("receive_buffer: %s\n", receive_buffer);
}
printf("Receive_buffer: %s\n", receive_buffer);
strcpy(temp_buffer, receive_buffer);
printf("temp_buffer: %s\n", temp_buffer);
fputs(temp_buffer2, f);
At the moment, say for example there is a text file called text.txt and sample text in side "this is a word", the recv function only gets 4 characters at a time. So on the first loop it would get "this", on the second it would get " is ", and so forth. How can I just get the whole string into the receive buffer and terminate it when there is no more text in the file that it is reading from?
recv the way you're using it will read until there's no more data in the socket's buffer or your receive buffer is full, causing the behavior you see. There's no way to know when the file is done being received unless you build that into your protocol.
If the file is text only, you could terminate messages with a 0 byte (\0) and call recv repeatedly until you see that arrive (since \0 won't be in any text file). Or you could prepend all transmissions with a special header indicating the length. Both ways are unsafe if you aren't very careful.

Multiple input for running program

I have the following C program:
#include<stdio.h>
main()
{
char buf[64];
gets(buf);
printf("Your input: %s\n", buf);
gets(buf);
printf("Your input: %s\n", buf);
}
I want to send data to the program using pipes or redirection. The problem is that the program don't wait for the second gets to enter new data.
e.g
$ echo "a" | ./test
Output:
Your input: a
Your input: a
How can I send let the program wait for the user input at each gets using pipes or redirection.
P.S I don't have persmission to write to /proc/$pid/fd/0 and I don't have to change the code.
Any help would be appreciated.
If you use pipes | to input data to a command, it is disconnected from the (input portion) of your terminal. gets reads the first line "a\n" and writes this to the buf as "a\0". Then it hits the end of the pipe, or EOF (end of file).
Your second gets then does nothing (as there is nothing to read after EOF) and lets buf alone; buf still contains "a\0", which is duly printed.
Further hints:
When doing I/O, which can inherently fail at any time, you have to check for errors after each and every call, or bad things will happen. Train yourself to do this and save lots of debugging time.
Never do an I/O like gets(buf) because it will lead to buffer overflows, the bane of computing security. If you input arbitrary data, you must use a call that lets you limit the number of bytes written. The man page for gets contains the sentence "Never use this function" right at the top. You can find other, better functions, read being a baseline, and if you are in C++ there will be plenty of other standard solutions for that.

c pipe read string is empty

I just want to create 2 new forks(child processes) and they will put their name sequentally. SO first they need to some string in pipe to check something. Let's see the code:
char myname[] = "ALOAA";
int main ()
{
int fds[2];
pid_t pid;
pipe(fds);
pid = fork();
if(pid == 0)
{
strcpy(myname, "first");
}
else
{
pid = fork();
if(pid == 0)
{
strcpy(myname, "second");
}
}
if(strcmp(myname, "ALOAA") != 0)
{
char readbuffer[1025];
int i;
for (i = 0; i < 2 ; i++)
{
//printf("%s\n", myname);
close(fds[0]);
write(fds[1], myname, strlen(myname));
while(1)
{
close(fds[1]);
int n = read(fds[0], readbuffer, 1024);
readbuffer[n] = 0;
printf("%s-alihan\n", readbuffer);
if(readbuffer != myname)
break;
sleep(1);
}
//printf("%s\n", myname);
}
}
return 0;
}
So the first process will write her name to pipe. And after that, will check if any new string in pipe. It will be same for second too. However I got empty string from read() function. So it prints like that
-alihan
-alihan
I couldn't get the problem.
However I got empty string from read() function [...] I couldn't get the problem.
#MikeCAT nailed this issue with his observation in comments that each child closes fds[0] before it ever attempts to read from it. No other file is assigned the same FD between, so the read fails. You do not test for the failure.
Not testing for the read failure is a significant problem, because your program does not merely fail to recognize it -- it exhibits undefined behavior as a result. This arises for (at least) two reasons:
read() will have indicated failure by returning -1, and your program will respond by attempting an out-of-bounds write (to readbuffer[-1]).
if we ignore the UB resulting from (1), we still have the program thereafter reading from completely uninitialized array readbuffer (because neither the read() call nor the assignment will have set the value of any element of that array).
Overall, you need to learn the discipline of checking the return values of your library function calls for error conditions, at least everywhere that it matters whether an error occurred (which is for most calls). For example, your usage of pipe(), fork(), and write() exhibits this problem, too. Under some circumstances you want to check the return value of printf()-family functions, and you usually want to check the return value of input functions -- not just read(), but scanf(), fgets(), etc..
Tertiarily, your usage of read() and write() is incorrect. You make the common mistake of assuming that (on success) write() will reliably write all the bytes specified, and that read() will read all bytes that have been written, up to the specified buffer size. Although that ordinarily works in practice for exchanging short messages over a pipe, it is not guaranteed. In general, write() may perform only a partial write and read() may perform only a partial read, for unspecified, unpredictable reasons.
To write successfully one generally must be prepared to repeat write() calls in a loop, using the return value to determine where (or whether) to start the next write. To read complete messages successfully one generally must be prepared similarly to repeat read() calls in a loop until the requisite number of bytes have been read into the buffer, or until some other termination condition is satisfied, such as the end of the file being reached. I presume it will not be lost on you that many forms of this require advance knowledge of the number of bytes to read.

Resources