How to display messages in every Indy event? - c++builder

I am working on a C++ Builder application using the Indy library. There are two main objectives:
To perform a forward between a server and a client.
To visualize the traffic and its decoding on a window (not console, windows app)
After implementing the solution described in:
Why do I need to send a message twice to trigger Indy's OnExecute event?
And modifying the solution to my needs, the application started to hang. Apparently, the application works well until I want to stop the TIdMappedPortTCP component or close the application.
As the application is small so far, I created a new project and started migrating portions of the code to try to identify the reason this is happening.
I was able to reproduce the undesired behaviour by just "printing" messages during Indy's events.
The OnExecute event has not been implemented yet (in the new project) which means that TCP data is flowing both ways.
This is my sync class implementation:
// TTextToDisplay.cpp
TTextToDisplay::TTextToDisplay() {
lineToAdd = NULL;
stringsToAdd = NULL;
}
TTextToDisplay::TTextToDisplay(String str) {
lineToAdd = str;
stringsToAdd = NULL;
}
void __fastcall TTextToDisplay::AddSingleLine(String str)
{
lineToAdd = str;
}
void __fastcall TTextToDisplay::AddStringList(TStringList* strings)
{
stringsToAdd = strings;
}
void __fastcall TTextToDisplay::DoSynchronize(){
// Use the input parameters here...
if (stringsToAdd)
Form1->Display->Lines->AddStrings(stringsToAdd);
else if (lineToAdd != NULL) {
Form1->Display->Lines->Add(lineToAdd);
}
}
Where Display is a TRichEdit control, lineToAdd is a String object and stringsToAdd is a TStringList.
Indy manages several events and I would like to add a text on each of them (if it's not forbidden by design or any other restriction).
I added this event:
void __fastcall TForm1::MITMProxyBeforeConnect(TIdContext *AContext)
{
String tempStr;
// displaying remote address.
tempStr = "Received connection from " +
AContext->Connection->Socket->Binding->PeerIP;
TTextToDisplay *TextToDisplay = new TTextToDisplay(tempStr);
TextToDisplay->Synchronize();
delete TextToDisplay;
}
The application was working fine. Then I added this:
void __fastcall TForm1::MITMProxyDisconnect(TIdContext *AContext)
{
String tempStr;
// displaying remote address.
tempStr = "Client disconnected"; TTextToDisplay *TextToDisplay =
new TTextToDisplay(tempStr); TextToDisplay->Synchronize();
delete TextToDisplay;
}
The application is still working fine. So I added one more
void __fastcall TForm1::MITMProxyConnect(TIdContext *AContext)
{
String tempStr;
// displaying remote address.
tempStr = "Attempting to connect to the remote server " +
MITMProxy->MappedHost + ":" + MITMProxy->MappedPort;
TTextToDisplay *TextToDisplay = new TTextToDisplay(tempStr);
TextToDisplay->Synchronize();
delete TextToDisplay;
}
And now the application starts to hang.
Working fine means that I can close the TIdMappedPortTCP
MITMProxy->Active = False;
and reactivate it
MITMProxy->Active = True;
several times, receive some messages and then close the application without it becoming irresponsive.
I would like to keep the application as verbose as possible, so is there a better way to log every Indy event?
The application that I was originally working on was doing great until I add some custom display of the data. Then the problem appeared. I don't know if the cause is related but the behaviour is the same.
So my application instead of showing this string:
008460000000190210703800000EC00000164593560001791662000000000000080000000002104302040235313531353135313531353153414C4535313030313233343536373831323334353637383930313233
Now shows:
0000: 60 00 00 00 19 02 10 70 38 00 00 0E C0 00 00 16
0010: 45 93 56 00 01 79 16 62 00 00 00 00 00 00 08 00
0020: 00 00 00 02 10 43 02 04 02 35 31 35 31 35 31 35
0030: 31 35 31 35 31 53 41 4C 45 35 31 30 30 31 32 33
0040: 34 35 36 37 38 31 32 33 34 35 36 37 38 39 30 31
0050: 32 33
This is a TStringList because it's easier for me to add all those lines to the TRichEdit at once. I want a second TRichEdit to show the decoded message.
To give you an idea it would be something like this:
000 MsgType : "0200"
001 BitMap : "70 24 06 80 20 C0 06 10"
002 PAN : "4593560001791662"
003 ProcessingCode : "000000"
004 TxnAmount : "000000080000"
011 SystemTraceNo : "000001"
014 ExpirationDate : "2411"
022 POSEntryMode : "520"
023 CardSequenceNo : "000"
025 POSConditionCode : "00"
035 Track2 : "4593560001791662=24111190000063900000"
041 TerminalID : "00064600"
042 AcquirerID : "000010585800001"
054 AddAmounts : "0"
055 Field55 : "9F 26 08 35 C2 C4 DF B5 FC 7B 0E 9F 27 01 80 9F 10 07 06 01 0A 03 A0 B8 03 9F 37 04 C1 5C 4B 3B 9F 36 02 01 3A 95 05 00 80 00 80 00 9A 03 22 04 02 9C 01 00 9F 02"
060 Field60 : "00 00 08"
--------------------------------------------------------------
Field 55 by Tag:
9F26 AppCryptogram : "35 C2 C4 DF B5 FC 7B 0E"
9F27 CryptogramInfoData : "80"
9F10 IssuerAppData : "06 01 0A 03 A0 B8 03"
9F37 UnpredictableNo : "C1 5C 4B 3B"
9F36 AppTxnCounter : "01 3A"
95 TermVerifResults : "00 80 00 80 00"
9A TxnDate : "220402"
9C TxnType : "00"
9F02 AmountAuthNum : "20"
A final consideration, I know apps that do the forwarding, and I know applications that decode, but I haven't seen apps that do both and that is why I want to create it. But, so far the hardest part has been the visualization. So I don't know if I am using the right tools or the right approach to build what I want. Any advice will be highly appreciated.

Indy servers are multi-threaded, and serrver shutdown is synchronous - it waits for the server's threads to fully terminate before returning to the caller.
TIdSync (and TThread::Synchronize() and equivalent) delegate to the main UI thread, blocking the calling thread until the main thread finishes processing the sync request.
So, you can easily get into a deadlock situation if you Synchronize with the main thread while the main thread is shutting down the server. The main thread will be waiting on the server's threads, while a syncing thread will be waiting on the main thread.
So, your options are to either:
Simply don't Synchronize at all during server shutdown. Set a flag somewhere before starting the shutdown, and then look at that flag before performing a sync. Although, this won't catch the scenario where the shutdown begins after a sync is already in flight.
Don't perform a synchronous sync, perform an asynchronous sync instead (TIdNotify, TThread::Queue(), or equivalent). There is no good reason to block your server threads waiting for the main thread to perform UI status updates.
Shutdown the server in a separate thread, leaving the main thread free to process sync requests.

Related

Flow control message while receiving CAN message with ELM327

I am trying to make a software, which runs under Windows and communicates with an ELM327 device. I created the first version and I went in my SMART ForTwo (SMART 451) vehicle and I managed to connect with the Instrument Cluster (Transmit CAN ID is 782, Receive CAN ID is 783). However I have a huge problem with Flow Control. Here is the log:
TX: ATI
RX: ELM327 v1.5a
TX: ATE0
RX: ATE0 OK
TX: ATSP6
RX: OK
TX: ATH1
RX: OK
TX: ATL1
RX: OK
TX: ATCFC1
RX: OK
TX: ATFCSM0
RX: OK
TX: ATAL
RX: OK
TX: ATSH782
RX: OK
TX: ATCRA783
RX: ?
TX: ATST64
RX: OK
TX: 1092
RX: 783 02 1A 87
TX: 1A87
RX: 783 10 16 5A 87 05 6E 00 08
I used another tool and I saw that the ELM327 device sends the Flow Control Frame, immediately. It is like this:
891.438 782 02 1A 87
891.444 783 10 16 5A 87 05 6E 00 08
891.444 782 30 00 00 00 00 00 00 00
As you can see - Flow Control frame is sent at exactly the same time as the First Frame, that is sent from the other device. I am sure that the other device has a problem to receive the "Flow Control" frame.
I studied the ELM327 documentation, but did not find any info about how to delay the Flow Control frame.
How should I correctly send the request "1A 87" and receive the response?
It's an old post but might help others!
This is my Experience with First Frame (FF) and Flow Control (FC) on MCP2515 connected with SPI.
First of all you should always send the FC message after the FF message and not in the same time.
Secondly the diagnostic reader can use the ID in the ECU response frame to continue communication with a specific ECU. In particular, multi-frame communication requires a response to the specific ECU ID rather than to ID 7DF. In the easy language you should not send your FF message with ID 7DF and you should address the exact ECU that you want to receive the consecutive frames. For instance requesting car VIN (based on real information from Golf VII):
7DF 02 09 00 00 00 00 00 00 //sending request
7E8 10 14 49 02 01 57 56 57 //receving from main ECU
7E0 30 00 00 00 00 00 00 00 //adressing the main ECU and not 7DF anymore !!
7E8 21 5A 5A 5A 41 55 5A 45 //consecutive messages are sending by 7E0!!
7E8 22 50 35 33 30 36 38 35
Hopefully it helps!
It's very easy, I guess..
Use the ATCFC0 command, and then you can process all the response frames from the control unit, and you need to manually send the flow control frame.

Calculate authenticator field for RADIUS message

I am trying to implement RADIUS protocol. As per the RFC 2866, for RADIUS Accounting, when calculating the Authenticator field these are the steps:
The Authenticator field in an Accounting-Response packet is called
the Response Authenticator, and contains a one-way MD5 hash
calculated over a stream of octets consisting of the Accounting-
Response Code, Identifier, Length, the Request Authenticator field
from the Accounting-Request packet being replied to, and the
response attributes if any, followed by the shared secret. The
resulting 16 octet MD5 hash value is stored in the Authenticator
field of the Accounting-Response packet.
I am trying to calculate it and I can not get the right value:
Code = 5 (0x05) 1 byte
Identifier: 134 (0x86) 1 byte
Length: 20 (0x0014) 2 bytes
Request Authenticator: bac85592365b2e786ad3095a1cf22646 , 16 bytes
There are no Attributes in my response
Shared-secret: 63 21 6d 40 35 32 32 35 (c!m#5225)
so the input for the MD% hash would be:
05860014bac85592365b2e786ad3095a1cf2264663216d4035323235
and I get:
b7ac1e6909302b06bd021aede380dbc5 using these 2 web sites: http://www.md5hashgenerator.com/ and http://www.miraclesalad.com/webtools/md5.php
The actual response has the Authenticator as 9629702dca9469714fb423ca7b1525bc
i am comparing looking at real RADIUS packets being sent by the client/server and the Authenticator that I calculate does not match the one sent by the Server. Any ideas what can be it?
The RFC 2865 at the end has a couple of examples. Example 1, using the shared
secret "xyzzy5461"
User Telnet to Specified Host
The NAS at 192.168.1.16 sends an Access-Request UDP packet to the
RADIUS Server for a user named nemo logging in on port 3 with
password "arctangent".
The Request Authenticator is a 16 octet random number generated by
the NAS.
The User-Password is 16 octets of password padded at end with nulls,
XORed with MD5(shared secret|Request Authenticator).
01 00 00 38 0f 40 3f 94 73 97 80 57 bd 83 d5 cb
98 f4 22 7a 01 06 6e 65 6d 6f 02 12 0d be 70 8d
93 d4 13 ce 31 96 e4 3f 78 2a 0a ee 04 06 c0 a8
01 10 05 06 00 00 00 03
1 Code = Access-Request (1)
1 ID = 0
2 Length = 56
16 Request Authenticator
Attributes:
6 User-Name = "nemo"
18 User-Password
6 NAS-IP-Address = 192.168.1.16
6 NAS-Port = 3
The RADIUS server authenticates nemo, and sends an Access-Accept UDP
packet to the NAS telling it to telnet nemo to host 192.168.1.3.
The Response Authenticator is a 16-octet MD5 checksum of the code
(2), id (0), Length (38), the Request Authenticator from above, the
attributes in this reply, and the shared secret.
02 00 00 26 86 fe 22 0e 76 24 ba 2a 10 05 f6 bf
9b 55 e0 b2 06 06 00 00 00 01 0f 06 00 00 00 00
0e 06 c0 a8 01 03
1 Code = Access-Accept (2)
1 ID = 0 (same as in Access-Request)
2 Length = 38
16 Response Authenticator
Attributes:
6 Service-Type (6) = Login (1)
6 Login-Service (15) = Telnet (0)
6 Login-IP-Host (14) = 192.168.1.3
Problem solved! The online md5 tools expect strings, so even though I was passing the bytes values it was being treated as string, hence the wrong value.

4 byte checksum, sum32 algorithm for Epson printers

I'm programming a low level communication with an Epson tm-t88iv thermal printer on a Linux device, which receives only hexadecimal packages. I have read the manual trying to understand how the checksum is built but i can't manage to recreate it.
the manual says that the checksum are 4 bytes representing the 2 bytes sum of all the data in the package sent.
I have currently four working examples I found by listening to a port on a windows computer with a different program. the last 4 hexadecimals are the checksum (03 marks the end of the data and is included in the checksum calculation, according to the manual).
02 AC 00 01 1C 00 00 03 30 30 43 45
02 AC 00 00 1C 80 80 1C 00 00 1C 00 00 1C 03 30 32 32 31
02 AD 07 01 1C 00 00 1C 31 30 03 30 31 35 33
02 AD 00 00 1C 80 80 1C 00 00 1C 00 00 1C 03 30 32 32 32
I have read somewhere that there is a sum32 algorithm but i can't find any example of it or how to program it.
Wow, this is a bad algorithm! If someone else finds himself trying to understand Epson's terrible low-level communication manual, this is how the check-sum is done:
The checksum base is 30 30 30 30
Sum in hexadecimals all of the data package (for example, 02+89+00+00+1C+80+80+1C+00+01+1C+09+0C+1C+03 = 214)
Then separate the result digit by digit, if its a letter add 1 to the value (for example B2 would be 2|1|4).
sum it to the checksum base number by number starting from right to left (this would be a checksum of 30 32 31 34).
Note: It works perfectly, but for some reason the examples I posted above don't seem to match so much. They are all the printers response, but slightly after it got a hardware problem and had to be reformatted by technical support, so maybe it got fixed.
I hope it helps somebody somewhere.

Delphi 7 turn off creation of DDP files

How do you turn off the feature or stop the creation of all the .ddp files for your Delphi 7 forms? I read something about removing the designdgm60.bpl, but is that the only way? It seems that there was another way I can't remember any longer.
Update: I tried renaming the designdgm70.bpl and that just creates a ton of program errors.
Also, I'm using Delphi 7.2 on one computer and there is no design tab I can see unless its covered by something in CnWizards. 7.2 definitely creates the ddp files though.
DDP files are for Delphi diagrams (DDP stands for Delphi Diagram Portfolio) in Delphi 6-7. Delphi 5 used the DTI extension for this.
DDP files can have meaningful information. They don't get compiled into .DCU/.EXE./... as they are for documentation purposes only.
Did you create diagrams of components on your form/datamodule? I used to do that (to explain structure to co-workers) so I was actually really happy with the DDP files.
Before deleting them, inspect them to see if they contain documentation you want to keep.
You can safely delete them if they are 51 bytes long and the TDUMP of it looks like this:
000000: 07 18 44 45 4C 50 48 49 2E 44 49 41 47 52 41 4D ..DELPHI.DIAGRAM
000010: 2E 50 4F 52 54 46 4F 4C 49 4F 0F 00 00 E0 40 02 .PORTFOLIO....#.
000020: 01 09 06 09 55 6E 74 69 74 6C 65 64 31 06 00 02 ....Untitled1...
000030: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
I suppose that it's impossible to turn off .ddp creation in IDE by built-in methods, but DDevExtensions tool includes this option (File Cleaner)
You can install DDevExtensions which is free.
There is an option which you can check that automatically deletes .ddp files.

Invalid pointer exception when closing app after upgrade from Delphi 2006 to Delphi XE

I've just upgraded a project from Delphi 2006 to Delphi XE. Everything is working as expected except I get an exception when I close my app.
It's not breaking on a code line. It breaks to the CPU window on a LEAVE command.
I've attached a Eureka log if that is any help.
EurekaLog 6.0.25
Application:
------------------------------------------------------
1.1 Start Date : Fri, 3 Dec 2010 10:44:17 +0100
1.2 Name/Description: LogoTid.exe
1.3 Version Number :
1.4 Parameters :
1.5 Compilation Date: Fri, 3 Dec 2010 10:44:15 +0100
1.6 Up Time : 5 seconds
Exception:
----------------------------------------------------
2.1 Date : Fri, 3 Dec 2010 10:44:22 +0100
2.2 Address : 004062A0
2.3 Module Name : LogoTid.exe
2.4 Module Version:
2.5 Type : EInvalidPointer
2.6 Message : Invalid pointer operation.
2.7 ID : 5E21
2.8 Count : 1
2.9 Status : New
2.10 Note :
User:
-------------------------------------------------------
3.1 ID : oda
3.2 Name :
3.3 Email :
3.4 Company :
3.5 Privileges: SeIncreaseQuotaPrivilege - OFF
SeSecurityPrivilege - OFF
SeTakeOwnershipPrivilege - OFF
SeLoadDriverPrivilege - OFF
SeSystemProfilePrivilege - OFF
SeSystemtimePrivilege - OFF
SeProfileSingleProcessPrivilege - OFF
SeIncreaseBasePriorityPrivilege - OFF
SeCreatePagefilePrivilege - OFF
SeBackupPrivilege - OFF
SeRestorePrivilege - OFF
SeShutdownPrivilege - OFF
SeDebugPrivilege - ON
SeSystemEnvironmentPrivilege - OFF
SeChangeNotifyPrivilege - ON
SeRemoteShutdownPrivilege - OFF
SeUndockPrivilege - OFF
SeManageVolumePrivilege - OFF
SeImpersonatePrivilege - ON
SeCreateGlobalPrivilege - ON
SeIncreaseWorkingSetPrivilege - OFF
SeTimeZonePrivilege - OFF
SeCreateSymbolicLinkPrivilege - OFF
Active Controls:
------------------------------------------------------------------
4.1 Form Class : TAppBuilder
4.2 Form Text : LogoTid - Delphi XE - uMain [Running] [Built]
4.3 Control Class:
4.4 Control Text :
Computer:
------------------------------------------------------------------------------------------------
5.1 Name : OLE-LAPTOP
5.2 Total Memory : 3891 Mb
5.3 Free Memory : 778 Mb
5.4 Total Disk : 120 Gb
5.5 Free Disk : 57,93 Gb
5.6 System Up Time: 1 day, 23 hours, 16 minutes, 56 seconds
5.7 Processor : Intel(R) Core(TM) i5 CPU M 520 # 2.40GHz
5.8 Display Mode : 1920 x 1200, 32 bit
5.9 Display DPI : 96
5.10 Video Card : Intel(R) Graphics Media Accelerator HD (driver 8.15.10.2025 - RAM 1721 MB)
5.11 Printer : RICOH Aficio 2232C RPCS (driver 1.0.0)
Operating System:
--------------------------------------------
6.1 Type : Microsoft Windows 7 (64 bit)
6.2 Build # : 7600
6.3 Update :
6.4 Language: Danish
6.5 Charset : 0
Call Stack Information:
-------------------------------------------------------------------
|Address |Module |Unit |Class|Procedure/Method |Line |
-------------------------------------------------------------------
|Running Thread: ID=5632; Priority=0; Class=; [Main] |
|-----------------------------------------------------------------|
|00D171A1|LogoTid.exe |LogoTid.dpr| | |32[5]|
|76A73675|kernel32.dll| | |BaseThreadInitThunk| |
-------------------------------------------------------------------
Assembler Information:
-----------------------------------------------------------------
; System.TObject.FreeInstance
; ----------------------------
00406294 push ebx
00406295 mov ebx, eax
00406297 mov eax, ebx
00406299 call System.TObject.CleanupInstance
0040629E mov eax, ebx
004062A0 call System._FreeMem ; <-- EXCEPTION
004062A5 pop ebx
004062A6 ret
Registers:
-----------------------------
EAX: 02AF8058 EDI: 00000001
EBX: 004062A5 ESI: 004062A5
ECX: 0041D700 ESP: 0018FE98
EDX: 004062A5 EIP: 004062A0
Stack: Memory Dump:
------------------ ---------------------------------------------------------------------------
0018FE98: FFFFFF02 004062A0: E8 3B E7 FF FF 5B C3 90 83 C0 CC 8B 00 C3 8B C0 .;...[..........
0018FE9C: 00404B78 004062B0: 84 D2 74 08 83 C4 F0 E8 54 05 00 00 84 D2 74 0F ..t.....T.....t.
0018FEA0: 02B1CEC0 004062C0: E8 A3 05 00 00 64 8F 05 00 00 00 00 83 C4 0C C3 .....d..........
0018FEA4: 02B1CEC0 004062D0: E8 E3 05 00 00 84 D2 7E 05 E8 82 05 00 00 C3 90 .......~........
0018FEA8: 00404BC2 004062E0: 85 C0 74 07 B2 01 8B 08 FF 51 FC C3 53 56 57 89 ..t......Q..SVW.
0018FEAC: 02B1CEC0 004062F0: C3 89 D7 AB 8B 4B CC 31 C0 51 C1 E9 02 49 F3 AB .....K.1.Q...I..
0018FEB0: 0018FEE8 00406300: 59 83 E1 03 F3 AA 89 D0 89 E2 8B 4B AC 85 C9 74 Y..........K...t
0018FEB4: 004062A5 00406310: 01 51 8B 5B D0 85 DB 74 04 8B 1B EB ED 39 D4 74 .Q.[...t.....9.t
0018FEB8: 03A02F01 00406320: 1D 5B 8B 0B 83 C3 04 8B 73 10 85 F6 74 06 8B 7B .[......s...t..{
0018FEBC: 00406865 00406330: 14 89 34 07 83 C3 1C 49 75 ED 39 D4 75 E3 5F 5E ..4....Iu.9.u._^
0018FEC0: 0045B949 00406340: 5B C3 8B C0 53 56 89 C3 89 C6 8B 36 8B 56 B4 8B [...SV.....6.V..
0018FEC4: 03A02FA0 00406350: 76 D0 85 D2 74 07 E8 85 36 00 00 89 D8 85 F6 75 v...t...6......u
0018FEC8: 03A02F01 00406360: E9 89 D8 E8 78 06 00 00 5E 5B C3 90 87 D1 81 F9 ....x...^[......
0018FECC: 004062EB 00406370: 00 00 00 FF 73 11 81 F9 00 00 00 FE 72 07 0F BF ....s.......r...
0018FED0: 00912606 00406380: C9 03 08 FF 21 FF E1 81 E1 FF FF FF 00 01 C1 89 ....!...........
0018FED4: 00000000 00406390: D0 8B 11 E9 A8 59 00 00 C3 8D 40 00 3B C2 0F 94 .....Y....#.;...
--- Edit
Ok, tried turning of parts of my program until the error went away, and found the troublemaker.
It's my webservice WSDL generated proxy. If I create the proxy object without calling any functions on the service, it throws the error.
I've created a test project without any other code than the proxy object creation and it also throws the error. I've also tried with another webservice, same error. Both webservices was created with Delphi 2006 (.net 1.1).
Lastly I tried with a .net 4.0 webservice created in VS2010. No problems. So either Delphi XE is projects is not compatible with .net 1.1 webservices or Delphi 2006 webservices. Either way it's a mess.
Any thouhts on how to solve this, maybe a workaround?
The log won't help here. It looks like a memory corruption issue, which can happen if your code performs indexed operations on strings (writing to string's character position, for example) and you have not fixed all code where string is casted to PChar or similar code.
In other words, you have to perform careful analysis of your code. Start with turning off some modules and code blocks completely until the exception disappears. Then start adding them one by one.
Likely related to the fact that the string is now a Unicode string (2 bytes per char), and not an AnsiString (1 byte per char). If you play with the raw bytes of strings, this is a major problem. To solve it, simply replace all string to AnsiString and all char to AnsiChar. Of course, you will lose Unicode support by doing this. A better fix is to rework your string handling routines. Often, what is necessary is only to add some multiplicative factors sizeof(char) (=2) every here and there.
Example (old code):
byteSize = length(str);
Example (new code):
byteSize = length(str) * sizeof(char);
Found a solution / workaround.
The error occurs if you use a Webservice directly in a form.
Create an empty vcl forms project, use the wsdl generator to generate a webservice proxy. Include proxy class in uses section. Declare a private object of the proxy, and then in the form create use the proxy class getXXXXXXX function to initiate your object. Run the project.
When you close the form, you get an exception.
The solution / workaround is to create your own class, and talk to the webservice proxy through this class.

Resources