Jump to content
merijnb

bugfix OverbyteIcsWSocket.TCustomWSocket.Listen()

Recommended Posts

We've run into a bug with regards the FTP client in ICS, it boils down to the Listen() method of TCustomWSocket in OverbyteIcsWSocket.pas

 

At the top of the method, fLastError should be set to 0:

 

procedure TCustomWSocket.Listen;
var
    iStatus        : Integer;
    optval         : Integer;
    optlen         : Integer;
    mreq           : ip_mreq;
    mreqv6         : TIpv6MReq;
    Success        : Boolean;
    FriendlyMsg    : String;
    ErrorCode      : Integer;
{$IFDEF MSWINDOWS}
    dwBufferInLen  : DWORD;
    dwBufferOutLen : DWORD;
    dwDummy        : DWORD;
{$ENDIF}
begin
    fLastError := 0;   // <-- this should be added
    FriendlyMsg := '';

The reason this is needed is as follows:

If you start an active FTP connection to a server, while using a data port range the client will try to setup a server for the data connection on port X, if this fails it will try again on X + 1 until it's able to start a server (or runs out of ports to try).

This is found inTCustomFtpCli.PortAsync() in OverbyteIcsFtpCli:

 

            StartDataPort := DataPort;
            while TRUE do begin
                FDataSocket.Port := IntToStr(DataPort);
                try
                    FDataSocket.Listen;
                    break;                { Found a free port }
                except
                    if FDataSocket.LastError = WSAEADDRINUSE then begin
                        DataPort := DataPort + 1;
                        if DataPort > FDataPortRangeEnd then
                            DataPort := FDataPortRangeStart;
                        if DataPort = StartDataPort then begin
                            HandleError('All ports in DataPortRange are in use');
                            Exit;
                        end;
                    end
                    else begin
                        HandleError('Data connection winsock bind failed - ' +
                                    GetWinsockErr(FDataSocket.LastError));
                        Exit;
                    end;
                end;
            end;

 

If you make a new FTP connection while one of the ports is already in use, but PortAsync() is able to find another port, the fLastError is still set to something <> 0 due to the earlier failed port. If you then end up in TCustomFtpCli.PutAsync(), it will still see that LastError and raise an exception over that while we're currently happily listening without problems.

 

procedure TCustomFtpCli.PutAsync;
begin
	DataSocket.LastError := 0; { V2.100 }
    HighLevelAsync(ftpPutAsync,
                   [ftpFctPort, ftpFctPut]);
    if DataSocket.LastError <> 0 then    { V2.100 }
       raise FtpException.Create('Socket Error - ' +
                              GetWinsockErr(DataSocket.LastError)); { V2.100 }
end;

 

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×