line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RPC::ExtDirect::Server::Util; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
216751
|
use strict; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
108
|
|
4
|
5
|
|
|
5
|
|
16
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
110
|
|
5
|
5
|
|
|
5
|
|
692
|
no warnings 'uninitialized'; ## no critic |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
164
|
|
6
|
|
|
|
|
|
|
|
7
|
5
|
|
|
5
|
|
15
|
use Carp; |
|
5
|
|
|
|
|
5
|
|
|
5
|
|
|
|
|
238
|
|
8
|
5
|
|
|
5
|
|
2241
|
use Socket; |
|
5
|
|
|
|
|
12869
|
|
|
5
|
|
|
|
|
1797
|
|
9
|
5
|
|
|
5
|
|
6738
|
use Getopt::Std; |
|
5
|
|
|
|
|
145
|
|
|
5
|
|
|
|
|
226
|
|
10
|
5
|
|
|
5
|
|
21
|
use Exporter; |
|
5
|
|
|
|
|
5
|
|
|
5
|
|
|
|
|
121
|
|
11
|
|
|
|
|
|
|
|
12
|
5
|
|
|
5
|
|
1833
|
use RPC::ExtDirect::Server; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
148
|
|
13
|
|
|
|
|
|
|
|
14
|
5
|
|
|
5
|
|
19
|
use base 'Exporter'; |
|
5
|
|
|
|
|
4
|
|
|
5
|
|
|
|
|
4554
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our @EXPORT = qw/ |
17
|
|
|
|
|
|
|
maybe_start_server |
18
|
|
|
|
|
|
|
start_server |
19
|
|
|
|
|
|
|
stop_server |
20
|
|
|
|
|
|
|
/; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
### PRIVATE PACKAGE SUBROUTINES ### |
23
|
|
|
|
|
|
|
# |
24
|
|
|
|
|
|
|
# Internal use only. |
25
|
|
|
|
|
|
|
# |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
{ |
28
|
|
|
|
|
|
|
my ($server_pid, $server_host, $server_port, $dont_stop); |
29
|
|
|
|
|
|
|
|
30
|
5
|
|
|
5
|
0
|
9
|
sub get_server_pid { $server_pid }; |
31
|
8
|
|
|
8
|
0
|
49
|
sub set_server_pid { $server_pid = shift; }; |
32
|
|
|
|
|
|
|
|
33
|
3
|
|
|
3
|
0
|
4
|
sub get_server_host { $server_host }; |
34
|
3
|
|
|
3
|
0
|
9
|
sub set_server_host { $server_host = shift }; |
35
|
|
|
|
|
|
|
|
36
|
3
|
|
|
3
|
0
|
3
|
sub get_server_port { $server_port }; |
37
|
8
|
|
|
8
|
0
|
18
|
sub set_server_port { $server_port = shift; }; |
38
|
|
|
|
|
|
|
|
39
|
5
|
|
|
5
|
0
|
30
|
sub get_no_shutdown { $dont_stop }; |
40
|
0
|
|
|
0
|
1
|
0
|
sub no_shutdown { $dont_stop = shift; }; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
### EXPORTED PUBLIC PACKAGE SUBROUTINE ### |
44
|
|
|
|
|
|
|
# |
45
|
|
|
|
|
|
|
# See if a host and port were given in the @ARGV, and start a new |
46
|
|
|
|
|
|
|
# server instance if not. |
47
|
|
|
|
|
|
|
# |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub maybe_start_server { |
50
|
3
|
50
|
|
3
|
1
|
272
|
if ( @ARGV ) { |
51
|
0
|
|
|
|
|
0
|
my %opt; |
52
|
|
|
|
|
|
|
|
53
|
0
|
|
|
|
|
0
|
getopts('h:p:fes:t:l:', \%opt); |
54
|
|
|
|
|
|
|
|
55
|
0
|
0
|
|
|
|
0
|
if ( $opt{p} ) { |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# If a port is given but not the host name, |
58
|
|
|
|
|
|
|
# we assume localhost |
59
|
0
|
|
0
|
|
|
0
|
my $host = $opt{h} || '127.0.0.1'; |
60
|
0
|
|
|
|
|
0
|
my $port = $opt{p}; |
61
|
|
|
|
|
|
|
|
62
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($host, $port) : "$host:$port"; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Not quoting $opt{s} makes my text editor lose its mind ;) |
66
|
0
|
0
|
|
|
|
0
|
push @_, static_dir => $opt{'s'} if $opt{'s'}; |
67
|
0
|
0
|
|
|
|
0
|
push @_, foreground => 1 if $opt{f}; |
68
|
0
|
0
|
|
|
|
0
|
push @_, enbugger => 1 if $opt{e}; |
69
|
0
|
0
|
|
|
|
0
|
push @_, enbugger_timer => $opt{t} if defined $opt{t}; |
70
|
0
|
0
|
|
|
|
0
|
push @_, host => $opt{h} if defined $opt{h}; |
71
|
0
|
0
|
|
|
|
0
|
push @_, port => $opt{l} if defined $opt{l}; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
3
|
|
|
|
|
9
|
return start_server( @_ ); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
### EXPORTED PUBLIC PACKAGE SUBROUTINE ### |
78
|
|
|
|
|
|
|
# |
79
|
|
|
|
|
|
|
# Start an RPC::ExtDirect::Server instance, wait for it to bind |
80
|
|
|
|
|
|
|
# to a port and return the host and port number. |
81
|
|
|
|
|
|
|
# If an instance has already been started, return its parameters |
82
|
|
|
|
|
|
|
# instead of starting a new one. |
83
|
|
|
|
|
|
|
# |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub start_server { |
86
|
3
|
|
|
3
|
1
|
8
|
my (%arg) = @_; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
{ |
89
|
3
|
|
|
|
|
3
|
my $host = get_server_host; |
|
3
|
|
|
|
|
7
|
|
90
|
3
|
|
|
|
|
7
|
my $port = get_server_port; |
91
|
|
|
|
|
|
|
|
92
|
3
|
50
|
|
|
|
9
|
if ( $port ) { |
93
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($host, $port) : "$host:$port"; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# This parameter is used for internal testing |
98
|
3
|
|
|
|
|
5
|
my $sleep = delete $arg{sleep}; |
99
|
3
|
|
|
|
|
6
|
my $foreground = delete $arg{foreground}; |
100
|
3
|
|
|
|
|
4
|
my $enbugger = delete $arg{enbugger}; |
101
|
3
|
|
|
|
|
5
|
my $enbugger_timer = delete $arg{set_timer}; |
102
|
3
|
|
50
|
|
|
15
|
my $timeout = delete $arg{timeout} || 30; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Debug flag is checked below to avoid printing the banner |
105
|
3
|
50
|
|
|
|
8
|
my $server_debug = $arg{config} ? $arg{config}->debug : $arg{debug}; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# We default to verbose exceptions, which is against Ext.Direct spec |
108
|
|
|
|
|
|
|
# but feels somewhat saner and is better for testing |
109
|
3
|
50
|
|
|
|
9
|
$arg{verbose_exceptions} = 1 unless defined $arg{verbose_exceptions}; |
110
|
|
|
|
|
|
|
|
111
|
3
|
50
|
|
|
|
8
|
if ( $enbugger ) { |
112
|
0
|
|
|
|
|
0
|
local $@; |
113
|
0
|
|
|
|
|
0
|
eval "require Enbugger"; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Interactive start means we're not forking but running the server |
117
|
|
|
|
|
|
|
# in the current process. Useful for Enbugging. |
118
|
3
|
50
|
|
|
|
7
|
if ( $foreground ) { |
119
|
0
|
0
|
|
|
|
0
|
if ( $enbugger_timer ) { |
120
|
0
|
|
|
|
|
0
|
my $old_alarm = $SIG{ALRM}; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
$SIG{ALRM} = sub { |
123
|
0
|
|
|
0
|
|
0
|
alarm 0; |
124
|
0
|
|
|
|
|
0
|
$SIG{ALRM} = $old_alarm; |
125
|
0
|
|
|
|
|
0
|
Enbugger->stop; |
126
|
0
|
|
|
|
|
0
|
}; |
127
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
0
|
alarm $enbugger_timer; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
do_start_server( |
132
|
|
|
|
|
|
|
%arg, |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
after_listener => sub { |
135
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
my $host = $self->host; |
138
|
0
|
|
|
|
|
0
|
my $port = $self->port; |
139
|
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
0
|
print ref($self)." is listening on $host:$port\n" |
141
|
|
|
|
|
|
|
unless $server_debug; |
142
|
|
|
|
|
|
|
} |
143
|
0
|
|
|
|
|
0
|
); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# This should be unreachable, but just in case |
146
|
0
|
|
|
|
|
0
|
exit 0; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
3
|
|
|
|
|
4
|
my ($pid, $pipe_rd, $pipe_wr); |
150
|
3
|
50
|
|
|
|
57
|
pipe($pipe_rd, $pipe_wr) or die "Can't open pipe: $!"; |
151
|
|
|
|
|
|
|
|
152
|
3
|
50
|
0
|
|
|
2386
|
if ( $pid = fork ) { |
|
|
0
|
|
|
|
|
|
153
|
3
|
|
|
|
|
85
|
close $pipe_wr; |
154
|
3
|
|
|
0
|
|
274
|
local $SIG{CHLD} = sub { waitpid $pid, 0 }; |
|
0
|
|
|
|
|
0
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Wait until the kid starts up, but don't block forever either |
157
|
3
|
|
|
|
|
35
|
my ($host, $port) = eval { |
158
|
3
|
|
|
0
|
|
76
|
local $SIG{ALRM} = sub { die "alarm\n" }; |
|
0
|
|
|
|
|
0
|
|
159
|
3
|
|
|
|
|
29
|
alarm $timeout; |
160
|
|
|
|
|
|
|
|
161
|
3
|
|
|
|
|
7689
|
my ($host, $port) = split /:/, <$pipe_rd>; |
162
|
3
|
|
|
|
|
48
|
close $pipe_rd; |
163
|
|
|
|
|
|
|
|
164
|
3
|
|
|
|
|
22
|
alarm 0; |
165
|
|
|
|
|
|
|
|
166
|
3
|
|
|
|
|
46
|
($host, $port + 0); # Easier than chomp |
167
|
|
|
|
|
|
|
}; |
168
|
|
|
|
|
|
|
|
169
|
3
|
50
|
|
|
|
20
|
if ( my $err = $@ ) { |
170
|
|
|
|
|
|
|
# If timed out, try to clean up the kid anyway |
171
|
0
|
|
|
|
|
0
|
eval { kill 2, $pid }; |
|
0
|
|
|
|
|
0
|
|
172
|
|
|
|
|
|
|
|
173
|
0
|
0
|
|
|
|
0
|
croak $err eq "alarm\n" ? "Timed out waiting for " . |
174
|
|
|
|
|
|
|
"the server instance to start " . |
175
|
|
|
|
|
|
|
"after $timeout seconds" |
176
|
|
|
|
|
|
|
: $err |
177
|
|
|
|
|
|
|
; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
3
|
|
|
|
|
37
|
set_server_pid($pid); |
181
|
3
|
|
|
|
|
10
|
set_server_host($host); |
182
|
3
|
|
|
|
|
7
|
set_server_port($port); |
183
|
|
|
|
|
|
|
|
184
|
3
|
50
|
|
|
|
85
|
return wantarray ? ($host, $port) |
185
|
|
|
|
|
|
|
: "$host:$port" |
186
|
|
|
|
|
|
|
; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
elsif ( defined $pid && $pid == 0 ) { |
189
|
0
|
|
|
|
|
0
|
close $pipe_rd; |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
0
|
srand; |
192
|
|
|
|
|
|
|
|
193
|
0
|
0
|
|
|
|
0
|
sleep $sleep if $sleep; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
do_start_server( |
196
|
|
|
|
|
|
|
%arg, |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
after_listener => sub { |
199
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
0
|
my $host = inet_ntoa inet_aton $self->host; |
202
|
0
|
|
|
|
|
0
|
my $port = $self->port; |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
0
|
print $pipe_wr "$host:$port\n"; |
205
|
0
|
|
|
|
|
0
|
close $pipe_wr; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
my $after_setup_listener |
208
|
0
|
|
|
|
|
0
|
= $self->{_old_after_setup_listener}; |
209
|
|
|
|
|
|
|
|
210
|
0
|
0
|
|
|
|
0
|
$after_setup_listener->($self, @_) |
211
|
|
|
|
|
|
|
if $after_setup_listener; |
212
|
|
|
|
|
|
|
} |
213
|
0
|
|
|
|
|
0
|
); |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Should be unreachable, just in case |
216
|
0
|
|
|
|
|
0
|
exit 0; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
else { |
219
|
0
|
|
|
|
|
0
|
croak "Can't fork: $!"; |
220
|
|
|
|
|
|
|
}; |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
0
|
return; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
### EXPORTED PUBLIC PACKAGE SUBROUTINE ### |
226
|
|
|
|
|
|
|
# |
227
|
|
|
|
|
|
|
# Stop previously started server instance |
228
|
|
|
|
|
|
|
# |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub stop_server { |
231
|
5
|
|
|
5
|
1
|
9
|
my ($pid) = @_; |
232
|
|
|
|
|
|
|
|
233
|
5
|
50
|
|
|
|
24
|
$pid = get_server_pid unless defined $pid; |
234
|
|
|
|
|
|
|
|
235
|
5
|
100
|
|
|
|
83
|
kill 2, $pid if defined $pid; |
236
|
|
|
|
|
|
|
|
237
|
5
|
|
|
|
|
16
|
set_server_port(undef); |
238
|
5
|
|
|
|
|
13
|
set_server_pid(undef); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
############## PRIVATE METHODS BELOW ############## |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
### PRIVATE PACKAGE SUBROUTINE ### |
244
|
|
|
|
|
|
|
# |
245
|
|
|
|
|
|
|
# Try to start the server, re-rolling port randomizer |
246
|
|
|
|
|
|
|
# if the old port is taken |
247
|
|
|
|
|
|
|
# |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub do_start_server { |
250
|
0
|
|
|
0
|
0
|
|
my (%arg) = @_; |
251
|
|
|
|
|
|
|
|
252
|
0
|
|
|
|
|
|
my $forced_port = defined $arg{port}; |
253
|
0
|
|
|
|
|
|
my $after_listener = delete $arg{after_listener}; |
254
|
|
|
|
|
|
|
my $server_class = delete $arg{server_class} || |
255
|
0
|
|
0
|
|
|
|
'RPC::ExtDirect::Server'; |
256
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
|
if ( !$forced_port ) { |
258
|
0
|
|
|
|
|
|
$arg{port} = random_port(); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
my $server = $server_class->new(%arg); |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# TODO This is a dirty hack - find a better way of |
264
|
|
|
|
|
|
|
# injecting after_setup_listener. Maybe send a patch |
265
|
|
|
|
|
|
|
# to HTTP::Server::Simple maintainer to make this easier? |
266
|
0
|
0
|
|
|
|
|
if ( $after_listener ) { |
267
|
|
|
|
|
|
|
$server->{_old_after_setup_listener} |
268
|
0
|
|
|
|
|
|
= $server_class->can('after_setup_listener'); |
269
|
|
|
|
|
|
|
|
270
|
5
|
|
|
5
|
|
24
|
no strict 'refs'; |
|
5
|
|
|
|
|
4
|
|
|
5
|
|
|
|
|
668
|
|
271
|
0
|
|
|
|
|
|
*{$server_class.'::after_setup_listener'} = $after_listener; |
|
0
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# If the port is taken, reroll the random generator and try again |
275
|
0
|
|
|
|
|
|
do { |
276
|
0
|
|
|
|
|
|
eval { $server->run() }; |
|
0
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# If the port was forced by the caller, punt |
279
|
0
|
0
|
0
|
|
|
|
croak "$@\n" if $forced_port && $@; |
280
|
|
|
|
|
|
|
|
281
|
0
|
|
|
|
|
|
$server->port( random_port() ); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
while ( $@ ); |
284
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
return 1; # This should be unreachable |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
### PRIVATE PACKAGE SUBROUTINE ### |
289
|
|
|
|
|
|
|
# |
290
|
|
|
|
|
|
|
# Generate a random port for the server to listen on |
291
|
|
|
|
|
|
|
# |
292
|
|
|
|
|
|
|
|
293
|
0
|
|
|
0
|
0
|
|
sub random_port { 30000 + int rand 10000 }; |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Ensure that the server is stopped cleanly at exit |
296
|
5
|
50
|
|
5
|
|
169739
|
END { stop_server unless get_no_shutdown } |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
1; |