SIGINT signal drops when recording to pipe

I have a program that flushes pcap data collected using libpcap in stdout using the pcap_dump function, with stdout as FILE *. SIGINT needs a bit of cleanup, so I handle this with sigaction (). This works well when executed from the shell.

However, this program is intended to be called by another program that does not seem to work. This β€œcalling” program calls pipe (), then fork (), then the descriptor of the stdout file of the child user closes and is replaced by the end of the record in the pipe. Finally, the above pcap program is executed in the child process. In this way, pcap data is written to the caller's program through the channel. This also works well. However, when I send SIGINT to the child process while writing to the pipe (well, pcap thinks it is being written to stdout, but its file descriptor has been changed), the signal seems to drop and the signal handler function is never called at all .

Why? If I write pcap data to stderr or a file, SIGINT will never be discarded. Only when recording to the handset.

This is how we configure pipe / fork / execute:

int fd[2]; //Create pipe pipe(fd); pid = fork(); //We forked a child if(pid == 0){ //We are the child now close(1); //close child stdout dup(fd[1]); //duplicate child stdout to the write end of the pipe close( fd[0]); //close unused file descriptors close( fd[1]); //Load the new program execlp("./collectraw", "collectraw", NULL); perror("Exec"); exit(127); //Should never get called but we leave it so the child //doesnt accidently keep executing } else{ //We are the parent //Set up the file descriptors close(fd[1]); } 

then, to kill the child we use:

 kill( pid, SIGINT); 

In the child case, the callback function for our pcap_loop () can be as simple as:

 void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){ write(1,"<pretend this is like a thousand zeros>",1000); //write to stdout, which is really a pipe } 

And we basically will always throw SIGINT. There are many packages to capture by the way, so it’s pretty safe to assume that it is almost always in the callback function.

But if we move from

 write(1,... ); //write to stdout, which is really a pipe 

to

 write(2,...); //write to stderr, or writing to a file would work too 

then everything becomes gloomy again.

Why did our SIGINT crash while recording to the channel?

Thanks for the help.

EDIT: the child SIGINT handler was never called at all, but the reason was not a problem for the child, it was a problem in the parent. I killed a child like:

 if( kill( pid, SIGINT) == -1){ perror("Could not kill child"); } close(pipefd); fprintf(stdout, "Successfully killed child\n"); 

And this used to be our SIGCHLD handler:

 void handlesigchild(int sig) { wait(); printf("Cleaned up a child\n"); } 

So, as described in the accepted answer, closing the pipe immediately caused our child to exit SIGPIPE before SIGINT processing. We just moved close (pipefd) to the SIGCHLD handler, and now it works.

+6
source share
1 answer

You do not show enough of your code to know what is happening. You should always try to build SSCCE and post it if you want people to be able to comment on your program.

Best guess: your parent exits after sending the signal, closing the read end of the pipe. This forces the client to exit SIGPIPE immediately before it can process SIGINT. Try cleaning on SIGPIPE, or ignore SIGPIPE.

+2
source

Source: https://habr.com/ru/post/988125/


All Articles