Hello all, I found a bug in the FtpCli - FtpSrv combination. Steps to reproduce:
1) (Client) put FtpCli into passive mode 2) (Server) assign FtpSrv.FtpServerValidateGet 3) (Client) request something from the Server - e.g. with FtpClient.Get 4) (server) fail the resulting RETR command on the server-side in FtpServerValidateGet (either by setting Allowed to false or by raising an exception) If the connection between Client and Server is slow enough(!) this will lead to wrong state in the client state-machine, so that subsequent RETR will fail! Below you can find a log that demonstrates the problem (logged on client side) - (please note that there are some custom-extended commands - namely STATUS and ACCESS - they all expect a one-line answer, just as regular ftp-commands). The error occurs in line L6. L1 to L4 are as expected, L4 is the result from the failed FtpServerValidateGet. Then the client issues the next command L5 and it expects a 1 line answer (which comes in L7), however L6 is received inbetween as the answer because the FtpSrv "unexpectedly" sends "226 File sent ok", although it never has transmitted anything. This unexpected answer shifts all subsequent server-answer and leads to an unexpected state at some time. L1: > PASV L2: < 227 Entering Passive Mode (81,189,215,215,78,33). L3: > RETR _SYSTEMARCHIVE_5889c6e9f9fb40d68fa23d6d74011566 L4: < 501 Cannot RETR. IDENTICAL L5: > STATUS L6: < 226 File sent ok L7: > ACCESS SYSTEM L8: < 200 Haupt-Bildschirm: Geteilter Schirm L9: > PASV L10: < 200 Ok. Access Type set! L11: > RETR _SYSTEMSTAT_0_500 L12: < 227 Entering Passive Mode (81,189,215,215,78,33). L13: ErrorMessage: 227 Entering Passive Mode (81,189,215,215,78,33). If you work on a fast network connection this problem doesn't occur, because L4 AND L6 are received "in one block" and effectively form L4 and L5, which doesn't shift anything. Reason for the problem: In passive mode FtpCli starts a passive data-connection to the server at the same time as it sends the RETR command (in TCustomFtpCli.DoGetAsync()), so it does NOT wait for a response from the FtpSrv if the RETR-command alltogether is valid (in active mode this doesn't happen because then the FtpSrv starts the data-connection - and this only happens if the FtpSrv.FtpServerValidateGet succeeds). As soon as the client receives the "501 Cannot RETR." (triggered by TFtpServer.CommandRETR() and the call to FtpSrv.FtpServerValidateGet) it closes the data-connection again. But this triggers TFtpServer.ClientRetrSessionClosed() which in turn sends the"226 File sent ok". So the reason for the problem is clear, however I don't know how to correct it? Should a) the passive data-connection only be connected if / as soon as the "primary command" is approved by the server b) the server simply ignore the ClientRetrSessionClosed and not send anything if nothing was transmitted (scheduled to transmit)? btw: This led my to discover another fundamental problem with passive mode (which luckily obviously doesn't occur in reality): On server side (in passive mode) DataSocket.OnSessionConnected, DataSocket.OnSessionClosed, DataSocket.OnDataAvailable and DataSocket.OnDataSent are assigned in TFtpServer.ClientPassiveSessionAvailable(), depending on the scheduled command (e.g. RETR). Since in FtpCli both, passive-mode data-connection _and_ the desired command (e.g. "RETR"), are issued at the same time (although on different ports), it _could_ happen that the data-connection is established _before_ the control-connection has transmitted the command! This would lead to TFtpServer.ClientPassiveSessionAvailable() being called before the server knows for which command the passive-data-connection is connected - in return effectively failing the rest of the transfer... best regards (and sorry for the lengthy post) Peter -- Peter Feldbaumer p dot feldbaumer at utanet dot at -- To unsubscribe or change your settings for TWSocket mailing list please goto http://www.elists.org/mailman/listinfo/twsocket Visit our website at http://www.overbyte.be