On numerous Tcl versions (up to 8.3) and ftp
library versions (1.2, 2.2, 2.3) we have
experienced false successes for ftp::Put.
Recently, we have noticed that these occur when
ftp::Put encounters the error:
"Timeout of control connection"
If a sequence of files are being sent by ftp::Put,
then subsequent files after the erroneous success
will have their data written to the wrong file name.
E.g.
ftp::Put A is OK
ftp::Put B times out
ftp::Put C sends C's contents to the file B!
As a work-around I set a flag in the
ftp::DisplayMsg procedure within the error
branch. If this flag is set despite ftp::Put
indicating success, then I treat this as a
failed ftp::Put. I then quit the connection
to try again.
Additionally, a couple of times after experiencing
these false-positive results when we have attempted
to quit the connection, we have encountered an
inifinite loop:
bgerror failed to handle background error.
Original error: Unknown state "quit_sent"
Error in bgerror: invalid command name "bgerror"
bgerror failed to handle background error.
Original error: too many nested calls to
Tcl_EvalObj (infinite loop?)
Error in bgerror: too many nested calls to
Tcl_EvalObj (infinite loop?)
(This is using ftp_lib.tcl 2.3 with Tcl 8.3 on
Solaris)
Logged In: YES
user_id=75003
Can you attach a small script/patch which show how you
modfied DisplayMsg ? I would basically like to know if you
check for a specific error message, or just that there was
an error message. If you know which error message you get,
well, that would be helpful as well. The ftp sources are a
bit convoluted and any piece of information you can give me
will make it easier to find the place where it should error
out instead of returning a false-positive. Especially as I
am not the original author of this code.
Patch to DisplayMsg and other pieces of info.
Logged In: YES
user_id=75003
With the error message in your patch I find 'ftp::Timeout'. The
interesting thing about this procedure is that it sets ftp
(state.control) to "1". This value seems to become the result
of the command in execution, and means 'Ok'. Which IMHO
is not ok. The error value is '0'.
Logged In: YES
user_id=526050
I've modified 'ftp::Timeout' to set ftp(state.control) to "0" and
I'm in the process of testing. I've not yet managed to recreate
the exact scenario to judge the behaviour with this
modification, but it does appear to be behaving as one would
hope.
Logged In: YES
user_id=526050
I have an undesirable result from "set ftp(stat.control) 0"
in "ftp::Timeout".
This time we had an unreliable connection that was timing-out
on the ftp::Get. When trying to close the connection with
ftp::Close the call to ftp::Timeout from ftp::WaitOrTimeout
would not return. Instead, it just hung. If I ignored trying to
close the connection, the connection hung when trying to
connect next.
The only reliable solution was to return to "set ftp
(state.control) 1" in ftp::Timeout, then to close the connection
with ftp::Close as soon as an error was discovered when
having run ftp::Get.
Logged In: YES
user_id=1625850
Originator: NO
I sometimes see the following crash during a ftp::Get :
can't read "ftp(Start_Time)": no such element in array
while executing
"expr {$stop_time - $ftp(Start_Time)}"
(procedure "ElapsedTime" line 5)
invoked from within
"ElapsedTime $s [clock seconds]"
(procedure "ftp::Get" line 87)
I think this happens because the proc ftp::WaitOrTimeout (used at the end of ftp::Get) returns 1 on timeout i.s.o. 0. And so ftp::Get tries to calculate the elapsed time in ftp::ElapsedTime, while ftp(Start_Time) is not yet existing, resulting in a crash.
I have looked at all usage of ftp::WaitOrTimeout, and the return code should be 1 on success, 0 on error. Therefore I suggest to change ftp::Timeout to put ftp(state.control) to 0.
It solves the crash for me and I think it will solve the related bugs of this thread as well.
As I am not able to add a patchfile to this comment, I will paste the diff (only a 1 needs to be changed to a 0) :
--- ftp1.45.tcl 2007-03-16 21:25:07.954228800 +0100
+++ ftp.tcl 2007-03-18 19:45:10.498745600 +0100
@@ -121,7 +121,7 @@
upvar ::ftp::ftp$s ftp
after cancel $ftp(Wait)
- set ftp(state.control) 1
+ set ftp(state.control) 0
DisplayMsg "" "Timeout of control connection after $ftp(Timeout) sec.!" error
Command $ftp(Command) timeout