Ho un programma che scarica i dati pcap raccolti usando libpcap su stdout usando la funzione pcap_dump, con stdout come FILE *. C'è un po 'di pulizia necessaria su SIGINT, quindi lo gestisco con sigaction(). Funziona bene quando viene eseguito da una shell.Il segnale SIGINT viene eliminato durante la scrittura su una pipe
Tuttavia, questo programma è destinato a essere chiamato da un altro programma, che non sembra funzionare. Questo programma "chiamante" chiama un pipe(), quindi un fork(), quindi il descrittore del file stdout del figlio viene chiuso e sostituito con la fine della scrittura del pipe. Infine, il suddetto programma pcap viene eseguito nel processo figlio. In questo modo i dati di pcap vengono scritti nel programma chiamante attraverso la pipe. Anche questo funziona bene. Tuttavia, quando invio un SIGINT al processo figlio mentre sta scrivendo sulla pipe (beh, il programma pcap pensa che stia scrivendo su stdout, ma il suo descrittore di file è stato modificato), il segnale sembra essere caduto e la funzione di gestione del segnale non viene mai chiamato.
Perché è quello? Se scrivo i dati di pcap su stderr o su un file, SIGINT non viene mai rilasciato. Solo quando si scrive alla pipe.
Ecco come stiamo allestendo il tubo/forchetta/esecuzione:
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's stdout
dup(fd[1]); //duplicate child's 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]);
}
poi di uccidere il bambino che usiamo:
kill(pid, SIGINT);
Nel bambino, la funzione di callback per la nostra pcap_loop() può essere semplice come:
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
}
E in pratica abbandoneremo sempre SIGINT. A proposito, ci sono molti pacchetti da catturare, quindi è abbastanza sicuro presumere che sia quasi sempre nella funzione di callback.
Ma se ci si sposta dall'attuale
write(1,...); //write to stdout, which is really a pipe
a
write(2,...); //write to stderr, or writing to a file would work too
poi tutto diventa ancora rose e fiori.
Perché il nostro SIGINT viene lasciato cadere durante una scrittura su una pipe?
Grazie per l'aiuto.
MODIFICA: il gestore SIGINT del bambino non è mai stato chiamato, ma il motivo non era un problema nel bambino, era un problema nel genitore. Ho usato per uccidere il bambino come:
if(kill(pid, SIGINT) == -1){
perror("Could not kill child");
}
close(pipefd);
fprintf(stdout, "Successfully killed child\n");
E questo era il nostro gestore di SIGCHLD:
void handlesigchild(int sig) {
wait();
printf("Cleaned up a child\n");
}
Così, come descritto nella risposta accettata, chiudendo immediatamente il tubo stava causando il nostro bambino per uscire con SIGPIPE prima che il SIGINT venisse gestito. Abbiamo appena spostato il close (pipefd) al gestore SIGCHLD e ora funziona.
Benvenuti in Stack Overflow. Si prega di leggere la pagina [Informazioni] a breve. In generale, dovresti scegliere C o C++ come tag del linguaggio e non entrambi - perché le soluzioni adatte al C++ di solito non sono adatte a C, e spesso succede anche il contrario. –
Cosa mostra l'esecuzione dei processi sotto 'strace'? (Supponendo che Linux sia il tuo sistema operativo) Inoltre, pubblica il tuo codice di gestione dei segnali. –
Potrebbe essere perché il gestore del segnale (supponendo che ne abbiate uno) non chiude il tubo (che è attualmente in uso)? Forse vale la pena provare. – Addison