I'm trying to use gpg to encrypt data in realtime. I'm already using libgcrypt directly but i need a standard format. I discarded gpgme since it did not seem suitable for a realtime stream application.
What I would like to accomplish is this command line:
gpg --passphrase hackerpass --symmetric -c
in the terminal it works well, print header, out the data and ends with the footer with a EOF CTRL-D, perfect!
This is the sample code, simple fork, bidirectional pipe, i write the data and wait the result asynchronously but... the execution of gpg does not end, in reality it seems that the data does not arrive, i receive only the header, at fd close gpg does not receive EOF:
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
pid_t pid = 0;
int inpipefd[2];
int outpipefd[2];
char buf[256];
int status;
pipe(inpipefd);
pipe(outpipefd);
pid = fork();
if (pid == 0) {
// Child
dup2(outpipefd[0], STDIN_FILENO);
dup2(inpipefd[1], STDOUT_FILENO);
//dup2(inpipefd[1], STDERR_FILENO);
//ask kernel to deliver SIGTERM in case the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM);
execlp("/bin/sh", "/bin/sh", "-c", "/usr/bin/gpg --passphrase pass --symmetric -c", (char *) NULL);
exit(1);
}
//close unused pipe ends
close(outpipefd[0]);
close(inpipefd[1]);
int flags;
flags = fcntl(inpipefd[0], F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(inpipefd[0], F_SETFL, flags);
// write example data
char *data = "dummy dummy";
ssize_t out = write(outpipefd[1], data, strlen(data));
if (out != strlen(data)) {
printf("fail write\n");
exit(-1);
}
close(outpipefd[1]);
int hasPendingData = 1;
while (hasPendingData) {
ssize_t r = read(inpipefd[0], buf, 255);
if (r == -1 && errno == EAGAIN) {
// in process
printf("no data available, wait...\n");
usleep(500000);
} else if (r > 0) {
printf("Incoming %ld bytes\n", (long) r);
} else {
// EOF
hasPendingData = 0;
printf("no mode data available, exit...\n");
}
}
waitpid(pid, &status, 0);
return 0;
}
Just a guess here, but you have several unclosed duplicate file descriptors in the sub-process. Gpg won't get EOF until those file descriptors are closed. As long as any process could possible write to them, it will just keep waiting for more.
Another thing to watch out for is the gpg blocking while writing waiting for your process to read the pipe. If that happens, your writing stage could then get blocked. Won't happen with very small amounts of data but could happen later if you put any volume through. Both write and read need to be non-blocking and running simultaneously.