TTcpServer remote connection to service - delphi

i need win XP service with TTcpServer.
application was created by "File->New->Other->ServiceApplication"
TTcpServer.localport := 33000
server registered with exename.exe /install
everything looks good, even netstat -a shows that port 33000 - LISTENING
but i can`t access that port from outside of this machine. only local.
and when i make the standard application with same params - all ok.
EDIT1
TTcpServe.OnAccept =
procedure TFlexorXL.tcpServerAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var str: string;
begin
if ClientSocket.Connect then
begin
str := ClientSocket.Receiveln;
ClientSocket.Sendln('test');
//ClientSocket.Disconnect;
end;
end;

TCP/IP works just fine in a service (I use it all the time), so you are likely just misusing the TTcpServer component (which is possible, because it is a horribly written component).
If the TTcpServer.LocalHost property is blank then the socket will bind to all available local IPv4 addresses, otherwise it will bind only to the particular IPv4 address that you specify (netstat will show you the actual IP that the server is actually bound to). That is the IP that you must have clients connect to. In the case of 0.0.0.0, you can connect to any IP that belongs to the server's machine.
With that said, in order to actually accept clients, you must either:
set the TTcpServer.BlockMode property to bmThreadBlocking. The server will then use an internal worker thread to accept connections, and each client will run in its own worker thread. However, you must perform all of your client-related logic inside of the TTcpServer.OnAccept event, because a client will be disconnected immediately after that event handler exits.
for any other value of BlockMode, you must call TTcpServer.Accept() yourself, such as in a timer or thread. If you call the overloaded version of Accept() that has no parameters, you must perform all of your client-related logic inside of the TTcpServer.OnAccept event, because the client will be disconnected immediately after that event handler exits. If you call the other overloaded version of Accept() that returns a TCustomIpClient object, then you control the lifetime of that object and can use it however you need.
With that said, if you are doing all of that, and still having problems, then you need to provide more information about your actual TTcpServer setup, show some actual TTcpServer code, etc. As it currently stands, you have not provides enough details to diagnose your problem.

Related

Firebird Events and Firewall Issue (TIBEvents)

I would use the power of Firebird Events with delphi application with TIBEvents component.
The problem is the firewall, not every time have the correct role and when I try to register the events the application stops responding and I must wait...
How can I do?
I also try to call register function in a separated thread but with the same result.
function RegisterEvents(data : Pointer) : Integer;
begin
with Form1 do begin
DBOspitiEvent.Registered := true;
end;
end; //<-- AFTER THIS, APPLICATION IS BLOCKED (for a while)
procedure TForm1.Button2Click(Sender: TObject);
var
ThreadId : Cardinal;
ThreadHandle : Integer;
begin
ThreadHandle := BeginThread(nil,0,#RegisterEvents,nil,0,ThreadId);
if ThreadHandle = 0
then ShowMessage('Error');
end;
For events, a client needs to establish a separate connection, and by default Firebird uses a random port for this. In combination with firewalls, this leads to problems because the port is - for example - not allowed.
You can configure Firebird to use a fixed port, by editing firebird.conf and setting the RemoteAuxPort to a fixed value (eg 3051), and restarting Firebird. You can then configure your firewall to allow this port.
See also How to configure events with firewall?
We had many problems with TIBEvent components since XP SP3 too.
Here is what works perfectly fine for us since than, even with newest Win10 updates:
We use UIB for receiving events. TUIBEvents component. (You may keep IBX for everything else... but UIB is better and faster and FB3.0 compatible.)
Do not execute any long-lasting code inside OnEvent procedure, but rather set multithread-safe variables to mark, what event you received (last time)
Deal with those variable inside each window locally. (For example: running a timer that checks and compares last-event-time with local last-refresh-time.)
If you are running SQL queries in a separate Thread, always create new database + transaction component, DO NOT USE the one from the main thread!
Open 3050 and 3051 TCP ports on Firewall!
We also add "fbserver.exe" file to Firewall exception and to Defender exception.
Set fixed ports in "firebird.conf" file: RemoteServicePort=3050 and RemoteAuxPort=3051
You may create a single FirstInstallScrip.bat file to do all these firewall changes and copies a pre-edited .conf file to FB's directory, overwriting the original one.
And YES, you can create these simple text files easily from Delphi and run it from there. Or notify the user if not ran yet. (You can read the original config file and compare those settings.)
#ECHO program in
#NETSH advfirewall firewall add rule name="FirebirdSQL szerver" program="%programfiles%\Firebird\Firebird_2_5\bin\fbserver.exe" profile=public,private,domain dir=in action=allow edge=yes description="FirebirdSQL Database engine"
#ECHO program out
#NETSH advfirewall firewall add rule name="FirebirdSQL szerver" program="%programfiles%\Firebird\Firebird_2_5\bin\fbserver.exe" profile=public,private,domain dir=out action=allow description="FirebirdSQL Database engine"
#ECHO ports in
#NETSH advfirewall firewall add rule name="FirebirdSQL portok" localport=3050-3051 protocol=tcp profile=public,private,domain dir=in action=allow edge=yes description="FirebirdSQL Database engine ports"
#ECHO ports out
#NETSH advfirewall firewall add rule name="FirebirdSQL portok" localport=3050-3051 protocol=tcp profile=public,private,domain dir=out action=allow description="FirebirdSQL Database engine ports"
#pause
As #Victoria suggested: use better business logic!
You may store your data (red from DB) in PC's memory and show it from there.
Create triggers inside your FB database self-updating the last modification.
Do not delete rows, just mark them as "deleted".
check only "what changed" SELECT * from "Customers" c where c.MODIFIED > '2019...' and compare with data already downloaded before, to reduce SQL load.
use separate, short-time transaction to write data into DB.

Delphi XE3 - Does Reuse socket rsTrue get overridden by system in any case?

Recently I made some very small, very light app that uses two UDP client and two UDP Server components. Apart from several functions, it has basically nothing else in it.
I was stuck for a while with "Cannot bind socket. Address and port already in use", but somehow solved that with changing the ports, using rsTrue property on Reuse Socket, but somehow, several users still got that error when they try to run the connection from the app.
The server and client has to use same port and same address, as the UDPClient needs to have BoundPort the same as UDPServer's binding port. That's because the responses are being sent to the same port the request came from. This was causing the primary error, which was solved with rsTrue property.
Now I wonder, is there any chance that system overrides this settings by something, I'm not familiar with? Because on 12 computers I have tested so far, it worked fine (on one I had to kill Bonjour service as it was using the exact port that I needed, but other than that...)
What could be causing errors otherwise?
These are settings which are being called on Connect button click:
Server.Binding.IP:=Interface.Text;
Server.Binding.Port:=StrToInt(Port.Text);
Server.DefaultPort:=StrToInt(Port.Text);
Client.Host:= DeviceIP.Text;
Client.Port:= 10023;
Client.BoundIP:= Interface.Text;
Client.BoundPort:= StrToInt(Port.Text);
LocalServer.Binding.IP:= '127.0.0.5';
LocalServer.Binding.Port:= 10023;
LocalServer.DefaultPort:= 10023;
LocalClient.BoundIP:= '127.0.0.1';
LocalClient.BoundPort:= 10024;
LocalClient.Host:= '127.0.0.1';
LocalClient.Port:= 10023;
try Client.Active:=True; finally end;
try Server.Active:=True; finally end;
try LocalClient.Active:=True; finally end;
try LocalServer.Active:=True; finally end;
Where Port is the TEdit field for user to enter port, DeviceIP the device's IP, and Interface the local network interface IP that he will use.
The only hardcoded thing that doesn't really need to be hardcoded is LocalClient.BoundPort:=10024, it's just to make GUI as light as possible. But changing this doesn't help either.
The app is kind of a proxy server between the original App on PC, and the device on network.
The 10023 must be set as is, since the device only listens on that port, and the original app only sends to that port!
Any help would be appreciated.
You do not need to use separate TIdUDPClient and TIdUDPServer on the same port. You can use TIdUDPServer by itself and let it handle both sending and receiving. No need to use a separate TIdUDPClient at all.
Also, you are not using the Binding property correctly. When you read a server's Binding property for the first time, the socket is bound using the settings from the server's Bindings collection. Your assignments to Binding.IP and Binding.Port are then ignored. You need to configure the server's Bindings collection first, then use the server's Binding property only for sending (the server will handle the reading for you).
Try this:
Server.Active := False;
Server.Bindings.Clear;
Server.DefaultPort := StrToInt(Port.Text);
Server.Bindings.Add.IP := Interface.Text;
Server.Active := True;
...
Server.Binding.Send(DeviceIP.Text, 10023, data here);
Replies will arrive in the server's OnUDPRead event.
BTW, since you are writing a proxy, have a look at the TIdMappedPortUDP component.

WWW server reports error after POST Request by Internet Direct components in Delphi

I'm using Delphi XE4 and i usually use Indy with IdHttp.POST to POST request to websites,
This time, whenever i try to POST the request i get Error: Your browser is not sending the correct data.
I'm very sure that I'm POSTing the right data, and i'm using the IOHandler and CookieManager.
Been dealing with this for days(literally)
Here is the code(the site in the code):
procedure TForm1.Button1Click(Sender: TObject);
var s, lge, Kf1, Kf2, Kf3, Kf4 : String;
lParam : TStringList;
begin
S := http.Get('https://www.neobux.com/m/l/');
Memo1.Lines.Add(S);
getParamLge(s,lge,'lge');
GetInput(s,Kf1,'id="Kf1"');
GetInput(s,Kf2,'id="Kf2"');
GetInput(s,Kf3,'id="Kf3"');
GetInput(s,Kf4,'id="Kf4"');
lParam := TStringList.Create;
lParam.Add('lge='+lge);
lParam.Add(Kf1+'=USERNAME');
lParam.Add(Kf2+'=PASSWORD');
lParam.Add(Kf3+'=');
lParam.Add(Kf4+'=');
lParam.Add('login=1');
memo1.Lines.Add(http.Post('https://www.neobux.com/m/l/', lParam));
end;
(the getParamLge and GetInput function, are just simple copy and pos functions to extract value from the GET respone).
I thought maybe it needed cookies so i've added this in the beginning:
Cookie.CookieCollection.Clear;
Cookie.CookieCollection.AddClientCookies('CFID=21531887; CFTOKEN=20369251; dh=20130709111845,1920x1080,{ts ''2013-07-09 06:18:58''}; __utma=90161412.436822896.1373368451.1373368451.1373368451.1; __utmb=90161412.11.10.1373368451; __utmc=90161412; __utmz=90161412.1373368451.1.1.'+'utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __asc=06ff77ad13fc32381fd1f5d6405; __auc=06ff77ad13fc32381fd1f5d6405; __atuvc=4%7C28; MS=flat');
But all in vain.
I'm very sure that I'm POSTing the right data
Since it does not work - obviously you do not (or Delphi does not - that makes no difference for server).
You should start usual debugging loop:
Observe reference working behaviour.
Observe your program behavior
Spot the difference
Eliminate the difference
Check if the program works now
If not - go to step 2.
Reference implementation would be some WWW browser working with site: Opera, Chrome, Firefox, MS IE, etc.
Observing tool would be some HTTP Sniffer like WireShark or OmniPacket or Microsoft Net Monitor or else, however this tinkers with OS work on rather deep level.
Or it can be local proxy with GUI, like Proxomitron or Membrane Monitor - but that would require special setup for both the program and the browser, to route their traffic through that local proxy.
Then you should read about HTTP, starting with shallow observation at Wikipedia and then opening related RFC documents (specifications of different part of HTTP protocol) so that you would understand what do the observed differences mean and how to fix them. For example many people use POST request when they actually should use GET request or such.
You want to debug HTTP program but for this HTTP logs, workign and borken, are required and your question lacks them. More so, most probably you can fix it your self, just bring your program's HTTP log to accordance with both RFCs theory and working browsers practice.

how i can trace an IP using delphi

i need trace the route of an ip, actually i am using the TIdTraceRoute indy component from the idTraceRoute unit.
IdTraceRoute1:= TIdTraceRoute.Create(Self);
IdTraceRoute1.ResolveHostNames:= True;
IdTraceRoute1.ReceiveTimeout:= 5000;
IdTraceRoute1.OnReply:= TraceRoute;
IdTraceRoute1.Host:= 'www.google.com';
IdTraceRoute1.Trace;
procedure TForm1.TraceRoute(ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
Memo1.Lines.Add(AReplyStatus.FromIpAddress);
end;
but always return.
0.0.0.0
0.0.0.0
0.0.0.0
0.0.0.0
0.0.0.0
0.0.0.0
exist another way of trace an ip maybe using windows api or using another indy component?
actually i am using delphi-xe and Windows 7.
I just wrote a entry on my blog, wich can help you.
Building a traceroute application with IP geolocation using delphi
Trace is basically based on sending ICMP packets starting with a TTL of 1 and increasing it until reaching the destination. Because each router decrease the TTL, and when it reaches 0 an error is returned to the caller, it can be used to track the "route" packets takes. Note that to work the ICMP protocol must not be stopped by a firewall. ICMP is a protocol that runs atop IP, like TCP does. It doesn't use TCP. You could code a traceroute utility just using ICMP. But does the Windows tracert utility work on your system?

How to redirect registry access of a dll loaded by my program

I have got a dll that I load in my program which reads and writes its settings to the registry (hkcu). My program changes these settings prior to loading the dll so it uses the settings my program wants it to use which works fine.
Unfortunately I need to run several instances of my program with different settings for the dll. Now the approach I have used so far no longer works reliably because it is possible for one instance of the program to overwrite the settings that another instance just wrote before the dll has a chance to read them.
I haven't got the source of the dll in question and I cannot ask the programmer who wrote it to change it.
One idea I had, was to hook registry access functions and redirect them to a different branch of the registry which is specific to the instance of my program (e.g. use the process id as part of the path). I think this should work but maybe you have got a different / more elegant.
In case it matters: I am using Delphi 2007 for my program, the dll is probably written in C or C++.
As an alternative to API hooking, perhaps you could use RegOverridePredefKey API.
Instead of hooking the registry access for the dll, you can use an inter-process lock mechanism for writing the values to the registry for your own app. The idea being that the lock acquired by instance1 isn't released until its dll "instance" has read the values, so that when instance2 starts it won't acquire the lock until instance1 has finished. You'd need a locking mechanism that works between processes for this to work. For example mutexes.
To create mutexes:
procedure CreateMutexes(const MutexName: string);
//Creates the two mutexes checked for by the installer/uninstaller to see if
//the program is still running.
//One of the mutexes is created in the global name space (which makes it
//possible to access the mutex across user sessions in Windows XP); the other
//is created in the session name space (because versions of Windows NT prior
//to 4.0 TSE don't have a global name space and don't support the 'Global\'
//prefix).
const
SECURITY_DESCRIPTOR_REVISION = 1; // Win32 constant not defined in Delphi 3
var
SecurityDesc: TSecurityDescriptor;
SecurityAttr: TSecurityAttributes;
begin
// By default on Windows NT, created mutexes are accessible only by the user
// running the process. We need our mutexes to be accessible to all users, so
// that the mutex detection can work across user sessions in Windows XP. To
// do this we use a security descriptor with a null DACL.
InitializeSecurityDescriptor(#SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(#SecurityDesc, True, nil, False);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.lpSecurityDescriptor := #SecurityDesc;
SecurityAttr.bInheritHandle := False;
CreateMutex(#SecurityAttr, False, PChar(MutexName));
CreateMutex(#SecurityAttr, False, PChar('Global\' + MutexName));
end;
To release a mutex, you'd use the ReleaseMutex API and to acquire a created mutex, you'd use the OpenMutex API.
For CreateMutex see: http://msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx
For OpenMutex see: http://msdn.microsoft.com/en-us/library/ms684315(v=VS.85).aspx
For ReleaseMutex see: http://msdn.microsoft.com/en-us/library/ms685066(v=VS.85).aspx
dirty method: open the dll in a hexeditor and change/alter the registry-path from the original hive to any other you want to use or have your proper settings.

Resources