Delphi Indy Ping Error 10040 - delphi

I have a small piece of code that checks if a computer is alive by pinging it. We use to have a room with 40 computer and I wanna check remotely through my program which on is alive.
Therefore I wrote a little ping function using indy
function TMainForm.Ping(const AHost : string) : Boolean;
var
MyIdIcmpClient : TIdIcmpClient;
begin
Result := True;
MyIdIcmpClient := TIdIcmpClient.Create(nil);
MyIdIcmpClient.ReceiveTimeout := 200;
MyIdIcmpClient.Host := AHost;
try
MyIdIcmpClient.Ping;
Application.ProcessMessages;
except
Result := False;
MyIdIcmpClient.Free;
Exit;
end;
if MyIdIcmpClient.ReplyStatus.ReplyStatusType <> rsEcho Then result := False;
MyIdIcmpClient.Free;
end;
So I've developped that at home on my wifi network and everthing just work fine.
When I get back to work I tested and I get an error saying
Socket Errod # 10040 Message too long
At work we have fixed IPs and all the computer and I are in the same subnet.
I tried to disconnect from the fixed IP and connect to the wifi which of course is DHCP and not in the same subnet, and it is just working fine.
I have tried searching the internet for this error and how to solve it but didn't find much info.
Of course I have tried to change the default buffer size to a larger value but it didn't change anything I still get the error on the fixed IP within same subnet.
Moreover, I don't know if this can help finding a solution, but my code treats exceptions, but in that case it takes about 3-4 seconds to raise the error whereas the Timeout is set to 200 milliseconds. And I cannot wait that long over each ping.
By the way I use delphi 2010 and I think it is indy 10. I also have tested on XE2 but same error.
Any idea
----- EDIT -----
This question is answered, now I try to have this running in multithread and I have asked another question for that
Delphi (XE2) Indy (10) Multithread Ping

Set the PacketSize property to 24:
function TMainForm.Ping(const AHost : string) : Boolean;
var
MyIdIcmpClient : TIdIcmpClient;
begin
Result := True;
MyIdIcmpClient := TIdIcmpClient.Create(self);
MyIdIcmpClient.ReceiveTimeout := 200;
MyIdIcmpClient.Host := AHost;
MyIdIcmpClient.PacketSize := 24;
MyIdIcmpClient.Protocol := 1;
MyIdIcmpClient.IPVersion := Id_IPv4;
try
MyIdIcmpClient.Ping;
// Application.ProcessMessages; // There's no need to call this!
except
Result := False;
Exit;
end;
if MyIdIcmpClient.ReplyStatus.ReplyStatusType <> rsEcho Then result := False;
MyIdIcmpClient.Free;
end;

For XE5 and Indy10 this is still a problem, even with different Packet Size.
To answer the more cryptical fix:
ABuffer := MyIdIcmpClient1.Host + StringOfChar(' ', 255);
This is a "magic" fix to get around the fact that there is a bug in the Indy10 component (if I have understood Remy Lebeau right).
My speculation is that this has some connection with the size of the receive buffer. To test my theory I can use any character and don't need to include the host address at all. Only use as many character you need for the receive buffer. I use this small code (C++ Builder XE5) to do a Ping with great success (all other values at their defaults):
AnsiString Proxy = StringOfChar('X',IcmpClient->PacketSize);
IcmpClient->Host = Host_Edit->Text;
IcmpClient->Ping(Proxy);
As you can see I create a string of the same length as the PacketSize property. What you fill it with is insignificant.
Maybe this can be of help to #RemyLebeau when he work on the fix.

use this code
ABuffer := MyIdIcmpClient1.Host + StringOfChar(' ', 255);
MyIdIcmpClient.Ping(ABuffer);

Related

IdHTTP Post returns connection reset by peer for Streams over 32KB

I have a problem posting to a web server using HTTPS. I am not sure if the problem is with me or with the server. So it appeared that if I try to post a Stream greater than 32KB, Delphi crashes with Socket Error 10054 - Connection reset by peer.
I am using Delphi XE5 with the internal version of Indy and latest to date open ssl dlls.
I also try this on XE with latest to date Indy and ssl dlls.
Here is part of my code
function TForm1.SendItemsList(aDataList: TStringList): Boolean;
var
aHTTP: TIdHTTP;
aRes: String;
aURL: String;
aErrMsg: String;
aStrm: TMemoryStream;
aResStrm: TMemoryStream;
aXML: TNativeXML;
aTmpNode: TXmlNode;
aErrNode: TXmlNode;
aList: TList;
i: Integer;
begin
Result := False;
aStrm := TMemoryStream.Create;
aResStrm := TMemoryStream.Create;
aXML := TNativeXML.Create(nil);
aHTTP := CreateHTTP('application/x-www-form-urlencoded');
try
aDataList.SaveToStream(aStrm);
aStrm.Position := 0;
aURL := Format(cIRPURL, ['1']);
try
aHTTP.Post(aURL, aStrm, aResStrm);
aResStrm.Position := 0;
aXML.LoadFromStream(aResStrm);
aTmpNode := aXML.Root.FindNode('ResponseCode');
if aTmpNode <> nil then
begin
if aTmpNode.Value <> '0' then
begin
aErrNode := aXML.Root.FindNode('ResponseText');
aErrMsg := '';
if aErrNode <> nil then
aErrMsg := aErrNode.Value;
aList := TList.Create;
try
aXML.Root.FindNodes('Detail', aList);
for i := 0 to aList.Count-1 do
begin
aErrMsg := aErrMsg+#13#10+TXmlNode(aList[i]).Value;
end;
finally
aList.Free;
end;
end;
end;
except
on E:Exception do
begin
if E is EIdHTTPProtocolException then
aErrMsg := E.Message + #13#10 + (E as EIdHTTPProtocolException).ErrorMessage
else
aErrMsg := E.Message;
Exit;
end;
end;
finally
aXML.Free;
aStrm.Free;
aHTTP.Free;
aResStrm.Free;
end;
Result := True;
end;
Where CreateHTTP looks like
function TForm1.CreateHTTP(aContentType: String): TIdHTTP;
begin
Result := TIdHTTP.Create(nil);
Result.ConnectTimeout:=60000;
Result.ReadTimeout:=90000;
Result.ProtocolVersion:=pv1_1;
Result.HTTPOptions := [hoForceEncodeParams];
Result.HandleRedirects:=True;
Result.IOHandler := SSLHandler;
SSLHandler.ReadTimeout := 30000;
Result.Request.Accept:='*/*';
Result.Request.AcceptLanguage:='en-US';
Result.Request.ContentType:=aContentType;
Result.Request.CharSet:='utf-8';
Result.Request.UserAgent := 'Mozilla/5.0';
end;
All these timeouts exist just because I was testing why I get that error. Then I realized that the problem is when the stream to be sent is larger than 32KB.
I can't really say that there is something wrong with the code at all, because in the same way I send data to several other services like Amazon and Walmart for example where I send sometimes megabytes and I don't receive any errors.
The server is IIS but I don't know what version, the support doesn't seem to believe me that I am doing everything OK.
What I notice is that the SSL handler has some default buffer sizes - SendBufferSize and RecvBufferSize which default to 32KB. Well I tried setting that to 1MB but still I get the same error.
If I send something which is less than 32KB then everything is OK. The error is returned immediately after line with POST is executed - there is no delay, just immediate error. Otherwise sending small streams results in having a delay of a second or two before it gets processed and then the debugger goes to the next line. I started believing it is a setting of the IIS and there is really such a setting, but the guys there say everything on their side is ok and they have 4MB of limit for the requests.
The service provider is IRPCommerce but unfortunately I can't give links for testing because of IP filtering which takes place at the moment there.
I spent several days discussing this with them, searching the web for problems any limitations etc.
So is there something I am missing here, any limitations in Indy which may cause this problem, I doubt but just to be sure I am asking? Anything else I can do to make it clearer where the problem might be?
EDIT:
Here is excerpt of the aDataList:
Stock_ExternalStockID|Brands_Active|Brands_Brand|Models_Active|Models_Model|Models_Description|Models_AdditionalInformation1|Models_AdditionalInformation2|Stock_DisplayOrder|Stock_Option|Stock_Price|Stock_RRP|Stock_SupplierCost|Categories_Active|Categories_Name|Stock_PostageWeight|Stock_PartCode|Stock_ISBNNumber|Stock_UPCAPartCode|Stock_EAN13PartCode|Models_ImageURLs|OptionSelector|OptionSelectorAttributes|OptionSelectorCount|Stock_OutOfStockStatus
17664-00001|TRUE|Polypads|TRUE|Polypads Plus One Outsider Pet Bed|<ul><li>The perfect pet bed for any animal around the house or for covering car seats or boots for travelling. </li><li>Convenient to use. </li><li>6cm Plus One thickness. </li><li>Fully machine washable and quick drying. </li><li>As there is such an extensive range of colours available for the Polypad collection many colour combinations will have to be ordered in specifically; this service could take up to two weeks. </li><li>If you do not have any specific colours in mind please select, Colour Not Important, from the drop down menu.</li></ul>| | |10|Royal Blue-Navy|43.95|48.99|21.69|TRUE|Dog Beds|1000|160||||https://saddlery.biz/media/catalog/product/o/u/outp1.jpg|1|21,44|2|10
17664-00002|TRUE|Polypads|TRUE|Polypads Plus One Outsider Pet Bed|<ul><li>The perfect pet bed for any animal around the house or for covering car seats or boots for travelling. </li><li>Convenient to use. </li><li>6cm Plus One thickness. </li><li>Fully machine washable and quick drying. </li><li>As there is such an extensive range of colours available for the Polypad collection many colour combinations will have to be ordered in specifically; this service could take up to two weeks. </li><li>If you do not have any specific colours in mind please select, Colour Not Important, from the drop down menu.</li></ul>| | |20|Soft Blue-Royal Blue|43.95|48.99|21.69|TRUE|Dog Beds|1000|160||||https://saddlery.biz/media/catalog/product/o/u/outp1.jpg|1|21,44|2|10
17664-00003|TRUE|Polypads|TRUE|Polypads Plus One Outsider Pet Bed|<ul><li>The perfect pet bed for any animal around the house or for covering car seats or boots for travelling. </li><li>Convenient to use. </li><li>6cm Plus One thickness. </li><li>Fully machine washable and quick drying. </li><li>As there is such an extensive range of colours available for the Polypad collection many colour combinations will have to be ordered in specifically; this service could take up to two weeks. </li><li>If you do not have any specific colours in mind please select, Colour Not Important, from the drop down menu.</li></ul>| | |30|Black-Purple|43.95|48.99|21.69|TRUE|Dog Beds|1000|160||||https://saddlery.biz/media/catalog/product/o/u/outp1.jpg|1|21,44|2|10
Here I have 165 rows. If I send about 40 of them they go, just because 40 are just about 32KB. I have confirmed that data is not the problem, because I have tried sending one by one each of the lines.
I tried multipart/form-data with no luck. Actually they haven't told me what to use, no matter how much times I have asked about that, so I used the same thing I am using with Walmart.
I think the server is IIS 8.5.
It seems that the "solution" is to change the Content-type to text/xml. None of the other mentioned content-types work with streams larger than 32KB. At the same time I got a confirmation from the developers of the site that the content-type is not considered at all on the server side.
So I am really confused what is going on here and why only 'text/xml' works fine.

Could not bind socket. Address and port are already in use - using TIdSMTPServer and TIdPop3Server

I've probably read dozens of answers and topics through the web, but I'm still missing something in order to fix this error. I have a TIdPop3Server and a TIdSMTPServer and I want to activate them, but I just can't do it successfully. I've set the ReuseSocket property of both to rsTrue and I'm not leaving the Bindings empty when I try to set them both to .Active := True; This is how my code looks like :
with POP3Server do begin
ReuseSocket := rsTrue;
Active := False;
Bindings.Clear;
DefaultPort := 110;
Bindings.Add.IP := myIpAddr;
end;
with SMTPServer do begin
ReuseSocket := rsTrue;
Active := False;
Bindings.Clear;
DefaultPort := 25;
Bindings.Add.IP := myIpAddr;
end;
And I have a TButton that I click where this is called :
SMTPServer.Active := True;
Pop3Server.Acive := True;
If someone had already fixed this problem can he tell me how he had done it (hope I didn't already read his answer somewhere else ...)
You did not say which server is failing to bind. But there is nothing to fix really. Something else on your machine, likely an antivirus or firewall, is already using one of those ports. Use a tool like Netstat or TCPViewer to find out which process is using those ports.

Is globalalloc with GMEM_MOVEABLE dangerous for local variables in Delphi?

Our programming dept just spent about a non-mythical man-month tracking down what we think is a bug in a 3rd party component, here's their copyrighted source code:
function TGDIPPicture.GetImageSizes: boolean;
var
multi: TGPImage;
pstm: IStream;
hGlobal: THandle;
pcbWrite: Longint;
begin
result := false;
if Empty then
Exit;
if FDataStream.Size = 0 then
Exit;
hGlobal := GlobalAlloc(GMEM_MOVEABLE, FDataStream.Size);
if (hGlobal = 0) then
raise Exception.Create('Could not allocate memory for image');
try
pstm := nil;
// Create IStream* from global memory
CreateStreamOnHGlobal(hGlobal, TRUE, pstm);
pstm.Write(FDataStream.Memory, FDataStream.Size,#pcbWrite);
multi := TGPImage.Create(pstm);
FWidth := multi.GetWidth;
FHeight := multi.GetHeight;
Result := true;
multi.Free;
finally
GlobalFree(hGlobal);
end;
end;
We found the problem was with TMS's AdvOfficeTabSet. If we added tabs, then it crashed, if we didn't add tabs then it didn't crash. (the crash was one of those un-debuggable app hangs that hits you 10 steps after the real problem).
Following Raymond Chen's advice I replaced GMEM_MOVEABLE with GPTR and it appears to have fixed the problem.
I'm wondering if anyone can tell me if the above code had any legitimate reason for using GMEM_MOVEABLE. AFAIK it's only for the clipboard and it should always be used with GlobalAlloc.
while I was typing this another programmer got an error in the GlobalFree function using my code. So, apparently this doesn't work either. Could really use some help here!
*CreateStreamOnHGlobal is a Windows API function. (which apparently prefers GMEM_MOVEABLE)
*TGPImage is part of TMS's implementation of the GDI+ library.
Jonathan has identified the obvious problem, that being the double free of the HGLOBAL. But as you have found, the use is GMEM_MOVEABLE is correct.
Frankly, the code seems needlessly complex. I suggest you use the built in stream adapter and avoid any GlobalAlloc. To get an IStream you just need to do this:
pstm := TStreamAdapter.Create(FDataStream);
That's it.

Find the serial port settings in Delphi

Hi I have the need to find the Baud rate and other settings for a serial port, Looking about on the web, it looks like I should be using GetCommConfig, This returns a TCommConfig record with what I assume is the data I need. The problem is the function I wote returns the wrong values.
The code below looks like it is working, but the baud rate is always 1200, which looking in windows device manager (and altering port settings), is wrong.
I have tried calling it like so:
ComPort('com1');
ComPort('COM1');
ComPort('COM1:');
ComPort('COM4');
ComPort('COM9');
the first 4 are valid but return 1200 and the 5th is invalid and returns 0
function ComPort(l_port:String):TCommConfig;
{Gets the comm port settings}
var
ComFile: THandle;
PortName: array[0..80] of Char;
size: cardinal;
CommConfig:TCommConfig;
begin
FillChar(Result, SizeOf(TCommConfig), 0);//blank return value
try
StrPCopy(PortName,l_port);
ComFile := CreateFile(PortName,GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,0{ FILE_ATTRIBUTE_NORMAL},0);
try
if (ComFile <> INVALID_HANDLE_VALUE) then
begin
FillChar(CommConfig, SizeOf(TCommConfig), 0);//blank record
CommConfig.dwSize := sizeof(TCommConfig);//set size
//CommConfig.dcb.DCBlength := SizeOf(_dcb);
size := sizeof(TCommConfig);
if (GetCommConfig(ComFile,CommConfig,size)) then
begin
Result := CommConfig;
end;
end;
finally
CloseHandle(ComFile);
end;
except
Showmessage('Unable to open port ' + l_port);
end;
end;
Stepping through the code, the first 4 always hit the line Result := CommConfig;, so the GetCommConfig is retuning a valid code, so I must be missing something.
I have tryed verious other things, such as setting the length of the dcb record, but all have the same result, as baud of 1200.
Does anyone know where I am going wrong?
The baud rate and other settings for a serial port, are set when the serial port is opened.
I think you are reading default values.
It turns out I was using the wrong function, I should have been using GetDefaultCommConfig and not the GetCommConfig that I was using.
By the look if it, and please correct me if I am wrong, GetDefaultCommConfig returns the settings from windows and GetCommConfig returns the settings of the open connection to the port, writefile opens the port up as it see fit (ignoring the default settings), which is where the 1200 baud rate was coming from.
If this helps anyone in the future, here is the function I came up with.
function ComPort(l_port:String):TCommConfig;
{Gets the comm port settings (use '\\.\' for com 10..99) }
var
size: cardinal;
CommConfig:TCommConfig;
begin
FillChar(Result, SizeOf(TCommConfig), 0);
//strip trailing : as it does not work with it
if (RightStr(l_port,1) = ':') then l_port := LeftStr(l_port,Length(l_port)-1);
try
FillChar(CommConfig, SizeOf(TCommConfig), 0);
CommConfig.dwSize := sizeof(TCommConfig);
size := sizeof(TCommConfig);
if (GetDefaultCommConfig(PChar(l_port),CommConfig,size)) then
begin
Result := CommConfig;
end
//if port is not found add unc path and check again
else if (GetDefaultCommConfig(PChar('\\.\' + l_port),CommConfig,size)) then
begin
Result := CommConfig;
end
except
Showmessage('Unable to open port ' + l_port);
end;
end;

Delphi Twain issue help

Using the DelphiTwain files from http://delphitwain.sourceforge.net/ and am getting some weird behavior.
After each scan a little more memory is being held onto.
After an hour or so of repetitive scans, the image scanned is zoomed in approxamately 10 times, and just the upper-left square inch is stored.
Has anyone had similar issues, or have some suggestions?
Code below...
try
try
Twain := TDelphiTwain.Create(self);
Twain.OnTwainAcquire := TwainAcquireHandler; //manually set the event handler
Twain.OnSourceFileTransfer := TwainSourceFileTransfer;
Twain.OnSourceSetupFileXfer := TwainSourceSetupFileXfer;
Twain.LoadLibrary;
Twain.LoadSourceManager;
Twain.Source[0].Loaded := TRUE;
Twain.Source[0].TransferMode := ttmFile;
Twain.Source[0].EnableSource(false, false);
except on e : exception do
showmessage('Error loading Scanner.');
end;
try
while Twain.Source[0].Enabled do
Application.ProcessMessages;
except on e : exception do
showmessage('Error Scanning Packing List.');
end;
finally
Twain.Source[0].Loaded := FALSE;
Twain.UnloadSourceManager(true);
Twain.UnloadLibrary;
Twain.Destroy;
end;
Since the TDelphiTwain appears to be a component you are creating in code, I would recommend passing in nil for the constructor and calling the .Free method or (as suggested by Joseph) FreeAndNil.
Twain := TDelphiTwain.Create(nil);
try
try
Twain.OnTwainAcquire := TwainAcquireHandler; //manually set the event handler
Twain.OnSourceFileTransfer := TwainSourceFileTransfer;
Twain.OnSourceSetupFileXfer := TwainSourceSetupFileXfer;
Twain.LoadLibrary();
Twain.LoadSourceManager();
Twain.Source[0].Loaded := True;
Twain.Source[0].TransferMode := ttmFile;
Twain.Source[0].EnableSource(False, False);
except on e : exception do
showmessage('Error loading Scanner.');
end;
try
while Twain.Source[0].Enabled do
Application.ProcessMessages;
except on e : exception do
showmessage('Error Scanning Packing List.');
end;
Twain.Source[0].Loaded := False;
Twain.UnloadSourceManager(True);
Twain.UnloadLibrary();
finally
FreeAndNil(Twain);
end;
I would also recommend better exception handling, but not related to question you asked. The only thing users will see and report to you (or worse, the quiet guy in the corner responsible for your IT support who loves to get non-descriptive errors from users) is 'Error doing something'
Good luck
Another area to look at is if the scanner supports WIA (Windows Image Acquisition)
var
DevMgr: IDeviceManager;
Scanner: Idevice;
Picture: IItem;
Image: OleVariant;
AImage: IImageFile;
begin
DevMgr := CreateOleObject('WIA.DeviceManager') as IDeviceManager;
// Figure out which device is the scanner
Scanner:= DevMgr.DeviceInfos.Item[1].Connect;
//Command: Figure out which command scans..
Picture := Scanner.ExecuteCommand(Scanner.Commands.Item[1].CommandID);
//Transfer as JPG
Image := Picture.Transfer(Picture.Formats.Item[1]);
//Save the image
AImage := IImageFile(Image);
AImage.SaveFile('c:\wia_viaScanner\image.' + AImage.FileExtension);
end;
More info on the WIA library can be found here..
http://msdn.microsoft.com/en-us/library/ms629859(VS.85).aspx
Examining the code within these calls may be fruitful:
TwainAcquireHandler;
TwainSourceFileTransfer;
TwainSourceSetupFileXfer;
Do any of those create any objects without freeing them?
If you are using Delphi 2006 or higher, then you can add this line to your .DPR file:
ReportMemoryLeaksOnShutdown := True;
Then reproduce the memory leak, close your app... and it will describe the leaks in detail. A little more info about this can be found here.
On another note, I'd suggest replacing
Twain.Destroy;
with
FreeAndNil(Twain);
.Destroy will call the destructor directly, while FreeAndNil is a safer alternative that will also prevent the "Twain" variable from pointing anywhere dangerous. (See the accepted answer to this question).
I can't address the problem you're reporting but you have a busy loop there that will gobble CPU time.
What are you doing when you get the Image, did you keep in memory?
Or the library can have some memory leaks, you can check if it is true with FastMM4.
to KevinRF:
I need to use WIA automation in Delphi 7 project. I registered WIAAut.dll in my system, import this library into Delphi and past your programm code into my project and got some errors:
Scanner:= DevMgr.DeviceInfos.Item[1].Connect;
Types of actual and formal var parameters must be identical
in "Item" must be Item[var Index: OleVariant], but "1" is integer
What's wrong, what i need to made it works?

Resources