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);
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,... );
to
write(2,...);
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.