close_on_exec in Perl : close socket opened in parent process whenfork child , is not working

  • Thread starter 陈云星
  • Start date
É

陈云星

I open a socket in my main perl program,
than i execute a shell script :'/home/admin/t.sh', when i use CTRL-C to interrupt the perl program, i saw that the port '4444' was already openning bythe shell script's program。

so,how to close the socket fd when the `system` function was executed ?

the $^F variable is unuseful.

very thanks !


1 #!/bin/env perl
2 use Linux::Inotify2;
3 use Modern::perl;
4 use Mojo::IOLoop;
5
6 $^F=0;
7 Mojo::IOLoop->server({
8 port => 4444,
9 },sub{
10 my ($stream,$chunk) = @_;
11 $stream->write('HTTP/1.1 200 OK');
12 print " I am server \n";
13 });
14
15 system('/home/admin/t.sh &>/dev/null &');
16
17 Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
 
R

Rainer Weikusat

Ben Morrow said:
Quoth =?UTF-8?B?6ZmI5LqR5pif?= <[email protected]>:
[...]
1 #!/bin/env perl
2 use Linux::Inotify2;
3 use Modern::perl;
4 use Mojo::IOLoop;
5
6 $^F=0;

Don't do that. If you should manage to end up with fds less than 2 with
the close-on-exec bit set, you will probably confuse any process you
exec.

That's sort of an understatement: The way UNIX(*) 'file descriptor
creating' calls work is that a newly created file descriptor will
always use the lowest available file descriptor number. This means
that if file descriptor 2 ('stderr') is closed, the next file
descriptor created by a program running in this environment (assuming
0 and 1 are still open) will have the number 2 and anything which
writes 'to the standard error output' in the program will henceforth
use this file descriptor. It is very likely that the code of the
program wasn't written with this possibility in mind and that the
'thing' which is now referred to by the former stderr descriptor is
actually supposed to be used for something completely different, eg, a
TCP connection to some remote server who doesn't expect random
diagnostic output but communication conforming to some kind of
application protocol.
 
R

Rainer Weikusat

Ben Morrow said:
Well, normally the answer would be 'set the close-on-exec flag', but it
is usually set by default on newly-opened filehandles since $^F is
usually 2. That means Mojo::IOLoop is going out of its way to clear the
flag, which suggests perhaps you should leave it that way.

Should this be the case, this 'suggests' that 'MoJo' is seriously
broken in this respect: A listening file descriptor which 'leaks'
through to an independent program in this way will prevent the actual
server from being restarted until this independent program has
terminated because the bind call in the server will fail with
EADDRINUSE for as long as it is still 'sitting' on this socket. That's
the kind of errors which makes people reboot 24x7 'server computers' in
despair because 'some important program' can't be started and no one
understands why (even if someone understands why, 'go hunting for the
leaked descriptor to terminate the offending process' may be seriously
onerous in a sufficiently hostile environment[*]).

[*] A 'sufficiently hostile environment' I remember would be the
'NS-BSD' BSD-based NetASQ firewall OS where this problem would
occasionally prevent restarting the process which provided 'the
GUI'. I ended up with writing a Perl script which correlated the fstat
and netstat output together (IIRC), based on the kernel addresses of
'tcp socket control blocks', this being the only way to determine
which process had a particular fd open in that environment. And I
wasn't really one of the support people supposed to deal with these
beasts, the problem only reached me because this device couldn't be
rebooted and everybody else was at his wits end (which is completely
ok for a non-programmer confronted with *this*).
 
C

C.DeRykus

I open a socket in my main perl program,

than i execute a shell script :'/home/admin/t.sh', when i use CTRL-C to interrupt the perl program, i saw that the port '4444' was already openning by the shell script's program。



so,how to close the socket fd when the `system` function was executed ?



the $^F variable is unuseful.



very thanks !





1 #!/bin/env perl

2 use Linux::Inotify2;

3 use Modern::perl;

4 use Mojo::IOLoop;

5

6 $^F=0;

7 Mojo::IOLoop->server({

8 port => 4444,

9 },sub{

10 my ($stream,$chunk) = @_;

11 $stream->write('HTTP/1.1 200 OK');

12 print " I am server \n";

13 });

14

15 system('/home/admin/t.sh &>/dev/null &');

16

17 Mojo::IOLoop->start unless Mojo::IOLoop->is_running;


Other options would definitely be preferable but if
you need to close only this particular descriptor
you could close it in the shell, eg,

my $fd = fileno($some_socket_stream);
system("exec $fd <&-; /home/admin/t.sh ....");
 
R

Rainer Weikusat

Ben Morrow said:
Quoth Rainer Weikusat said:
Ben Morrow <[email protected]> writes:
[...]
Should this be the case, this 'suggests' that 'MoJo' is seriously
broken in this respect: A listening file descriptor which 'leaks'
through to an independent program in this way will prevent the actual
server from being restarted until this independent program has
terminated because the bind call in the server will fail with
EADDRINUSE for as long as it is still 'sitting' on this socket.

I wouldn't call it 'broken'. It is no longer usual for Perl programs of
the sort which use frameworks like Mojo to exec external programs, so
the question of random programs inheriting your fds shouldn't normally
arise.

Is this documented? If so, it's a misfeature. If not, it's another
case of "it works on my laptop !!1" (and - surely - no one would ever
think of doing anything I NEVER do !!2), IOW, it's broken and the
people who wrote the perl code knew better.
It looks as though Mojo clears the CLOEXEC bit because under some
circumstance your program will run as a long-running daemon, and it
periodically re-execs itself to start from a clean slate.

If this is the case, it looks suspiciously like "the Mojo code
contains serious bugs the developers neither understand nor care about
and they thought periodically invoking exec would be a great
workaround even if this means that 'exec without preautions' will be
broken for everyone else despite the perl documentation claims that
perl deals with this without application programmers having to worry
about that". In particular, this suggests that 'Mojo' leaks memory.
 
É

陈云星

You are right, I use following code , watch /proc/2312/fd , find that shellscript does not hold any socket fd.

this should be the mojolicious's problem.

$cat t.pl
#!/bin/env perl
use Modern::perl;
use IO::Socket; # or Socket;

$^F=2;

# server
my $server_port = 4444;
my $server = IO::Socket::INET->new(
LocalPort => $server_port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10)
or die "Couldn't be a tcp server on port $server_port:$!\n";
my $client;
while($client = $server->accept()){
say 'client connected ...';
system('/home/admin/t.sh &>/dev/null &');

}



在 2013å¹´1月17日星期四UTC+8下åˆ7æ—¶14分32秒,Ben Morrow写é“:
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top