line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## Domain Registry Interface, TCP/SSL Socket Transport |
2
|
|
|
|
|
|
|
## |
3
|
|
|
|
|
|
|
## Copyright (c) 2005-2013,2016 Patrick Mevzek . All rights reserved. |
4
|
|
|
|
|
|
|
## |
5
|
|
|
|
|
|
|
## This file is part of Net::DRI |
6
|
|
|
|
|
|
|
## |
7
|
|
|
|
|
|
|
## Net::DRI is free software; you can redistribute it and/or modify |
8
|
|
|
|
|
|
|
## it under the terms of the GNU General Public License as published by |
9
|
|
|
|
|
|
|
## the Free Software Foundation; either version 2 of the License, or |
10
|
|
|
|
|
|
|
## (at your option) any later version. |
11
|
|
|
|
|
|
|
## |
12
|
|
|
|
|
|
|
## See the LICENSE file that comes with this distribution for more details. |
13
|
|
|
|
|
|
|
#################################################################################################### |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
package Net::DRI::Transport::Socket; |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
1319
|
use base qw(Net::DRI::Transport); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
74
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
17
|
|
20
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
21
|
|
|
|
|
|
|
|
22
|
1
|
|
|
1
|
|
4
|
use Time::HiRes (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
18
|
|
23
|
1
|
|
|
1
|
|
4
|
use IO::Socket::INET; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
24
|
|
|
|
|
|
|
## At least this version is needed, to have getline() |
25
|
1
|
|
|
1
|
|
1401
|
use IO::Socket::SSL 0.90; |
|
1
|
|
|
|
|
39294
|
|
|
1
|
|
|
|
|
9
|
|
26
|
1
|
|
|
1
|
|
219
|
use Scalar::Util (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
16
|
|
27
|
|
|
|
|
|
|
|
28
|
1
|
|
|
1
|
|
4
|
use Net::DRI::Exception; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
29
|
1
|
|
|
1
|
|
3
|
use Net::DRI::Util; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
17
|
|
30
|
1
|
|
|
1
|
|
3
|
use Net::DRI::Data::Raw; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=pod |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 NAME |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Net::DRI::Transport::Socket - TCP/TLS Socket connection for Net::DRI |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 DESCRIPTION |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
This module implements a socket (tcp or tls) for establishing connections in Net::DRI |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 METHODS |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
At creation (see Net::DRI C) you pass a reference to an hash, with the following available keys: |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head2 socktype |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
ssl, tcp or udp |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 ssl_key_file ssl_cert_file ssl_ca_file ssl_ca_path ssl_cipher_list ssl_version ssl_passwd_cb ssl_hostname |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
if C is 'ssl', all key materials, see IO::Socket::SSL documentation for corresponding options |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head2 ssl_verify |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
see IO::Socket::SSL documentation about verify_mode (by default 0x00 here) |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head2 ssl_verify_callback |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
see IO::Socket::SSL documentation about verify_callback, it gets here as first parameter the transport object |
62
|
|
|
|
|
|
|
then all parameter given by IO::Socket::SSL; it is explicitly verified that the subroutine returns a true value, |
63
|
|
|
|
|
|
|
and if not the connection is aborted. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head2 remote_host remote_port |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
hostname (or IP address) & port number of endpoint |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head2 client_login client_password |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
protocol login & password |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head2 client_newpassword |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
(optional) new password if you want to change password on login for registries handling that at connection |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=head2 protocol_connection |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Net::DRI class handling protocol connection details. (Ex: C or C) |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 protocol_data |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
(optional) opaque data given to protocol_connection class. |
84
|
|
|
|
|
|
|
For EPP, a key login_service_filter may exist, whose value is a code ref. It will be given an array of services, and should give back a |
85
|
|
|
|
|
|
|
similar array; it can be used to filter out some services from those given by the registry. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 close_after |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
number of protocol commands to send to server (we will automatically close and re-open connection if needed) |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head2 local_host |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
(optional) the local address (hostname or IP) you want to use to connect |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 SUPPORT |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
For now, support questions should be sent to: |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Enetdri@dotandco.comE |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Please also see the SUPPORT file in the distribution. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 SEE ALSO |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
http://www.dotandco.com/services/software/Net-DRI/ |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head1 AUTHOR |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Patrick Mevzek, Enetdri@dotandco.comE |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 COPYRIGHT |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Copyright (c) 2005-2013,2016 Patrick Mevzek . |
114
|
|
|
|
|
|
|
All rights reserved. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
117
|
|
|
|
|
|
|
it under the terms of the GNU General Public License as published by |
118
|
|
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or |
119
|
|
|
|
|
|
|
(at your option) any later version. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
See the LICENSE file that comes with this distribution for more details. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=cut |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#################################################################################################### |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub new |
128
|
|
|
|
|
|
|
{ |
129
|
0
|
|
|
0
|
1
|
|
my ($class,$ctx,$rp)=@_; |
130
|
0
|
|
|
|
|
|
my %opts=%$rp; |
131
|
0
|
|
|
|
|
|
my $po=$ctx->{protocol}; |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
my %t=(message_factory => $po->factories()->{message}); |
134
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('protocol_connection') unless (exists($opts{protocol_connection}) && $opts{protocol_connection}); |
135
|
0
|
|
|
|
|
|
$t{pc}=$opts{protocol_connection}; |
136
|
0
|
|
|
|
|
|
Net::DRI::Util::load_module($t{pc},'transport/socket'); |
137
|
0
|
0
|
|
|
|
|
if ($t{pc}->can('transport_default')) |
138
|
|
|
|
|
|
|
{ |
139
|
0
|
|
|
|
|
|
%opts=($t{pc}->transport_default('socket_inet'),%opts); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
my $self=$class->SUPER::new($ctx,\%opts); ## We are now officially a Net::DRI::Transport instance |
143
|
0
|
0
|
|
|
|
|
$self->has_state(exists $opts{has_state}? $opts{has_state} : 1); |
144
|
0
|
|
|
|
|
|
$self->is_sync(1); |
145
|
0
|
|
|
|
|
|
$self->name('socket_inet'); |
146
|
0
|
|
|
|
|
|
$self->version('0.8'); |
147
|
|
|
|
|
|
|
##delete($ctx->{protocol}); ## TODO : double check it is ok |
148
|
0
|
|
|
|
|
|
delete($ctx->{registry}); |
149
|
0
|
|
|
|
|
|
delete($ctx->{profile}); |
150
|
|
|
|
|
|
|
|
151
|
0
|
0
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('socktype must be defined') unless (exists($opts{socktype})); |
152
|
0
|
0
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('socktype must be ssl, tcp or udp') unless ($opts{socktype}=~m/^(ssl|tcp|udp)$/); |
153
|
0
|
|
|
|
|
|
$t{socktype}=$opts{socktype}; |
154
|
0
|
|
|
|
|
|
$t{client_login}=$opts{client_login}; |
155
|
0
|
|
|
|
|
|
$t{client_password}=$opts{client_password}; |
156
|
0
|
0
|
0
|
|
|
|
$t{client_newpassword}=$opts{client_newpassword} if (exists($opts{client_newpassword}) && $opts{client_newpassword}); |
157
|
|
|
|
|
|
|
|
158
|
0
|
0
|
0
|
|
|
|
$t{protocol_data}=$opts{protocol_data} if (exists($opts{protocol_data}) && $opts{protocol_data}); |
159
|
0
|
|
|
|
|
|
my @need=qw/read_data write_message/; |
160
|
0
|
0
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('protocol_connection class ('.$t{pc}.') must have: '.join(' ',@need)) if (grep { ! $t{pc}->can($_) } @need); |
|
0
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
0
|
0
|
0
|
|
|
|
if (exists($opts{find_remote_server}) && defined($opts{find_remote_server}) && $t{pc}->can('find_remote_server')) |
|
|
|
0
|
|
|
|
|
163
|
|
|
|
|
|
|
{ |
164
|
0
|
|
|
|
|
|
($opts{remote_host},$opts{remote_port})=$t{pc}->find_remote_server($self,$opts{find_remote_server}); |
165
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{phase=>'opening',message=>'Found the following remote_host:remote_port = '.$opts{remote_host}.':'.$opts{remote_port}}); |
166
|
|
|
|
|
|
|
} |
167
|
0
|
|
|
|
|
|
foreach my $p ('remote_host','remote_port','protocol_version') |
168
|
|
|
|
|
|
|
{ |
169
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters($p.' must be defined') unless (exists($opts{$p}) && $opts{$p}); |
170
|
0
|
|
|
|
|
|
$t{$p}=$opts{$p}; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('close_after must be an integer') if ($opts{close_after} && !Net::DRI::Util::isint($opts{close_after})); |
174
|
0
|
|
0
|
|
|
|
$t{close_after}=$opts{close_after} || 0; |
175
|
|
|
|
|
|
|
|
176
|
0
|
0
|
|
|
|
|
if ($t{socktype} eq 'ssl') |
177
|
|
|
|
|
|
|
{ |
178
|
0
|
|
|
|
|
|
$t{ssl_context}=$self->parse_ssl_options(\%opts); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
0
|
0
|
0
|
|
|
|
$t{local_host}=$opts{local_host} if (exists($opts{local_host}) && $opts{local_host}); |
182
|
0
|
|
|
|
|
|
$t{remote_uri}=sprintf('%s://%s:%d',$t{socktype},$t{remote_host},$t{remote_port}); ## handy shortcut only used for error messages |
183
|
0
|
|
|
|
|
|
$self->{transport}=\%t; |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
my $rc; |
186
|
0
|
0
|
|
|
|
|
if ($self->defer()) ## we will open, but later |
187
|
|
|
|
|
|
|
{ |
188
|
0
|
|
|
|
|
|
$self->current_state(0); |
189
|
|
|
|
|
|
|
} else ## we will open NOW |
190
|
|
|
|
|
|
|
{ |
191
|
0
|
|
|
|
|
|
$rc=$self->open_connection($ctx); |
192
|
0
|
|
|
|
|
|
$self->current_state(1); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
return ($self,$rc); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
0
|
0
|
|
0
|
0
|
|
sub sock { my ($self,$v)=@_; $self->transport_data()->{sock}=$v if defined($v); return $self->transport_data()->{sock}; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
## TODO (for IRIS DCHK1 + NAPTR/SRV) |
201
|
|
|
|
|
|
|
## Wrap in an eval to handle timeout (see if outer eval already for that ?) |
202
|
|
|
|
|
|
|
## Handle remote_host/port being ref array of ordered strings to try (in which case defer should be 0 probably as the list of things to try have been determined now, not later) |
203
|
|
|
|
|
|
|
## Or specify a callback to call when doing socket open to find the correct host+ports to use at that time |
204
|
|
|
|
|
|
|
sub open_socket |
205
|
|
|
|
|
|
|
{ |
206
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
207
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
208
|
0
|
|
|
|
|
|
my $type=$t->{socktype}; |
209
|
0
|
|
|
|
|
|
my $sock; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
my %n=( PeerAddr => $t->{remote_host}, |
212
|
|
|
|
|
|
|
PeerPort => $t->{remote_port}, |
213
|
0
|
0
|
|
|
|
|
Proto => $t->{socktype} eq 'udp'? 'udp' : 'tcp', |
214
|
|
|
|
|
|
|
Blocking => 1, |
215
|
|
|
|
|
|
|
MultiHomed => 1, |
216
|
|
|
|
|
|
|
); |
217
|
0
|
0
|
|
|
|
|
$n{LocalAddr}=$t->{local_host} if exists($t->{local_host}); |
218
|
|
|
|
|
|
|
|
219
|
0
|
0
|
0
|
|
|
|
if ($type eq 'ssl') |
|
|
0
|
|
|
|
|
|
220
|
|
|
|
|
|
|
{ |
221
|
0
|
|
|
|
|
|
$sock=IO::Socket::SSL->new(%{$t->{ssl_context}}, |
|
0
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
%n, |
223
|
|
|
|
|
|
|
); |
224
|
|
|
|
|
|
|
} elsif ($type eq 'tcp' || $type eq 'udp') |
225
|
|
|
|
|
|
|
{ |
226
|
0
|
|
|
|
|
|
$sock=IO::Socket::INET->new(%n); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
0
|
0
|
|
|
|
|
Net::DRI::Exception->die(1,'transport/socket',6,'Unable to setup the socket for '.$t->{remote_uri}.' with error: "'.$!.($type eq 'ssl'? '" and SSL error: "'.IO::Socket::SSL::errstr().'"' : '"')) unless defined $sock; |
|
|
0
|
|
|
|
|
|
230
|
0
|
|
|
|
|
|
$sock->autoflush(1); |
231
|
0
|
|
|
|
|
|
$self->sock($sock); |
232
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{phase=>'opening',message=>'Successfully opened socket to '.$t->{remote_uri}}); |
233
|
0
|
|
|
|
|
|
return; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub send_login |
237
|
|
|
|
|
|
|
{ |
238
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
239
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
240
|
0
|
|
|
|
|
|
my $sock=$self->sock(); |
241
|
0
|
|
|
|
|
|
my $pc=$t->{pc}; |
242
|
0
|
|
|
|
|
|
my $dr; |
243
|
0
|
|
|
|
|
|
my $cltrid=$self->generate_trid($self->{logging_ctx}->{registry}); |
244
|
0
|
|
|
|
|
|
my @rs; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
## Get server greeting, if needed |
247
|
0
|
0
|
|
|
|
|
if ($ctx->{protocol}->has_action('session','connect')) |
248
|
|
|
|
|
|
|
{ |
249
|
0
|
|
|
|
|
|
my $t1=Time::HiRes::time(); |
250
|
0
|
|
|
|
|
|
$dr=$pc->read_data($self,$sock); |
251
|
0
|
|
|
|
|
|
my $t2=Time::HiRes::time(); |
252
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{trid=>$cltrid,phase=>'opening',direction=>'in',message=>$dr}); |
253
|
0
|
|
|
|
|
|
push @rs,$self->protocol_parse($ctx->{protocol},'session','connect',$dr,$cltrid,$t2-$t1); |
254
|
0
|
0
|
|
|
|
|
return Net::DRI::Util::link_rs(@rs) unless $rs[-1]->is_success(); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
|
return unless $ctx->{protocol}->has_action('session','login'); |
258
|
|
|
|
|
|
|
|
259
|
0
|
|
|
|
|
|
foreach my $p (qw/client_login client_password/) |
260
|
|
|
|
|
|
|
{ |
261
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters($p.' must be defined') unless (exists($t->{$p}) && $t->{$p}); |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
$cltrid=$self->generate_trid($self->{logging_ctx}->{registry}); |
265
|
|
|
|
|
|
|
|
266
|
0
|
0
|
|
|
|
|
my $login=$ctx->{protocol}->action('session','login',$cltrid,$t->{client_login},$t->{client_password},{ client_newpassword => $t->{client_newpassword}, %{$t->{protocol_data} || {}}}); ## TODO: fix last hash ref |
|
0
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'login',trid=>$cltrid,phase=>'opening',direction=>'out',message=>$login}); |
268
|
0
|
|
|
|
|
|
my $t1=Time::HiRes::time(); |
269
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception->die(0,'transport/socket',4,'Unable to send login message to '.$t->{remote_uri}) unless ($sock->connected() && $sock->print($pc->write_message($self,$login))); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
## Verify login successful |
272
|
0
|
|
|
|
|
|
$dr=$pc->read_data($self,$sock); |
273
|
0
|
|
|
|
|
|
my $t2=Time::HiRes::time(); |
274
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'login',trid=>$cltrid,phase=>'opening',direction=>'in',message=>$dr}); |
275
|
0
|
|
|
|
|
|
push @rs,$self->protocol_parse($ctx->{protocol},'session','login',$dr,$cltrid,$t2-$t1,$login); |
276
|
|
|
|
|
|
|
|
277
|
0
|
|
|
|
|
|
return Net::DRI::Util::link_rs(@rs); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub send_logout |
281
|
|
|
|
|
|
|
{ |
282
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
283
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
284
|
0
|
|
|
|
|
|
my $sock=$self->sock(); |
285
|
0
|
|
|
|
|
|
my $pc=$t->{pc}; |
286
|
|
|
|
|
|
|
|
287
|
0
|
0
|
|
|
|
|
return unless $ctx->{protocol}->has_action('session','logout'); |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
|
my $cltrid=$self->generate_trid($self->{logging_ctx}->{registry}); |
290
|
0
|
|
|
|
|
|
my $logout=$ctx->{protocol}->action('session','logout',$cltrid); |
291
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'logout',trid=>$cltrid,phase=>'closing',direction=>'out',message=>$logout}); |
292
|
0
|
|
|
|
|
|
my $t1=Time::HiRes::time(); |
293
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception->die(0,'transport/socket',4,'Unable to send logout message to '.$t->{remote_uri}) unless ($sock->connected() && $sock->print($pc->write_message($self,$logout))); |
294
|
0
|
|
|
|
|
|
my $dr=$pc->read_data($self,$sock); ## We expect this to throw an exception, since the server will probably cut the connection |
295
|
0
|
|
|
|
|
|
my $t2=Time::HiRes::time(); |
296
|
0
|
|
|
|
|
|
$self->time_used(time()); |
297
|
0
|
|
|
|
|
|
$t->{exchanges_done}++; |
298
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'logout',trid=>$cltrid,phase=>'closing',direction=>'in',message=>$dr}); |
299
|
0
|
|
|
|
|
|
my $rc1=$self->protocol_parse($ctx->{protocol},'session','logout',$dr,$cltrid,$t2-$t1,$logout); |
300
|
0
|
0
|
|
|
|
|
die $rc1 unless $rc1->is_success(); |
301
|
0
|
|
|
|
|
|
return $rc1; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub open_connection |
305
|
|
|
|
|
|
|
{ |
306
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
307
|
0
|
|
|
|
|
|
$self->open_socket($ctx); |
308
|
0
|
|
|
|
|
|
my $rc=$self->send_login($ctx); |
309
|
0
|
|
|
|
|
|
$self->current_state(1); |
310
|
0
|
|
|
|
|
|
$self->time_open(time()); |
311
|
0
|
|
|
|
|
|
$self->time_used(time()); |
312
|
0
|
|
|
|
|
|
$self->transport_data()->{exchanges_done}=0; |
313
|
0
|
|
|
|
|
|
return $rc; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub ping |
317
|
|
|
|
|
|
|
{ |
318
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx,$autorecon)=@_; |
319
|
0
|
0
|
|
|
|
|
$autorecon=0 unless defined $autorecon; |
320
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
321
|
0
|
|
|
|
|
|
my $pc=$t->{pc}; |
322
|
0
|
|
|
|
|
|
my $sock=$self->sock(); |
323
|
|
|
|
|
|
|
|
324
|
0
|
0
|
|
|
|
|
return 0 unless $self->has_state(); |
325
|
0
|
0
|
|
|
|
|
return 0 unless $ctx->{protocol}->has_action('session','noop'); |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
|
my $rc1; |
328
|
0
|
|
|
|
|
|
my $cltrid=$self->generate_trid($self->{logging_ctx}->{registry}); |
329
|
|
|
|
|
|
|
my $ok=eval |
330
|
0
|
|
|
|
|
|
{ |
331
|
0
|
|
|
0
|
|
|
local $SIG{ALRM}=sub { die 'timeout' }; |
|
0
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
alarm 10; |
333
|
0
|
|
|
|
|
|
my $noop=$ctx->{protocol}->action('session','noop',$cltrid); |
334
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'keepalive',trid=>$cltrid,phase=>'keepalive',direction=>'out',message=>$noop}); |
335
|
0
|
|
|
|
|
|
my $t1=Time::HiRes::time(); |
336
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception->die(0,'transport/socket',4,'Unable to send keepalive message to '.$t->{remote_uri}) unless ($sock->connected() && $sock->print($pc->write_message($self,$noop))); |
337
|
0
|
|
|
|
|
|
my $dr=$pc->read_data($self,$sock); |
338
|
0
|
|
|
|
|
|
my $t2=Time::HiRes::time(); |
339
|
0
|
|
|
|
|
|
$self->time_used(time()); |
340
|
0
|
|
|
|
|
|
$t->{exchanges_done}++; |
341
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{otype=>'session',oaction=>'keepalive',trid=>$cltrid,phase=>'keepalive',direction=>'in',message=>$dr}); |
342
|
0
|
|
|
|
|
|
$rc1=$self->protocol_parse($ctx->{protocol},'session','noop',$dr,$cltrid,$t2-$t1,$noop); |
343
|
0
|
0
|
|
|
|
|
die $rc1 unless $rc1->is_success(); |
344
|
0
|
|
|
|
|
|
1; |
345
|
|
|
|
|
|
|
}; |
346
|
0
|
|
|
|
|
|
my $err=$@; |
347
|
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
|
alarm 0; |
349
|
0
|
0
|
0
|
|
|
|
if (defined $ok && $ok==1) |
350
|
|
|
|
|
|
|
{ |
351
|
0
|
|
|
|
|
|
$self->current_state(1); |
352
|
|
|
|
|
|
|
} else |
353
|
|
|
|
|
|
|
{ |
354
|
0
|
|
|
|
|
|
$self->current_state(0); |
355
|
0
|
0
|
0
|
|
|
|
$rc1=$err if defined $err && Net::DRI::Util::is_class($err,'Net::DRI::Protocol::ResultStatus'); |
356
|
0
|
0
|
|
|
|
|
if ($autorecon) |
357
|
|
|
|
|
|
|
{ |
358
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',{},{phase=>'keepalive',message=>'Reopening connection to '.$t->{remote_uri}.' because ping failed and asked to auto-reconnect'}); |
359
|
0
|
|
|
|
|
|
my $rc2=$self->open_connection($ctx); |
360
|
0
|
0
|
|
|
|
|
$rc1=defined $rc1 ? Net::DRI::Util::link_rs($rc1,$rc2) : $rc2; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
0
|
0
|
|
|
|
|
return defined $rc1 ? $rc1 : Net::DRI::Protocol::ResultStatus->new_error('COMMAND_FAILED_CLOSING','ping failed, no auto-reconnect'); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub close_socket |
368
|
|
|
|
|
|
|
{ |
369
|
0
|
|
|
0
|
0
|
|
my ($self)=@_; |
370
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
371
|
0
|
0
|
0
|
|
|
|
if (defined $self->sock() && Scalar::Util::openhandle($self->sock())) |
372
|
|
|
|
|
|
|
{ |
373
|
0
|
|
|
|
|
|
$self->sock()->close(); |
374
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',{},{phase=>'closing',message=>'Successfully closed socket for '.$t->{remote_uri}}); |
375
|
|
|
|
|
|
|
} |
376
|
0
|
|
|
|
|
|
$self->sock(undef); |
377
|
0
|
|
|
|
|
|
return; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub close_connection |
381
|
|
|
|
|
|
|
{ |
382
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
383
|
0
|
|
|
|
|
|
$self->send_logout($ctx); |
384
|
0
|
|
|
|
|
|
$self->close_socket(); |
385
|
0
|
|
|
|
|
|
$self->current_state(0); |
386
|
0
|
|
|
|
|
|
return; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub end |
390
|
|
|
|
|
|
|
{ |
391
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx)=@_; |
392
|
0
|
0
|
|
|
|
|
if ($self->current_state()) |
393
|
|
|
|
|
|
|
{ |
394
|
|
|
|
|
|
|
eval |
395
|
0
|
|
|
|
|
|
{ |
396
|
0
|
|
|
0
|
|
|
local $SIG{ALRM}=sub { die 'timeout' }; |
|
0
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
|
alarm 10; |
398
|
0
|
|
|
|
|
|
$self->close_connection($ctx); |
399
|
|
|
|
|
|
|
}; |
400
|
0
|
|
|
|
|
|
alarm 0; ## since close_connection may die, this must be outside of eval to be executed in all cases |
401
|
|
|
|
|
|
|
} |
402
|
0
|
|
|
|
|
|
return; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
#################################################################################################### |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub send ## no critic (Subroutines::ProhibitBuiltinHomonyms) |
408
|
|
|
|
|
|
|
{ |
409
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx,$tosend,$count)=@_; |
410
|
|
|
|
|
|
|
## We do a very crude error handling : if first send fails, we reset connection. |
411
|
|
|
|
|
|
|
## Thus if you put retry=>2 when creating this object, the connection will be re-established and the message resent |
412
|
0
|
|
|
0
|
|
|
return $self->SUPER::send($ctx,$tosend,\&_print,sub { shift->current_state(0) },$count); |
|
0
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub _print ## here we are sure open_connection() was called before |
416
|
|
|
|
|
|
|
{ |
417
|
0
|
|
|
0
|
|
|
my ($self,$count,$tosend,$ctx)=@_; |
418
|
0
|
|
|
|
|
|
my $pc=$self->transport_data('pc'); |
419
|
0
|
|
|
|
|
|
my $sock=$self->sock(); |
420
|
0
|
0
|
|
|
|
|
my $m=($self->transport_data('socktype') eq 'udp')? 'send' : 'print'; |
421
|
0
|
0
|
0
|
|
|
|
Net::DRI::Exception->die(0,'transport/socket',4,'Unable to send message to '.$self->transport_data('remote_uri').' because of error: '.$!) unless (($m ne 'print' || $sock->connected()) && $sock->$m($pc->write_message($self,$tosend))); |
|
|
|
0
|
|
|
|
|
422
|
0
|
|
|
|
|
|
return 1; ## very important |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub receive |
426
|
|
|
|
|
|
|
{ |
427
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx,$count)=@_; |
428
|
0
|
|
|
|
|
|
return $self->SUPER::receive($ctx,\&_get,undef,$count); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub _get |
432
|
|
|
|
|
|
|
{ |
433
|
0
|
|
|
0
|
|
|
my ($self,$count,$ctx)=@_; |
434
|
0
|
|
|
|
|
|
my $t=$self->transport_data(); |
435
|
0
|
|
|
|
|
|
my $sock=$self->sock(); |
436
|
0
|
|
|
|
|
|
my $pc=$t->{pc}; |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
## Answer |
439
|
0
|
|
|
|
|
|
my $dr=$pc->read_data($self,$sock); |
440
|
0
|
|
|
|
|
|
$t->{exchanges_done}++; |
441
|
0
|
0
|
0
|
|
|
|
if ($t->{exchanges_done}==$t->{close_after} && $self->has_state() && $self->current_state()) |
|
|
|
0
|
|
|
|
|
442
|
|
|
|
|
|
|
{ |
443
|
0
|
|
|
|
|
|
$self->log_output('notice','transport',$ctx,{phase=>'closing',message=>'Due to maximum number of exchanges reached, closing connection to '.$t->{remote_uri}}); |
444
|
0
|
|
|
|
|
|
$self->close_connection($ctx); |
445
|
|
|
|
|
|
|
} |
446
|
0
|
|
|
|
|
|
return $dr; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
sub try_again |
450
|
|
|
|
|
|
|
{ |
451
|
0
|
|
|
0
|
0
|
|
my ($self,$ctx,$po,$err,$count,$istimeout,$step,$rpause,$rtimeout)=@_; |
452
|
0
|
0
|
|
|
|
|
if ($step==0) ## sending not already done, hence error during send |
453
|
|
|
|
|
|
|
{ |
454
|
0
|
|
|
|
|
|
$self->current_state(0); |
455
|
0
|
|
|
|
|
|
return 1; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
## We do a more agressive retry procedure in case of udp (that is IRIS basically) |
459
|
|
|
|
|
|
|
## See RFC4993 section 4 |
460
|
0
|
0
|
0
|
|
|
|
if ($step==1 && $istimeout==1 && $self->transport_data()->{socktype} eq 'udp') |
|
|
|
0
|
|
|
|
|
461
|
|
|
|
|
|
|
{ |
462
|
0
|
|
|
|
|
|
$self->log_output('debug','transport',$ctx,{phase=>'active',message=>sprintf('In try_again, currently: pause=%f timeout=%f',$$rpause,$$rtimeout)}); |
463
|
0
|
|
|
|
|
|
$$rtimeout=2*$$rtimeout; |
464
|
0
|
|
|
|
|
|
$$rpause+=rand(1+int($$rpause/2)); |
465
|
0
|
|
|
|
|
|
$self->log_output('debug','transport',$ctx,{phase=>'active',message=>sprintf('In try_again, new values: pause=%f timeout=%f',$$rpause,$$rtimeout)}); |
466
|
0
|
|
|
|
|
|
return 1; ## we will retry |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
0
|
|
|
|
|
|
return 0; ## we do not handle other cases, hence no retry and fatal error |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
#################################################################################################### |
474
|
|
|
|
|
|
|
1; |