I'm having a persistent problem using Indy 10 where I am posting a string of XML encoded as a TIdMultiPartFormDataStream, the code that I am using to invoke the POST is given below. A majority of the time, this works no problem, however I am getting a repeated error when running on Windows 7 that throws a #10060 Connection Timeout socket error only when the XML string is longer than 32767 bytes, anything under that size works without a problem.
I have verified that it is not related to the server I am posting to, as there is no problem for messages of any size sent with the same code/application on Windows XP.
IdHTTP2 := TIdHTTP.Create();
UsingHTTPS := (Pos(LowerCase('https://'), Trim(LowerCase(URL)))> 0);
if UsingHTTPS then begin
IdSSLIOHandlerSocketOpenSSL2:=TIdSSLIOHandlerSocketOpenSSL.Create();
with IdSSLIOHandlerSocketOpenSSL2 do
begin
SSLOptions.Method := sslvTLSv1;
SSLOptions.Mode := sslmUnassigned;
SSLOptions.VerifyMode := [];
SSLOptions.VerifyDepth := 0;
Port := 443;
end;
end; //if UsingHTTPS
try
try
with IdHTTP2 do
begin //with some browser style defaults
AllowCookies := False;
ProxyParams.BasicAuthentication := False;
//ProxyParams.ProxyPort := 0;
Request.ContentLength := data.Size;
Request.host := '';
Request.CustomHeaders.Clear;
Request.Accept := '';
Request.ContentEncoding := '';
IOHandler:=IdSSLIOHandlerSocketOpenSSL2;
ReadTimeout := -1;
end;
//http post
IdHTTP2.Post(URL, data, response);
Does anyone have any recommendations to solve this problem? I tried to set the ReadTimeout variable but this had no change. Any pointers to solve this problem would be much appreciated.
TIdSSLIOHandlerSocketOpenSSL sets a hard-coded 30 second read/write timeout on an SSL socket on Windows Vista+ when the ReadTimeout property is <= 0, so chances are the connection is slow enough to take longer than 30 seconds to transmit data. Try setting the ReadTimeout property to a higher value to see if it delays the error. If so, then there really is a transmission issue.
You can use a packet sniffer, such as Wireshark, to make sure data is actually being transmitted back and forth in a timely manner. Also look at the call stack when the exception is raised to see if the timeout is occurring during the SSL handshake, while sending the HTTP request, or while receiving the HTTP response. That will help determine whether it is an issue with OpenSSL, Indy, or the server.
Related
I use Delphi 10.1 Update 2 and Indy 10.6.2.5341.
We experience access violations in SSL_accept. This happens if a TIdTCPServer is setup using SSL and there is an open connection that has NOT yet negotiated TLS if the TIdTCPServer is stopped.
This looks like a problem in Libssl32 or Indy. This can be simply reproduced with the following code and Putty using a RAW connection. Does anyone knows a solution (or workaround) to prevent these crashes?
procedure TSslCrash.HandlerOnExecute(AContext: TIdContext);
begin
//
end;
procedure TSslCrash.HandlerOnConnect(AContext: TIdContext);
begin
TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;
procedure TSslCrash.ButtonStartClick(Sender: TObject);
begin
LServer := TIdTCPServer.Create;
LIOHandler := TIdServerIOHandlerSSLOpenSSL.Create;
LIOHandler.SSLOptions.Mode := sslmServer;
LIOHandler.SSLOptions.Method := sslvTLSv1_2;
LIOHandler.SSLOptions.VerifyMode := [];
LIOHandler.SSLOptions.VerifyDepth := 0;
LIOHandler.SSLOptions.CertFile := 'localhost.crt';
LIOHandler.SSLOptions.RootCertFile := 'localhost.crt';
LIOHandler.SSLOptions.KeyFile := 'localhost.key';
LServer.Bindings.Add.Port := 10000;
LServer.IOHandler := LIOHandler;
LServer.OnExecute := HandlerOnExecute;
LServer.OnConnect := HandlerOnConnect;
LServer.Active := True;
//Now open a RAW connection with Putty on port 10000 and keep it open
end;
procedure TSslCrash.ButtonStopClick(Sender: TObject);
begin
if Assigned(LServer) then begin
LServer.Active := False; //This causes an AV in TIdSSLSocket.Accept
FreeAndNil(LIOHandler);
FreeAndNil(LServer);
end;
end;
When Putty is connected in Raw mode, there is no SSL/TLS handshake performed, so SSL_accept() is stuck waiting for a handshake request that never arrives.
When TIdTCPServer is being deactivated, it disconnects active socket connections, failing any blocking socket operations in progress in other threads. In the case of SSL_accept(), that should unblock it so it can exit with an error code that TIdSSLSocket.Accept() can then detect and wrap into a raised exception (EIdOSSLUnderlyingCryptoError, EIdOSSLAcceptError, EIdSocketError, etc depending on the nature of the error code) in the context of the client thread that is waiting for the handshake to complete.
However, when TIdTCPServer is disconnecting a socket connection during deactivation, TIdTCPConnection.Disconnect() is called, which calls TIdIOHandler.Close(), which TIdSSLIOhandlerSocketOpenSSL has overridden to free its internal TIdSSLSocket object - the same object that is calling SSL_accept(). So it is quite likely that the underlying OpenSSL SSL object is being freed in TIdSSLSocket.Destroy() (which calls SSL_shutdown() and SSL_free()) in the context of the deactivating thread while still actively being used in TIdSSLObject.Accept() (which calls SSL_accept()) in the context of the client thread, thus causing an Access Violation.
There is not much that can be done about this without altering Indy's source code. For instance, maybe change TIdCustomTCPServer.DoTerminateContext() to call AContext.Binding.CloseSocket() instead of AContext.Connection.Disconnect(False) so the IOHandler itself is not closed, just the underlying socket (similar to what TIdCustomTCPServer.StopListening() does when terminating its listening accept() threads).
I have opened a ticket in Indy's issue tracker for you:
#218: Access Violation in SSL_accept() when deactivating TIdTCPServer
Hello im trying to send a file Via TCP with delphi using Indy Components with a Client/Server
i manage to send and recieve the files correctly, the problem is before sending the file i would like to send its size aswell to compare it after i get it the server.
Now im sending the files from the Client To Server.
Client:
Ms := TMemoryStream.Create;
Ms.LoadFromFile('cliente.exe');
Ms.Position := 0;
Result := True;
Client.IOHandler.LargeStream := True;
try
Client.IOHandler.Write(ms, 0, True);// (Ms, 0, true);
except
Result := False;
end;
Ms.Free;
Server:
AStream := TFileStream.Create('C:\temp\file.exe', fmCreate + fmShareDenyNone);
try
AContext.Connection.IOHandler.LargeStream := True;
AContext.Connection.IOHandler.ReadStream(AStream, -1,false);
finally
FreeAndNil(AStream);
Memo1.Lines.Add('File received');
end;
So the question would be how could i send the file size with the file?
Your code is already sending the file size. You are setting the AWriteByteCount parameter of Write(TStream) to True, which tells it to send the stream size before sending the stream data. And you are telling ReadStream() to read the stream size before reading the stream data. So Indy is already validating the size for you before ReadStream() exits. You don't need to do it manually at all.
I've this code snippet in Python:
s = socket.create_connection(('192.168.0.111', 123), timeout=2.0)
s.sendall('REQUEST,status,interface'); result = s.recv(1024)
How I can do the "s.recv(1024)" in Delphi using TIdTCPClient from Indy components? Server returns a string without any terminator, so ReadLn doesn't work.
In Python, recv(1024) simply reads whatever is available on the socket, up to 1024 bytes max. It is possible to do the same thing with TIdTCPClient (see below), but it is not the best way to handle socket programming in general. You really need to know how the server is actually terminating the data. Does it close its end of the connection after sending the data? If not, does it expect you to simply read whatever bytes are available regardless of the actual length? And if so, how does it expect you to handle TCP packet fragmentation (TCP/IP can separate transmitted data into multiple packets, and may receive data as multiple packets even if they were not sent as such)? Does it expect you to keep reading until some timeout occurs, indicating no more data is being sent?
It makes a big difference in how you write code to handle the reading properly. For example:
IdTCPClient1.Host := '192.168.0.111';
IdTCPClient1.Port := 123;
IdTCPClient1.ConnectTimeout := 2000;
IdTCPClient1.Connect;
try
IdTCPClient1.IOHandler.Write('REQUEST, status, interface');
// wait for a disconnect then return everything that was received
Result := IdTCPClient1.IOHandler.AllData;
finally
IdTCPClient1.Disconnect;
end;
Vs:
IdTCPClient1.Host := '192.168.0.111';
IdTCPClient1.Port := 123;
IdTCPClient1.ConnectTimeout := 2000;
IdTCPClient1.Connect;
try
IdTCPClient1.IOHandler.Write('REQUEST, status, interface');
// set the max number of bytes to read at one time
IdTCPClient1.IOHandler.RecvBufferSize := 1024;
// read whatever is currently in the socket's receive buffer, up to RecvBufferSize number of bytes
IdTCPClient1.IOHandler.CheckForDataOnSource;
// return whatever was actually read
Result := IdTCPClient1.IOHandler.InputBufferAsString;
finally
IdTCPClient1.Disconnect;
end;
Vs:
IdTCPClient1.Host := '192.168.0.111';
IdTCPClient1.Port := 123;
IdTCPClient1.ConnectTimeout := 2000;
IdTCPClient1.Connect;
try
IdTCPClient1.IOHandler.Write('REQUEST, status, interface');
// keep reading until 5s of idleness elapses
repeat until not IdTCPClient1.IOHandler.CheckForDataOnSource(5000);
// return whatever was actually read
Result := IdTCPClient1.IOHandler.InputBufferAsString;
finally
IdTCPClient1.Disconnect;
end;
Using Delphi XE2, Indy 10 that ships with it and OpenSSL dll's version 1.0.1c.
We are in the final stages of converting our Delphi 6 project to Delphi XE2.
We have solved every show stopper so far but I am running into one trying to connect to Gmail smtp server.
Our Delphi 6 app works fine using SSL v2.3 and SSL v3 and Indy 9 components connecting to port 465 per Google's own documentation. Google Support
Our Delphi XE2 app does not connect at all. The call to connect goes into the ether and nothing happens for some 7 minutes until I get bored waiting for the thing to timeout and kill it off. I actually traced the program execution all the way to the IdWinsock2 funcion here:
function Stub_select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Integer; stdcall;
begin
#select := FixupStub(hWinSockDll, 'select'); {Do not Localize}
Result := select(nfds, readfds, writefds, exceptfds, timeout);//<-this line never returns and timeout is always nil
end;
I need to maintain the old SSL connectivity for existing users' configurations.
New users will be able to connect using TLS (to port 587) and that DOES work!?!?
I am at a loss as to why the non-TLS SSL options do not work and do not report any error and do not time out but just go off to Never-Never Land. Please help!
TJ
Here is the code:
SMTPClient.Host := trim(EditSMTPServer.Text);
SMTPClient.Port := EditSMTPServerPort.AsInteger;//<- value from custom edit box
SMTPClient.Username := trim(EditSMTPLogon.Text);
SMTPClient.Password := trim(EditSMTPPassword.Text);
SMTPClient.AuthType := satDefault;
if CheckBoxUseSSL.Checked then begin
SMTPClient.IOHandler := IdSSLIOHandlerSocket1;
IdSSLIOHandlerSocket1.ReadTimeout := 30000;//30 second timeout which does not appear to work
case ComboBoxSSLMode.ItemIndex of
0 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv2;
1 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv23;
2 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv3;
3 : begin
IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLsv1;
SMTPClient.UseTLS := utUseImplicitTLS;
end;
end;//case
IdSSLIOHandlerSocket2.SSLOptions.Method := IdSSLIOHandlerSocket1.SSLOptions.Method;
IdSSLIOHandlerSocket2.PassThrough := False;
end
else begin
SMTPClient.IOHandler := nil;
end;
try
SMTPClient.Connect;
if SMTPClient.Connected then begin
if SMTPClient.Authenticate then begin
... do some work ...
end;
end;
except
on e:Exception do begin
showmessage(e.message);
end;
end;
EDIT:
As usual, after I post a question I have stumbled across a workaround.
If I set the UsetTLS property to utUseImplicitTLS for all NON-SSL transactions and set it to utUseExplicitTLS for TLS transactions my connections appear to work in a timely manner.
Hopefully this helps someone out.
updated code:
if CheckBoxUseSSL.Checked then begin
SMTPClient.IOHandler := IdSSLIOHandlerSocket1;
SMTPClient.UseTLS := utUseImplicitTLS;
case ComboBoxSSLMode.ItemIndex of
0 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv2;
1 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv23;
2 : IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv3;
3 : begin
IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLsv1;
SMTPClient.UseTLS := utUseExplicitTLS;
end;
end;//case
IdSSLIOHandlerSocket2.SSLOptions.Method := IdSSLIOHandlerSocket1.SSLOptions.Method;
IdSSLIOHandlerSocket2.PassThrough := False;
end
else begin
SMTPClient.UseTLS := utNoTLSSupport;//reset TLS support flag
SMTPClient.IOHandler := nil;
end;
What you discovered is what you are supposed to be doing. SSL and TLS have different semantics, so you have to set UseTLS accordingly.
For SSL on port 465, the server expects your client to initiate an SSL handshake immediately upon connecting, before the server then sends an encrypted Greeting. UseTLS=utUseImplicitTLS does that, but UseTLS=utUseExplicitTLS does not. When UseTLS=utUseExplicitTLS, TIdSMTP will expect the server to send an unencrypted Greeting immediately, which would explain the hang in select() - the server is not sending any data!
For TLS on port 587, the server is expecting the client to connect initially unencrypted and then send an explicit STARTTLS command when it is ready to initiate encryption. UseTLS=utUseExplicitTLS does that, but UseTLS=utUseImplicitTLS does not.
I have a delphi code that basically upload files to remote secure server using Indy 10.4.704:
IdHTTP := TIdHTTP.Create(nil);
try
TheCompressor := TIdCompressorZLib.Create(nil);
TheSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
with IdHTTP do
begin
HTTPOptions := [hoForceEncodeParams];
AllowCookies := True;
HandleRedirects := True;
ProtocolVersion := pv1_1;
IOHandler := TheSSL;
Compressor := TheCompressor;
end; // with
// Get upload resume offset
try
IdHttp.Head('https://www.domain.com/my-file.bin');
if (IdHttp.Response.ResponseCode <> 404) And (IdHttp.Response.ContentLength >= 0) then
StartPos := IdHttp.Response.ContentLength
else
StartPos := 0;
except
StartPos := 0;
end; // try/except
// Upload File
TheFile := TFileStream.Create(FileName, fmOpenRead OR fmShareDenyWrite);
RangeStream := TIdHTTPRangeStream.Create(TheFile, StartPos, -1, True);
try
if (RangeStream.ResponseCode = 206) then
IdHTTP.Post(https://www.domain.com/upload.php', RangeStream);
finally
RangeStream.Free;
end; // try/finally
finally
FreeAndNil(IdHTTP);
end; // try/finally
The problem is that sometimes the code fails with Indy throwing a EIdSocketError Socket Error # 0 exception (idHTTP.ResponseCode is -1)
Given my crappy internet connection, I launched an EC2 windows instance and tested my code on it (the windows instance is running on the cloud, so I assume connection is not a problem), yet I got the same issue!
The error seems to be random, sometimes upload works, sometimes not. I debugged with TidLogFile, all I could find is something like this:
Stat Connected.
Sent 4/26/2012 4:18:42: POST /app/upload.php...
Sent 4/26/2012 4:18:42: <uploaded_file_data_here>
Stat Disconnected.
Anyone knows what's causing this/how to fix this?
EDIT
I traced the exception back to TIdSSLIOHandlerSocketOpenSSL. I googled a lot, it seems that it's not an SSL error.
Please upgrade to the latest Indy 10 version, which is 10.5.8 r4743. SSL-related issues with Error Code 0 were fixed over a year ago.