Jump to content
mtjmohr

TServerSocket - TClientSocket Issue - Code from Delphi 7 from 2010

Recommended Posts

I have been carrying out the tests on the live system. At the very moment, I have set up a python server on port 3000, and the "HL7 Sender" program I have compiled here with RAD Studio 10.3.3 CE addresses it correctly, I can follow that under the Python console messages.

 

Most currently, I am going bonkers in my head having been buried the entire day in code (not my natural thing). Therefore, I decided to mimic the live system to be able to handle this issue live here without needing to go to the live system for every test every time. The live development systems are my Wampserver 3.2.3 amd MAMP Pro 4.2.0 (I am using them in comparison to their individual installation and configuration) in which I keep and develop my PHP code for the Mazimoi Obesity Documentation System Suite (Mazimoi ODS Suite) version 7.9.9.9 (version 8 is a major upgrade within a few days to come).

 

Having set up the development system and, thus, mimicking the live system, I will further analyse the Delphi code and especially the asynchronous socket error (Windows 10061).

 

RAD Studio 10.3.3 CE and more recent versions of RAD Studio allow only the installation on Windows 10. Has anyone of you tried to install it onto a Windows server?

 

@Kas Ob.: Yes, you compiled my flowery lengthy wording in a short list. The content is the same 🙂

@aehimself: Yes, the port can be identified as occupied by the Python script. And we continue to talk about the VCL app 🙂

 

I will report about my progress.

Edited by mtjmohr

Share this post


Link to post

So far, I have quit working with Borland Delphi 7. I have it still installed. I have switched to RAD Studio 10.3.3 CE in the first place to go on.

 

Under this version, I have successfully compiled an old code version by ...

  • defining the 32-bit MySQL ODBC driver 5.3.14 in both ANSI and UniCode flavors,
  • using the fore-mentioned driver in its ANSI flavor,
  • adapting the HL7Import.ini accordingly - I will show you the code below, and
  • changing the string declaration to AnsiString declarations (at least for the connection, not yet for the data transfer).

This way, I have a working *.exe which does, however, not yet handle the database table saving procedure. This is still to follow if I have fully understood how to change from string to AnsiString.

 

Here is the *.ini file (in German only):

[Common]
ADTEvents=A01,A08,P01
DatabaseType=MySQL
DatabaseUsername=
DatabasePassword=
ODBCName=ol_ansi_adipositas
TimeOutReconnect=3
LogEmailAddress=
LogEmailSMTPServer=

[HL7-Collector Socket]
Port=3000

[HL7-Parser]
Parsing=0
UpdatePeriodMinutes=60
WaitPeriodDays=60

[HL7-Specification]
PID=PID,3,1
KIS=MSH,2
EventID=MSH,8,2
EventTimestamp=MSH,6,1
Nachname=PID,5,1
Vorname=PID,5,2
Titel=PID,5,5
Geburtsdatum=PID,7,1
Geburtsname=PID,5,3
Geschlecht=PID,8
Land=PID,11,6
Strasse=PID,11,1
PLZ=PID,11,5
Ort=PID,11,3
Nationalitaet=PID,15
Unterrichtung=
IKNummer=IN1,3,1
Krankenkasse=IN1,4,1
VersNummer=IN1,36,0
VersStatus=
VersArtMFR=
StatusErgaenzung=
KVKGueltigBis=
KVKEinlesedatum=

# Fuer BAR P01 HL7-Nachrichten
DiagnoseCode=DG1,3,1
DiagnoseSide=DG1,3,2
DiagnoseDate=DG1,5
ProzedurCode=PR1,3
ProzedurDate=PR1,5

# Beispiel-HL7-Nachricht (Tieto to BariatricManager):
#
# MSH|^~\&|i1 IS-OUT|Ein1^260950226|MANATHEA||20111128101357||ADT^A08^ADT_A01|671405|P|2.4|||AL|NE|DEU||||
# EVN|A08|20111127211747|||Kissmed|20111128101341|Ein1
# PID|1||2104614^^^Ein1^PI~^^^^BSN||Name^Vorname^^^^^L^A~^^^^^^B^A||19411021|M|||Str . XX^^XXXX^^74226^D^H~^^^^^^O||07133.8521 Frau^PRN^PH^^^^07133.8521 Frau~^PRN^FX^^^^~^PRN^CP^^^^~^NET^X.400^^^^|^WPN^PH^^^^|Deutsch|||||||||N||||||N|||20111128101342|||||
# PV1|1|I|Innere II^2303^2303T^Innere^^N|Notfall||^^^^^N|^^^^^|835359379^Liebl^Matthias^^^Dr. med.^^LANR^^^^^^687966600|^^^^^|N||J|||||^^^^^||2117782^^^Ein1^VN|Standard||||||||||||||||||||||||20111127193400||||||||
# PV2|||0107||||||||||||||||||||||||||||||||||||||||||||
# IN1|1|BKK^BKK|9938503^^^BAHN-BKK/WEST^NII~K111167^^^BAHN-BKK/WEST^NIIP|BAHN-BKK/WEST|Karl-Marx-Allee 90 a^^Berlin^^10243||030,26946764|||||19411021|||^||||^^^^^|||||||||||||||||1040412003|||||||||||||1040412003^^^^^^^
# ZBE|2788557|20111127193400||R
#
# (ACK)
# MSH|^~\&|MANATHEA||i1 IS-OUT|Ein1^260950226||20111129100442|ACK^A08|123456|P|2.4
# MSA|AA|671405
#
# (NACK)
# MSH|^~\&|MANATHEA||i1 IS-OUT|Ein1^260950226||20111129100442|ACK^A08|123456|P|2.4
# MSA|AR|671405

The next step is to change all strings into AnsiStrings and then see if the data accepted is being saved in the appropriate database table.

 

I've had enough for today scrutinizing code and learning to handle RAD Studio 10.3.3 CE, I will continue tomorrow and report about milestones.

 

As so often: A small question:

Are there good instruction as to how to change strings into AnsiStrings (I have been using an automating tool for that, cf. http://www.innovasolutions.com.au/delphistuf/ADUGStringToAnsiStringConv.htm) or into UniCodeStrings? If I have understood correctly, RAD Studio 10.3.3 CE uses Unicode as default. This should mean that I actually need to convert my 2010 source code to Unicode strings? Or what is the value of an AnsiString conversion then?

Share this post


Link to post
Guest
8 hours ago, mtjmohr said:

If I have understood correctly, RAD Studio 10.3.3 CE uses Unicode as default.

All the IDE since Delphi 2009 have that.

8 hours ago, mtjmohr said:

This should mean that I actually need to convert my 2010 source code to Unicode strings?

No if it is working on 2010 then strings should not be a problem between 2010 and any newer, that based on what did you mean by "2010", is it a code fully working and tested on "Delphi 2010" or a code written in the year 2010 on older IDE than Delphi 2009.

 

8 hours ago, mtjmohr said:

Or what is the value of an AnsiString conversion then?

I think you by now can see the difference or if you already have a code working on D2010 then compare string handling parts, which is a process might be five minutes or 5 days.

But to begin

1) you should be clear what code is 100% is ansi and working 100% means it is built with D2007 or older,

2) search the above code in all the units for that project for any reference for "string" and "Char", do not include any libraries that does not belong to the project itself, you need to collect how many reference are there and their places, if you opened the project in the IDE then from IDE menu find and use "Find in files" search for both "string" and "Char", for that tick "all files in project", "Whole words only" and "display in separate tab", you might also need to check/search for "Ansistring" and "AnsiChar" to be sure.

3) the result might be hundreds or less, might be just a few, but whatever the result is, it is irrelevant, and you don't need to change most of them, in fact your adjustment might be less than you can imagine, but you definitely should walk each and every declaration of them for where and how they are used, most string and char usage will be working fine except few cases like where every string the size is calculated, i mean if you see this Length(myData) while myData is as string, you should change that to "Length(myData)*SizeOf(Char)" this will make it work on both versions, Char in Ansi does have 1 byte size while in Unicode it is 2 bytes, the usage of Length will be for copy or sending over the socket, here you might have another problem as it might not work like this, may be it is expected to be Ansistring on the other end, in that case "*SizeOf(myData)" will be wrong, and the solution is to leave length as it, but typecast the myData into AnsiString on the operation of copy or send like this "Ansistring(myData)" to replace "myData" in a copy function or the send one.

 

Also you have working unicode part, that mean you can repeat the above "search and follow" to get better understanding how things been handled on that end, this will save you great time.

 

Extra also 🙂 , be careful with using tools to do the converting, as strings in many places should be string and will work fine between all versions, and i hope you did understand the example of changing the length against changing the content in (3).

 

Share this post


Link to post
29 minutes ago, Kas Ob. said:
10 hours ago, mtjmohr said:

This should mean that I actually need to convert my 2010 source code to Unicode strings?

No if it is working on 2010 then strings should not be a problem between 2010 and any newer, that based on what did you mean by "2010", is it a code fully working and tested on "Delphi 2010" or a code written in the year 2010 on older IDE than Delphi 2009.

Ah, yes, stupidly expressed by me, what I mean is the source code from 2010 developed under D7 and ported to D2007.

 

Well, one version of the code from 2010, as I mentioned last night, I was happy to recompile into a fully working *.exe and *.dll using RAD Studio 10.3.3 CE. The problem is, however, that there are some warnings in the code which allude to a possible mismatch between string and AnsiString or AnsiString and string, and I guess that this is the reason why I may have solved the SetPort access issue but not the handling of the data transmitted between the Integration Server and my "HL7 SocketCollector".

In a minute I will show you some of these warnings, and maybe you can tell me whether they are relevant or not.

 

My personal problem hereto is that I have no longer access to the original D7 and D2007 installation into which all necessary libraries, units, and whatsoever had been integrated. Thus, I have no idea whether they in those times had accepted these warnings or "remedied" them, but if the latter had been the case I should see this potential issue (already) resolved in the code or should I not?

Share this post


Link to post
37 minutes ago, Kas Ob. said:
10 hours ago, mtjmohr said:

Or what is the value of an AnsiString conversion then?

I think you by now can see the difference or if you already have a code working on D2010 then compare string handling parts, which is a process might be five minutes or 5 days.

[...]

Thank you so much for taking that much time for an explanation of my "uneducated" questions. My primary programming experiences in "languages for medicine" such as LISP and PROLOG had given me a different style of thinking and handling code, and script languages did not enhance this process. I find it relatively easy to "read" someone else's PHP or Python code and follow what the code is about to do, whereas in Delphi, C++ and C# this process is much harder for me ... I am sorry for that, but as I stated yesterday already I have learnt a great lot from your pointing me to do the right thing. Maybe I can give that back one day ...

Share this post


Link to post

Another question:

 

Would it be helpful for all of you who have intended to help and support me to take a quick look into ...

  • the working *.exe and *.dll from the live system, compared to
  • the freshly RAD Studio 10.3.3 CE-compiled *.exe and *.dll from the D7 / D2007 sources, compared to
  • the freshly RAD Studio 10.3.3 CE-compiled *.exe and *.dll from the modified D7 / D2007 sources?

I will put them all into separate ZIP files (containing the *.ini file and the latest MySQL 5 ODBC driver 5.3.14) on a Google Drive folder and give you the link here ...

 

https://drive.google.com/drive/folders/1xR5u0KIJe_w9R9SSMffyIHUnN-jae7rI?usp=sharing

 

... for your convenience.

Share this post


Link to post
Guest
37 minutes ago, mtjmohr said:

I have no idea whether they in those times had accepted these warnings or "remedied" them, but if the latter had been the case I should see this potential issue (already) resolved in the code or should I not?

About Warnings and Hints, not all are dangerous but i would suggest to handle each and everyone of them, in most case they are not dangerous and will not cause trouble, like the following example

var
  SomeStr:string;
  AnsiOne:AnsiString;
begin
  SomeStr := AnsiOne;     //  [dcc32 Warning] .. W1057 Implicit string cast from 'AnsiString' to 'string'
  AnsiOne := SomeStr;     //  [dcc32 Warning] .. W1058 Implicit string cast with potential data loss from 'string' to 'AnsiString'

  SomeStr := string(AnsiOne);           // no warning
  AnsiOne := AnsiString(SomeStr);       // no warning

We did handle the warning by simply telling the compiler that we know what we are doing, but is there better solution or approach by removing AnsiOne to string, this belongs to where did it came from, is it from a file (like raw reading or an ini file..) or over socket in this case you could convert it to a string earlier instead on passing on as ansistring, unless you are gonna to send/output it as ansi again, this means out conversion is just a waste of time. 

The point is each situation need its solution, and there is no one role to follow.

 

By the way you are doing great, just spend some time in thinking on your methods to fix while keeping the logic work right.

 

I can stress this enough, don't depend on tools to make the transition, they will cost you more time than doing it manually, i expect 90% of the string in the project will not need any change and will work out of the box, only few that handle the I/O (input and output) to disk and socket, those most likely will need adjusting, any string handled or passed by VCL will be compatible out of the box, except the I/O. 

Share this post


Link to post

The 2 following screenshots are made from a recompilation of the original code after automatic string to AnsiString conversion.

 

My next message will contain the difference from the original code without that conversion.

04-01-_2021_08-27-04.png

04-01-_2021_08-28-01.png

Edited by mtjmohr

Share this post


Link to post

The 2 following screenshots are made from a recompilation of the original code without any string conversion (, i. e. the original unmodified code).

04-01-_2021_08-31-10.png

04-01-_2021_08-31-48.png

Share this post


Link to post
Guest
19 minutes ago, mtjmohr said:

Would it be helpful for all of you who have intended to help and support me to take a quick look into ...

I doubt compiled binaries would help at all.

 

As for 51 or less warning, this is nothing and you can track and handle in very short time, i worked on legacy software with +5000 warning and hints, after fixing at least 1000 compiling error.

 

That been said, i am sorry if i am not offering to take this job, simply i hate messing with my IDE's by installing libraries i am not familiar with, i need them clean to finish what i am working on, but some one here might take this, also i am sure that you can do it, by doing it logically and in small steps.

Share this post


Link to post

Let's take one step at a time. String conversions (AnsiString vs. String) will only matter in data transfer / storage but as far as I understand, you can not even connect with your application. Is that right?

 

I'm a bit confused. You said that TCP port 3000 is listening by your Python script...? Shouldn't your application be listening there (that's what TServerSocket does; it listens and accepts client connections)?

Can you share some basic layout of your application? What is running where, what should connect where, etc.

Share this post


Link to post
1 minute ago, aehimself said:

Let's take one step at a time. String conversions (AnsiString vs. String) will only matter in data transfer / storage but as far as I understand, you can not even connect with your application. Is that right?

No, meanwhile the port problem is fixed. I had to do with the Palette icons not dropped onto the FormMain.dfm. Now that works well.

 

2 minutes ago, aehimself said:

I'm a bit confused. You said that TCP port 3000 is listening by your Python script...? Shouldn't your application be listening there (that's what TServerSocket does; it listens and accepts client connections)?

Can you share some basic layout of your application? What is running where, what should connect where, etc.

Nah. I had used that Python server- and client-connection test script to see whether I had a WinSocket problem due to previous Windows hardening in the first place. This was not the case, and I could prove that by opening a Python server port (3000) and listening for a Python client connection to this port which worked flawlessly. So the Python "thingy" was just to test whether I can open and serve a port.

 

Thank you, @aehimself, for mentioning the need to depict a workflow.

 

The program's workflow is as such:

  • My very large PHP-MySQL-JavaScript-XML-based suite called "Mazimoi ODS" can either create a new patient data record manually (there is a PHP-HTML form for that) or ...
  • automatically scan for so-called ADT messages from the HL7 standards versions 2.2 to 2.5 (https://www.hl7.org/ and https://en.wikipedia.org/wiki/Health_Level_7) ...
  • on port 3000 to which a so-called Data Exchange Integration Server (DEIS) sends these ADT messages as the result of the conversion of proprietary data from a clinical information system (CIS) which are often ORACLE-based.
  • My software which I call "Mazimoi HL7 SocketCollector" basically "sniffs" for such ADT messages on port 3000 (agreed upon between DEIS and my software, it could be any other unoccupied port).
  • Before that, it checks whether there is a valid ODBC name installed which you need a MySQL ODBC Connector version 3.x to ideally 5.x set up and running (32-bit also on 64-bit Windows [Windows -> SysWOW64 -> odbcad32.exe -> SystemDSN), if that is not the case, you will receive a Windows error message.
  • The DLL file contains the parsing rules for detecting whether the ADT message is "in good shape" or has formal issues.
  • Thus, when an ADT message (typically A01, A04, A08, P01, R01 ...) arrives at port 3000, this message is parsed.
  • If the parsing does not reflect any formal issues, my software sends an "ACK" to the DEIS telling it that this ADT message has been acknowledged positively. In this case, the data contained in the ADT message (ASCII) is being extracted from the message (cf. an example message format below) and saved in the table "hl7_messages" in the database "adipositas" to be requested by an import step from within Mazimoi ODS (the user searches for a patient's known ID or her / his last or first name, gets the result list of potential patients and then may choose one to take over into the main system).
  • If the parsing finds formal issues, a "NOACK" or "NO_ACK" is sent to the DEIS telling it that the message was rejected, and consecutively such rejected data is being saved in the table "hl7_messages_noack" in the database "adipositas" (within 9 years of running Mazimoi ODS using my "Mazimoi HL7 SocketCollector" not a single data record has been saved there as "NOACK" or "NO_ACK" in the context of roughly 22.5 million single ADT messages).
  • The ADT messages are plain ASCII files delimited by a "|" separator - the only art here is to count the right position of the "field" transferred which is basically clumsy and error-prone, but the advantage is you can deal with a text file and do not need to decode something format-proprietary again.

Here is an example if such ADT messages (all in German, but these messages can be internationalized according to the HL7 standards):

MSH|^~\&|DPS||MANATHEA|3|201206250200||ADT^A01|1522464|P|2.2|||AL|NE
EVN|A01|20120625020049
PID||CMM04069327|10024397|31210357|AAAAAA^BBBBBB||19930604000000|M|||fffffffff 36^^dddddd^^34127^D|06611000|0561/5299887||D||||||||dddddd|N||D
PV1||O|3INAMB^^^3INN||31210357|||||||||||||ANOT|31210357||K||||||||||||||||||3922200|||||20120625020000|20120630235900|||||31210357


MSH|^~\&|MCCGateway|200^0001|KIM|Test1|20040603065933||ADT^A01|999999|P|2.2
EVN|A01|20040603065933|||NP4000
PID|2||0000176633||Pirner^Hans^Herr^^^|Pirner|19370506|M|||Albert Reichstr. 1^^Neumarkt^^92318^DE||||D||||||||||||
PV1|2|O|AM-NOTAU^^^FA-NOTAU^|AM|||^^^^^^^^^^^^^|^^^^^^^^^^^^^|^^^^^^^^^^^^^~~~|AMB|||||||||01168880||K||||||||||||||||||FA-NOTAU||||
|20040603065600||||||00001^^^^4
NK1|2|Pirner^^^^^||Albert Reichstr. 1^^Neumarkt^^92318^DE|||0
IN1|2|0004003230|0105830016^^^|TAUNUS BKK|Heidelbergerstr.14^^Darmstadt^^64283^DE||0180320220400|||||19370506|99991231||R|^^^^^|||^^^^^|||01||||||||||||||0595394007|||||||
IN1|3||^^^||^^^^^|||||||19370506|99991231|||^^^^^|||^^^^^|||99|||||||||||||||||||||


MSH|^~\&|GAPIT|GAPIT|CLOVER|CLOVER|20090610124829^YYYYMMDDHHM||BAR^P01||P|2.2|||NE|NE
EVN|P01
PID|1|0001280539|0001280539||Mustermann^Max^^^Herr||19550122|M|||Musterstraße 6^^Musterstadt^^93053^DE||462410|||vh|RK|||||||||DE|J
PV1|1|O|Amb_ADI^^^A_Chirurgie^^N|VorstatBeh||^^^^^N|^^^^^|993110801^Pache^Ulrich^^^Dr. med.^^LANR^^^^^^658039900|993110801^Pache^Ulrich^^^Dr. med.^^KVNR^^^^^^|Vorstat||J|||||^^^^^||2118733^^^Ein1^VN|Standard||||||||||||||||0401|||||AB|||20111212125900|20111212163113|||||||
PV2|1|S|||||||||||||||||0029096978OBX|1||Vorerkrankung||?
OBX|3||Diagnoseanlass||Eigenuntersuchung
OBX|4||Erstdiagnosedatum||31.12.2007
OBX|5||Aufklärung||N
DG1|1|IC|C48.2 ^^ICD10SGBV_20||20090513082000||||||||||2|Bösartige Neubildung: Peritoneum, nicht näher bezeichnet
PR1|1|OP|3-222||2009051409500000|I|1|||||||2
ORC||C 2009006167-01|C 2009006167-01||CM|||||Pathologie|Pathologie|0000933018|||20090810000000|||PAT_BEFUND^001|
OBR|1||C 2009006167-01|||||||||||20090806153300||||||||20090807133600||||||||||hm|
OBX|1|FT|PATHOLOGY^Pathologiebefund||C_2009006167-01.pdf|PDF|Tester, Karl, 30.01.1999\.br\Material: Urin\.br\\.br\9 ml gelbe klare Flüssigkeit.\.br\\.br\Zytologisch im Zytozentrifugat einzelne urotheliale Schirmzellen sowie\.br\vereinzelt Urothelien aus tieferen Zelllagen, teils mit geringer\.br\Kerngrößenvariation. Einzelne Plattenepithelien aus oberen Zelllagen.\.br\Präzipitate eines fädigen und fein granulären Materials.\.br\\.br\Kritischer Bericht:\.br\\.br\Es handelt sich um einen sehr zellarmen,  zytologisch negativen Urin\.br\(kein Tumorzellnachweis).\.br\\.br\\.br\\.br\\.br\\.br\Prof. Dr. med. T. Rüdiger\.br\\.br\Dieser Befund wurde qualifiziert elektronisch signiert und ist somit\.br\ohne Unterschrift gültig.\.br\|
OBX|2|FT|PATHOLOGY^KRBW||C_2009006167-01.XML|XML||

Short legend:

 

Each element between 2 "|" has a potential meaning. If there is no such "content", i. e. "||" or even "|||||||||||||", that means that there is no such content or that an existing content has not been transformed.

 

Every new message starts with a "MSH".

 

The first line starting with "MSH" ("medical subject header") tells me what this is all about - for instance, take a look at the second example, the name of the sender software ("MCCGateway"), the ADT message type ("ADT^A01") and he used HL7 version ("2.2").

 

The first elements on a new line determine the "originating section" meaning the context where this specific information arose in the CIS and needs to be imported logically into the subsequent systems (e. g. mine).

 

Another art here is to see that some systems say they are using version 2.2 of the HL7 specification when in reality they use e. g. version 2.3, but this can easily be detected within the parsing process described and is of no higher importance. Additionally, there are specialized segments in such ADT messages which can be separately defined, for instance in "OBX segments" where some not routinely available information is saved to. This is as well not an issue since the preceding identifier is always "OBX". Again, this is just for explaining. And finally, there are "verncaculars" or "dialects" of HL7 interpreted by each generating system or DEIS as part of a tiny wee proprietary strategy, but this is seldom the cause of any ACK errors.

 

In conclusion, "Mazimoi HL7 SocketCollector" is a regular and legal "port sniffer" for HL7 ADT messages, parses and accepts or rejects them according to "well-formedness", and saves the acknowledged message in a MySQL table "hl7_messages" (in case of failure "hl7_messages_noack") in the database "adipositas". Of course, port, table and database names are arbitrary and just need to be defined.

 

Last, not least: There is also a "Mazimoi HL7 Files Collector" for those systems which prefer to send ADT messages as single files, but it has become clear during the last 10 years that almost no one uses this way to hand over information (this software checks for the new = most recent arrival of files in a certain directory and then starts the basically same parsing process).

 

And, additionally, there is also the same software not for HL7 but for CSV data (socket collector) or files (files collector), but, again, this has not been in use much and is similarly structured to the HL7 source code. So, if I ever wanted to bring this to new life, I must have fixed the HL7 software issue.

 

Now you should have a complete overview with necessary and unnecessary but context-relevant bits of information.

Share this post


Link to post

So the layout is somewhat like this:

 

image.thumb.png.329f981cbd06197cd7f21f76ac22c59e.png

 

Since I got lost somewhere, I'll start from the beginning. Do you have a FUNCTIONAL issue with the application now (meaning, not the warnings in the source but something not working / not working properly)? If yes, where?

A bit off-topic: is there any particular reason why the packet verification resides in a DLL? If no other application is using it I feel like it only adds unnecessary complexity and points of failure (see one of my first replies about allocations).

Share this post


Link to post

The AnsiString function is now in two units. The new unit is System.AnsiStrings. Further, let them be competent to do so. I'm not him! The change of unit helped me.

Share this post


Link to post
39 minutes ago, aehimself said:

image.thumb.png.329f981cbd06197cd7f21f76ac22c59e.png

I am starting a lecture right now, so I do not have the time to depict it differently, so here just some plain words:

  • An "integration server" receives specific data records about one single patient from its "clinical information system", it transforms, for instance, a data record from an ORACLE database into a single ADT message (thus generates ASCII text) and sends this ADT message to port 3000.
  • My Delphi application "sits" on port 3000 and listens to what comes in.
  • If what comes in is a parsed-as-valid ADT message, it sends back an ACK signal, extracts the individual elements from the ADT message into single items which then are saved into a MySQL (or MSAccess or MSSQLServer or PostGreSQL etc.) database table, in our context in a MySQL database; if the ADT message is malformed or not an ADT message at all (theoretically possible), the message or whatever it might be is rejected, a NOACK signal is sent, and the content is being saved in a different MySQL database table.
  • Basis for the interaction between my Delphi application and the MySQL database is the ODBCname definition (cf. screenshot)
  • Users, on the other hand, have exclusive access to the database via my Mazimoi ODS suite handled by PHP code, they see nothing of that "port 3000 sniffing and data handling" process. They either see the patients in the MySQL database table or they do not see them because, for example, the "integration server" was offline or the patient's data record in the "clinical information system" has been deleted or disactivated.

The "Python script" and "Other sources" are not in that concept. The Python script was a quick hack 4 days ago to see whether my Windows 10 Pro system was able to handle sockets because I had hardened my Windows about a month before and feared that this might have had an influence on ports. I never used this Python script before, it was just a PoC.

 

If you read my 5 bullet points "from left to right" then you see the direction.

 

If you see your "Delphi application" sitting in the middle, then the picture is not right: The Delphi app (DA) communicates with the MySQL database via 32-bit-ODBC, correct. "Other sources" could be the "integration server" (IS), yes, but then the communication between IS and DA is mediated over the port 3000. The "PHP application" (PA) using a "WebUI" only communicates with the Database (using mysqli or PDO), there is no connection to the DA whatsoever. The DA is merely used to evaluate and store the IS-sent ADT messages in the MySQL database. PA and DA never see each other, PA merely sees DA's results as data record entries in the MySQL database.

04-01-_2021_11-00-12.png

04-01-_2021_11-10-04.png

Edited by mtjmohr

Share this post


Link to post
Guest

Sorry i we get repeating questions due lack of understanding, but here another try

43 minutes ago, mtjmohr said:

An "integration server" receives specific data records about one single patient from its "clinical information system", it transforms, for instance, a data record from an ORACLE database into a single ADT message (thus generates ASCII text) and sends this ADT message to port 3000.

Reading from DB and generate ADT messages, moving it from old compiler (AnsiString for string) to modern compiler, that depends on its code if it is using string and there is big chance the code is either declared as ansistring and AnsiChar this will and should work for newer IDE's out of the box, or it is simply strings and char, this most like also will work out of the box, one thing though you can replace all the code in that parser form string to ansistring and or just change it at last step before sending over a socket.

47 minutes ago, mtjmohr said:
  • My Delphi application "sits" on port 3000 and listens to what comes in.
  • If what comes in is a parsed-as-valid ADT message, it sends back an ACK signal, extracts the individual elements from the ADT message into single items which then are saved into a MySQL (or MSAccess or MSSQLServer or PostGreSQL etc.) database table, in our context in a MySQL database; if the ADT message is malformed or not an ADT message at all (theoretically possible), the message or whatever it might be is rejected, a NOACK signal is sent, and the content is being saved in a different MySQL database table.
  • Basis for the interaction between my Delphi application and the MySQL database is the ODBCname definition (cf. screenshot)

Same as above the DB engine and connection is irrelevant here, worst case you need to switch few lines (like AsString to AsAnsiString) etc, as the most important thing is the entry point of the data and the exit point.

49 minutes ago, mtjmohr said:

Users, on the other hand, have exclusive access to the database via my Mazimoi ODS suite handled by PHP code, they see nothing of that "port 3000 sniffing and data handling" process. They either see the patients in the MySQL database table or they do not see them because, for example, the "integration server" was offline or the patient's data record in the "clinical information system" has been deleted or disactivated.

This is also irrelevant to your problem at hand with ansi or 32bit.

 

 

aehimself asked very critical question about the usage of DLL, and i also share his concern about it.

Why there is a DLL ? What purposes it server ? can your Delphi EXE be compiled with its code instead of using an external DLL? ( compiling without a dll is the easiest step)

 

Also i looked at your binaries ( didn't run them) , and that DLL to what see is only responsible for parsing the data, means it will insert extra layer of complexity specially for what i wrote above because if it is using ansistring for its parameters then you have an extra in and out point per function to make the conversion, which might be trivial to fix but you should do on all the parts (other EXE) at the same time.

If it is there so you don't need to recompile the EXE then you are recompiling the DLL each time. 

Another thing it might also produce an obstacle if you are going to convert to 64bit later.

 

In short, that DLL might be carrying most of the work you should concern about.

Share this post


Link to post

I fully agree to omitting the above-mentioned aspects which have nothing to do with the Delphi application regarding its "sniffing" activity and getting data in the right format.

 

However, I usually try to be as thorough as possible when it comes to describing the entire context.

 

I did not have time enough to describe the "DLL incident" 😉 any longer as I had to give my lecture at 11 AM.

 

The DLL, back in 2010, was implemented because the original programmer, son of the then director of the "Institution of Informatics" at the University of Moscow, came to Germany with the Russian teaching then that considerable aspects of a software should be exported into a DLL. He also told me that some of the there-in contained code will get executed only later when needed. Since in those times we did not know which volume of data we had to deal with in the first place, we thought "DLL-outsourcing" the parsing process might be a good idea ...

 

Personally, I am completely "emotionless" regarding the use of a DLL. Actually, that was to be one of my next steps, anyway, to get rid of the DLL as I do not like them very much. However, please bear in mind that I have been able to initially handle all this by means of your helping me only since yesterday and that my prior goal and "what we have agreed on here" was to do things step-wise. And this is exactly what I have followed. In other words: I have not been able time-wise to touch the DLL issue and ask you another question whether it would actually be needed in the first place and, therefore, all the code should not better be incorporated in one single EXE file.

 

🙂

Edited by mtjmohr

Share this post


Link to post

To give you a picture of the whole meaning why this tiny little wee Delphi application is so outstandingly important:

Workflow_HL7_SocketCollector-20210104.jpg

Share this post


Link to post

Look what I just detected:

Although we had decided in 2010 to buy and use ASPack 2.12 to pack our even then rather larger EXE files, one of my 2 Delphi coders used Bobsoft Mini Delphi ... something I had no idea of until this very day (as you may know, this obfuscator / cryptor has become rather "famous" during 2018 and 2019 as it had been used to stealth some RATs active especially in Europe).

 

Maybe that is the reason why the old but running Socket Collectors from 2010 show a 1/70 on VirusTotal ...

 

And even if it is only 1/70, this means that the 3 different Socket Collector versions - I have checked only one so far with Exeinfo PE and PEiD -, up to now, have been FUD ... 😐

04-01-_2021_16-51-47.png

Share this post


Link to post
Guest
20 minutes ago, mtjmohr said:

Bobsoft Mini Delphi

I have no clue about this, never heard of it, and trust me i heard about a lot.

 

And that was a reason why i didn't even ran your compiled binary, i am not saying anything bad could or will happen, but one thing, sign your binary to make people trust running them, a valid signature signed by trusted CA will put some consequences to any damage your binaries can cause, that will make people trust your website and applications.

 

Another thing or information for anyone want to use packer or protector, in some cases using protector is guaranteed way to stay away from false positive.

Read about Software Taggant

https://en.wikipedia.org/wiki/Software_taggant

and browse this to get the idea on how it does work and who was involved at the beginning 

https://media.blackhat.com/bh-us-11/Kennedy/BH_US_11_KennedyMuttik_IEEE_Slides.pdf

 

Simply put a valid signature by a certificate issued by trusted CA should be enough, the problem is that these certificate are getting more and more popular means the chance to be hacked (stolen private key) is higher, and AV software will always be looking for signals (eg the app is using sockets, reading registry...) and with only such signature it might be not enough, also based on the user setting the AV might flag them as virus/trojan.., with protectors the AV will go crazy to flag them, but if the AV does support taggant and your protector signature is valid( means also the protector putting the taggant), then this will give the AV assurance that nothing is wrong and not be false positive, i simplified that greatly but mostly it is a scale of points and thresholds.

 

In short if you are going to use protector then make sure to choose one that does support software taggant, never use a protector without it, also always sign your binaries, unless they are malicious :classic_laugh:

 

Share this post


Link to post

Yes, thank you, a certificate is exactly what I want to turn to once the software is in action.

 

Meanwhile, I have scrutinized the other *.exe files from 2010 and 2011 none of which has BobSoft in it any longer. We then either did not crypt the code or the *.exe files any longer or used tools such as the mentioned ASPack 2.12.

 

I am fully aware of your concern regarding the safety and security but also the "open information strategy" regarding good proprietary software. Nonetheless, even a certificate nowadays, and also 10 years back at Stuxnet times is no longer any guarantee that nothing happens, but people at least can observe your willingness to be on the white and neither the grey nor black side of coding.

 

I will crack on now compiling ... 🙂

Share this post


Link to post

Due to you help, dear friends, I have been successfully able to create both x86- and x64-applications under the original scheme (EXE and DLL) - I have taken the latest source code I could find, associated the files to each other which, version-wise, belonged to one another, and compiled them.

 

There have been some string warnings so far, but none of them hindered compiling. The port is detected correctly, and data can be transferred using the "HL7Sender" test program (I will show you a screenshot in a minute).

 

But as I now want to professionalize the software development process and cycle, I want to do 4 things:

  1. Check the "pristineness" of my software on systems such as Virus Total - done.
  2. Enter my "Details" and Copyright data in the "Version Info" - done.
  3. Generating a md5 hash to identify the authenticity of my software - how can I do this? By using an external tool?
  4. Get a certificate to identify myself as the software originator - is there one which you can recommend?

Furthermore, there are another 2 thoughts I wanted to ask you about:

  1. Does it make any sense to compress the EXE using EXE obfuscator or security tools such as UPX or ASPack?
    Size-wise it is no longer needed, and it surely will not optimize the execution speed of the program itself or the inner processing of data. So what could be a reason to still do it?
  2. Does it make sense to have the software provided with a registration or licence key?
    My setting is that a clinic receives a full virtual software appliance with everything preinstalled or I copy the programs' installer onto the virtual appliance and run it there - per se there is no need for a license file as it is absolutely clear and well-documented where I put my HL7 software (and also the PHP App Suite) on. It is, to be honest, more an emotional question for me as I always wanted to try this out (no need for me, historically, to do that for LISP or PROLOG programs in an academic setting, of course ...). So, just in case I still want to try this out, is there a good solution you might recommend to me?

Share this post


Link to post

Uses System.Hash;

 

....

var

md5kont:ThashMD5;

s1:string

...

 

s1:=md5kont.GetHashString(mystringtohash);

 

br,

m

Share this post


Link to post
Guest
2 minutes ago, mtjmohr said:

Generating a md5 hash to identify the authenticity of my software - how can I do this? By using an external tool?

Not needed and useless.

2 minutes ago, mtjmohr said:

Get a certificate to identify myself as the software originator - is there one which you can recommend?

Anyone from trusted CA will do, so go after the cheapest, although must know this, are you gonna publish/distribute the software as individual developer or as company, this what you should be choosing between, the process of validation your person or company is very different in the documents required, i would choose the cheapest always as long it is trusted by Microsoft, which happen is Sectigo (ex Comodo), they provide have both types of certificates for individuals and organization https://sectigo.com/ssl-certificates-tls/code-signing

but if you searched you will have better offer from retailers of Sectigo itself like this one https://www.ksoftware.net/code-signing-certificates/ or https://www.thesslstore.com/sectigo/sectigo-code-signing-certificate.aspx , i am user of thesslstore for many years now, there help like any other are limited as the validation process is exclusively belongs to the issuer.

use Google for a list of Microsoft trusted CA partners

 

14 minutes ago, mtjmohr said:

Does it make any sense to compress the EXE using EXE obfuscator or security tools such as UPX or ASPack?
Size-wise it is no longer needed, and it surely will not optimize the execution speed of the program itself or the inner processing of data. So what could be a reason to still do it?

Not needed step, the important step is code signing by a certificate.

15 minutes ago, mtjmohr said:

Does it make sense to have the software provided with a registration or licence key?
My setting is that a clinic receives a full virtual software appliance with everything preinstalled or I copy the programs' installer onto the virtual appliance and run it there - per se there is no need for a license file as it is absolutely clear and well-documented where I put my HL7 software (and also the PHP App Suite) on. It is, to be honest, more an emotional question for me as I always wanted to try this out (no need for me, historically, to do that for LISP or PROLOG programs in an academic setting, of course ...). So, just in case I still want to try this out, is there a good solution you might recommend to me?

This is up to you and what kind of users/client you will have, there is no one role fit all here.

 

But i would recommend WinLicense https://www.oreans.com/ to get familiar with, it is protector while license manager at the same time, has good documentation and very good support, i am using since 2011.

 

 

And almost forgot, Congratulations ! and you should be proud of this achievement in such short time.

Share this post


Link to post
1 hour ago, mtjmohr said:

Due to you help, dear friends, I have been successfully able to create both x86- and x64-applications under the original scheme (EXE and DLL) - I have taken the latest source code I could find, associated the files to each other which, version-wise, belonged to one another, and compiled them.

 

There have been some string warnings so far, but none of them hindered compiling. The port is detected correctly, and data can be transferred using the "HL7Sender" test program (I will show you a screenshot in a minute).

Congratulations! Now you can re-think, restructure and modernize your code if you wish (what I strongly advise if you'd like to run it as a service, btw).

 

1 hour ago, mtjmohr said:

Generating a md5 hash to identify the authenticity of my software - how can I do this? By using an external tool?

Since you are already using DCPCrypt, you can use TDCP_MD5 for this purpose. Question is what you want to achieve? Self-diagnosis?

 

1 hour ago, mtjmohr said:

Does it make any sense to compress the EXE using EXE obfuscator or security tools such as UPX or ASPack?

I don't know about ASPack, but UPX is NOT an obfuscator. It's a compressor. An executable you compress with it can be uncompressed to it's original form in a fraction of a second (to be precise - that is exactly what a packed .EXE does)

 

1 hour ago, mtjmohr said:

Does it make sense to have the software provided with a registration or licence key?

That is something what you have to know. Proper licensing is really complex and a never ending cat-and-mouse game. On the other hand, you'll earn your daily bread.

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

×