I want to have a Perl daemon listen for and accept an incoming connection from a client, and then fork & exec another Perl program to continue the conversation with the client.
I can do this fine when simply forking - where the daemon code also contains the child's code. But I don't see how the open socket can be "passed" across an exec() to another Perl program.
Somehow I got the impression that this was easy in Unix (which is my environment) and therefore in Perl, too. Can it actually be done?
This can be done in approximately three steps:
1. Perl (by default) sets the close-on-exec flag on file descriptors it opens. This means file descriptors won't be preserved across an exec
. You have to clear this flag first:
use Fcntl;
my $flags = fcntl $fh, F_GETFD, 0 or die "fcntl F_GETFD: $!";
fcntl $fh, F_SETFD, $flags & ~FD_CLOEXEC or die "fcntl F_SETFD: $!";
2. Now that the file descriptor will stay open across exec
, you need to tell the program which descriptor it is:
my $fd = fileno $fh;
exec 'that_program', $fd; # pass it on the command line
# (you could also pass it via %ENV or whatever)
3. Recover the filehandle on the other side:
my $fd = $ARGV[0]; # or however you passed it
open my $fh, '+<&=', $fd; # fdopen
$fh->autoflush(1); # because "normal" sockets have that enabled by default
Now you have a Perl-level handle in $fh
again.
Addendum: As ikegami mentioned in a comment, you can also make sure the socket is using one of the three "standard" file descriptors (0 (stdin), 1 (stdout), 2 (stderr)) which are 1. left open by default across execs, 2. have known numbers so no need to pass anything, and 3. perl will create corresponding handles for them automatically.
open STDIN, '+<&', $fh; # now STDIN refers to the socket
exec 'that_program';
Now that_program
can simply use STDIN
. This works even for output; there is no inherent restriction on file descriptors 0, 1, 2 that they be for input or output only. It's just a convention that all unix programs follow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With