C
Chris
Anyone have any experience using Net::FTP going against IBM TSO? As
usual, IBM (just like Microsloth) have their own way of doing things,
unfortunately. It would *appear* from using debug in a real FTP client
and turning on Net::Cmd debugging that the real FTP client sends an
'EPSV' command just before each 'get' on a TSO dataset. Trying to
simulate this behavior using Net::FTP doesn't seem to do the job.
Sending or not sending EPSV results in the same thing using Net::FTP --
a download timeout. So now I'm faced with the possibility of doing an
external 'ftp -s' hack... :-(
Here is the main part of the script with all the Net::FTP commands I am
using, the XML file I am using, and the debug output from each
(Net::FTP and real ftp client running on Linux). The hostname,
username, password and the gets I want to do are defined in an XML
file. So don't worry about those details in the script too much. It's
irrelevant. All the information from the XML file (handled by
XML::Simple) is fine -- I've verified the data I need to drive this is
being picked up and used just fine. It's the actual $ftp->get() that
isn't working with or without the $ftp->quot( 'EPSV' ) command:
__PERL__
## Get hostname, username, and password, decrypt password if encrypted,
and login to
## host via FTP.
my $dlConfig = $config->{Download};
my $lnConfig = $dlConfig->{Login};
$lnConfig->{Password} = decrypt( $lnConfig->{Password} )
if $lnConfig->{PasswordEncrypted};
my $ftp = Net::FTP->new( $lnConfig->{Host}, Debug => $lnConfig->{Debug}
|| 0 ) ||
error( "Can't open session to host /$lnConfig->{Host}/!" );
$ftp->login( $lnConfig->{Username}, $lnConfig->{Password} ) ||
error( "Can't log in to host /$lnConfig->{Host}/ as username
/$lnConfig->{Username}/!" );
## Get all files designated in get section of download section.
my $gets = getCollection( $dlConfig->{Gets}->{Get} );
for my $get (@{$gets}) {
puts( " Getting: Remote( $get->{Remote} ) -> Local( $get->{Local}
)" );
$ftp->quot( 'EPSV' ); # Doesn't seem to matter if I use this or
not...
$ftp->get( $get->{Remote}, $get->{Local} ); # Line 69 in Perl debug
session below
}
$ftp->quit(); # Line 71 in Perl debug session below
sub puts { for (@_) { print "$_\n" } }
sub getCollection { ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ] }
__END__
__XML__
<?xml version="1.0" encoding="utf-8"?>
<config>
<Download>
<Login>
<Host>ftphost.some.private.net</Host>
<Username>foouser</Username>
<Password>foo.password</Password>
<PasswordEncrypted>0</PasswordEncrypted>
<Debug>1</Debug>
</Login>
<Gets>
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/foouser.cob"
/>
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/a.cob" />
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/b.cob" />
</Gets>
</Download>
</config>
__END__
Real ftp client debug session:
chris@mylinux:~/work/foo> ftp ftphost.some.private.net
Connected to ftphost.some.private.net.
220-FTPHOST IBM FTP CS V1R6 at FTPHOST.SOME.PRIVATE.NET, 21:52:49 on
2006-03-14.
220 Connection will close if idle for more than 5 minutes.
Name (ftphost.some.private.net:chris): foouser
331 Send password please.
Password:
230 FOOUSER is logged on. Working directory is "FOOUSER.".
Remote system type is MVS.
ftp> debug
Debugging on (debug=1).
ftp> get 'FOO.SOX.COBOL(GEN1)' x.cob
local: x.cob remote: 'FOO.SOX.COBOL(GEN1)'
ftp: setsockopt (ignored): Permission denied
---> EPSV
229 Entering Extended Passive Mode (|||1874|)
---> RETR 'FOO.SOX.COBOL(GEN1)'
125 Sending data set FOO.SOX.COBOL(GEN1) FIXrecfm 80
250 Transfer completed successfully.
114308 bytes received in 00:00 (281.03 KB/s)
ftp> quit
---> QUIT
221 Quit command received. Goodbye.
Net::FTP debug session:
colive@mylinux:~/work/foo> ./download-dbload-foo.pl -i
download-dbload-foo.xml download-dbload-foo.pl (v1.00-000) - Download &
DB Load Foo Feed
(c) Copyright 2006, My Big Company - All rights reserved
Net::FTP>>> Net::FTP(2.75)
Net::FTP>>> Exporter(5.58)
Net::FTP>>> Net::Cmd(2.26)
Net::FTP>>> IO::Socket::INET(1.28)
Net::FTP>>> IO::Socket(1.28)
Net::FTP>>> IO::Handle(1.24)
Net::FTP=GLOB(0x87846d0)<<< 220-FTPHOST IBM FTP CS V1R6 at
FTPHOST.SOME.PRIVATE.NET, 21:57:41 on 2006-03-14.
Net::FTP=GLOB(0x87846d0)<<< 220 Connection will close if idle for more
than 5 minutes.
Net::FTP=GLOB(0x87846d0)>>> user foouser
Net::FTP=GLOB(0x87846d0)<<< 331 Send password please.
Net::FTP=GLOB(0x87846d0)>>> PASS ....
Net::FTP=GLOB(0x87846d0)<<< 230 FOOUSER is logged on. Working
directory is "FOOUSER.".
Getting: Remote( 'FOO.SOX.COBOL(GEN1)' ) -> Local( /tmp/foouser.cob
)
Net::FTP=GLOB(0x87846d0)>>> EPSV
Net::FTP=GLOB(0x87846d0)<<< 229 Entering Extended Passive Mode
(|||1875|)
Net::FTP=GLOB(0x87846d0)>>> PORT 172,17,4,47,4,80
Net::FTP=GLOB(0x87846d0)<<< 200 Port request OK.
Net::FTP=GLOB(0x87846d0)>>> RETR 'FOO.SOX.COBOL(GEN1)'
Net::FTP=GLOB(0x87846d0): Timeout at ./download-dbload-foo.pl line 69
Net::FTP=GLOB(0x87846d0)>>> QUIT
Net::FTP=GLOB(0x87846d0): Timeout at ./download-dbload-foo.pl line 71
The "get" on a.cob and b.cob in the XML file above is never done
because I took them out for the debug session above. I left them in
the XML file above to demonstrate the intent of the getCollection() and
for loop for the gets.
If I take the $ftp->quot( 'EPSV' ) line out, I get the exact same
results as the above Net::FTP session save for seeing EPSV sent to the
host, of course.
If anyone has any ideas, I've love to hear about them. I grow weary of
IBM and Microsoft and their "implementation" of TCP/IP standards. :-/
Sorry if anyone here works for them, but those are my candid
sentiments.
-ceo
usual, IBM (just like Microsloth) have their own way of doing things,
unfortunately. It would *appear* from using debug in a real FTP client
and turning on Net::Cmd debugging that the real FTP client sends an
'EPSV' command just before each 'get' on a TSO dataset. Trying to
simulate this behavior using Net::FTP doesn't seem to do the job.
Sending or not sending EPSV results in the same thing using Net::FTP --
a download timeout. So now I'm faced with the possibility of doing an
external 'ftp -s' hack... :-(
Here is the main part of the script with all the Net::FTP commands I am
using, the XML file I am using, and the debug output from each
(Net::FTP and real ftp client running on Linux). The hostname,
username, password and the gets I want to do are defined in an XML
file. So don't worry about those details in the script too much. It's
irrelevant. All the information from the XML file (handled by
XML::Simple) is fine -- I've verified the data I need to drive this is
being picked up and used just fine. It's the actual $ftp->get() that
isn't working with or without the $ftp->quot( 'EPSV' ) command:
__PERL__
## Get hostname, username, and password, decrypt password if encrypted,
and login to
## host via FTP.
my $dlConfig = $config->{Download};
my $lnConfig = $dlConfig->{Login};
$lnConfig->{Password} = decrypt( $lnConfig->{Password} )
if $lnConfig->{PasswordEncrypted};
my $ftp = Net::FTP->new( $lnConfig->{Host}, Debug => $lnConfig->{Debug}
|| 0 ) ||
error( "Can't open session to host /$lnConfig->{Host}/!" );
$ftp->login( $lnConfig->{Username}, $lnConfig->{Password} ) ||
error( "Can't log in to host /$lnConfig->{Host}/ as username
/$lnConfig->{Username}/!" );
## Get all files designated in get section of download section.
my $gets = getCollection( $dlConfig->{Gets}->{Get} );
for my $get (@{$gets}) {
puts( " Getting: Remote( $get->{Remote} ) -> Local( $get->{Local}
)" );
$ftp->quot( 'EPSV' ); # Doesn't seem to matter if I use this or
not...
$ftp->get( $get->{Remote}, $get->{Local} ); # Line 69 in Perl debug
session below
}
$ftp->quit(); # Line 71 in Perl debug session below
sub puts { for (@_) { print "$_\n" } }
sub getCollection { ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ] }
__END__
__XML__
<?xml version="1.0" encoding="utf-8"?>
<config>
<Download>
<Login>
<Host>ftphost.some.private.net</Host>
<Username>foouser</Username>
<Password>foo.password</Password>
<PasswordEncrypted>0</PasswordEncrypted>
<Debug>1</Debug>
</Login>
<Gets>
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/foouser.cob"
/>
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/a.cob" />
<Get Remote="'FOO.SOX.COBOL(GEN1)'" Local="/tmp/b.cob" />
</Gets>
</Download>
</config>
__END__
Real ftp client debug session:
chris@mylinux:~/work/foo> ftp ftphost.some.private.net
Connected to ftphost.some.private.net.
220-FTPHOST IBM FTP CS V1R6 at FTPHOST.SOME.PRIVATE.NET, 21:52:49 on
2006-03-14.
220 Connection will close if idle for more than 5 minutes.
Name (ftphost.some.private.net:chris): foouser
331 Send password please.
Password:
230 FOOUSER is logged on. Working directory is "FOOUSER.".
Remote system type is MVS.
ftp> debug
Debugging on (debug=1).
ftp> get 'FOO.SOX.COBOL(GEN1)' x.cob
local: x.cob remote: 'FOO.SOX.COBOL(GEN1)'
ftp: setsockopt (ignored): Permission denied
---> EPSV
229 Entering Extended Passive Mode (|||1874|)
---> RETR 'FOO.SOX.COBOL(GEN1)'
125 Sending data set FOO.SOX.COBOL(GEN1) FIXrecfm 80
250 Transfer completed successfully.
114308 bytes received in 00:00 (281.03 KB/s)
ftp> quit
---> QUIT
221 Quit command received. Goodbye.
Net::FTP debug session:
colive@mylinux:~/work/foo> ./download-dbload-foo.pl -i
download-dbload-foo.xml download-dbload-foo.pl (v1.00-000) - Download &
DB Load Foo Feed
(c) Copyright 2006, My Big Company - All rights reserved
Net::FTP>>> Net::FTP(2.75)
Net::FTP>>> Exporter(5.58)
Net::FTP>>> Net::Cmd(2.26)
Net::FTP>>> IO::Socket::INET(1.28)
Net::FTP>>> IO::Socket(1.28)
Net::FTP>>> IO::Handle(1.24)
Net::FTP=GLOB(0x87846d0)<<< 220-FTPHOST IBM FTP CS V1R6 at
FTPHOST.SOME.PRIVATE.NET, 21:57:41 on 2006-03-14.
Net::FTP=GLOB(0x87846d0)<<< 220 Connection will close if idle for more
than 5 minutes.
Net::FTP=GLOB(0x87846d0)>>> user foouser
Net::FTP=GLOB(0x87846d0)<<< 331 Send password please.
Net::FTP=GLOB(0x87846d0)>>> PASS ....
Net::FTP=GLOB(0x87846d0)<<< 230 FOOUSER is logged on. Working
directory is "FOOUSER.".
Getting: Remote( 'FOO.SOX.COBOL(GEN1)' ) -> Local( /tmp/foouser.cob
)
Net::FTP=GLOB(0x87846d0)>>> EPSV
Net::FTP=GLOB(0x87846d0)<<< 229 Entering Extended Passive Mode
(|||1875|)
Net::FTP=GLOB(0x87846d0)>>> PORT 172,17,4,47,4,80
Net::FTP=GLOB(0x87846d0)<<< 200 Port request OK.
Net::FTP=GLOB(0x87846d0)>>> RETR 'FOO.SOX.COBOL(GEN1)'
Net::FTP=GLOB(0x87846d0): Timeout at ./download-dbload-foo.pl line 69
Net::FTP=GLOB(0x87846d0)>>> QUIT
Net::FTP=GLOB(0x87846d0): Timeout at ./download-dbload-foo.pl line 71
The "get" on a.cob and b.cob in the XML file above is never done
because I took them out for the debug session above. I left them in
the XML file above to demonstrate the intent of the getCollection() and
for loop for the gets.
If I take the $ftp->quot( 'EPSV' ) line out, I get the exact same
results as the above Net::FTP session save for seeing EPSV sent to the
host, of course.
If anyone has any ideas, I've love to hear about them. I grow weary of
IBM and Microsoft and their "implementation" of TCP/IP standards. :-/
Sorry if anyone here works for them, but those are my candid
sentiments.
-ceo