RTC Forums
November 21, 2024, 10:05:39 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: Second HttpServer on same port > no error?  (Read 4826 times)
MartijnTonies
RTC License
***
Posts: 4


« on: October 19, 2022, 10:35:34 AM »

Hi,

I'm attempting to detect a second TRtcHttpServer starting to listen on the same port.

There appears to be no error when calling .Listen. Any ideas on how to avoid using a port that's already being listened to on a machine?

Code:
 TCP    0.0.0.0:49696          VM-DEVELOPING19:0      LISTENING
  TCP    127.0.0.1:999          VM-DEVELOPING19:0      LISTENING
  TCP    127.0.0.1:999          VM-DEVELOPING19:0      LISTENING
  TCP    127.0.0.1:5037         VM-DEVELOPING19:0      LISTENING

Here, both use port 999.

With regards,

Martijn
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: October 19, 2022, 08:21:39 PM »

A call to Listen on the TRtcHttpServer object should trigger the "OnListenError" event if the Port is already in use, unless another Application has set the SO_REUSEADDR flag while opening their socket on that same Port, in which case you might NOT get errors (on some Windows versions) if you would try to Listen on that same Port, and the behavior of yours and any other Applications "listening" on that same port would be "indeterminate".

From what I can see, Microsoft has introduced a new flag in later Windows versions, which might resolve such problems (SO_EXCLUSIVEADDRUSE), but ... the RTC SDK does NOT have that flag declared, which means that you would have to add it yourself. If that is your intention, then you should open the rtcWinSocket.pas unit from the RTC SDK (it should be in the "Lib" folder) and add the necessary flag in the TRtcWinSocket.Listen method ... somewhere after the socket is created and before it is bound, which is currently in the code block following source code line 1450 (you will see code setting other socket flags there). Adding the following lines of code there, should do the trick ...

Code:
    optval  := -1;
    iStatus := _setsockopt(FHSocket, SOL_SOCKET, -5 {SO_EXCLUSIVEADDRUSE}, @optval, SizeOf(optval));
    if iStatus <> 0 then
      begin
      RealSocketError('setsockopt(SO_EXCLUSIVEADDRUSE)',False);
      Exit;
      end;

SO_EXCLUSIVEADDRUSE is declared as -5 in .NET for C# and as (int)(~SO_REUSEADDR) in WinSock2.h (which is also -5, since SO_REUSEADDR is 4).

WARNING: Administrator rights are (probably) required to set this option/flag.

See this MSDN article for more details about these flags and WinSock API behavior ...
https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse

Best Regards,
Danijel Tkalcec
Logged
MartijnTonies
RTC License
***
Posts: 4


« Reply #2 on: October 20, 2022, 01:52:16 PM »

Hello Danijel,

Well, that's the thing -- I tried this with running 2 instances of a TRtcHttpServer based application, no error.

So in order to reproduce, I then tried it with 2 TRtcHttpServer components in a single application, just to try it out, with a ShowMessage in the OnListenError (and MultiThread set to False, Blocking to True).

No error was raised.

This is all the code there is, running on Windows 10.
Code:
procedure TForm2.Button2Click(Sender: TObject);
begin
  RtcHttpServer.Listen;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  RtcHttpServer1.Listen;
end;

procedure TForm2.RtcHttpServer1ListenError(Sender: TRtcConnection;
  E: Exception);
begin
  Showmessage('server 2: listen error, ' + e.Message);
end;

procedure TForm2.RtcHttpServer1ListenLost(Sender: TRtcConnection);
begin
  Showmessage('server 2: listen lost');
end;

procedure TForm2.RtcHttpServer1ListenStart(Sender: TRtcConnection);
begin
  ShowMessage('server 2: start');
end;

procedure TForm2.RtcHttpServerListenError(Sender: TRtcConnection; E: Exception);
begin
  Showmessage('server 1: listen error, ' + e.Message);
end;

procedure TForm2.RtcHttpServerListenLost(Sender: TRtcConnection);
begin
  Showmessage('server 1: listen lost');
end;

procedure TForm2.RtcHttpServerListenStart(Sender: TRtcConnection);
begin
  ShowMessage('server 1: start');
end;

I expected an error. Instead, "netstat -a" shows the port twice, as 'listening'.

All I really want, is catching the error and trying a different port.  Grin
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: October 20, 2022, 05:35:50 PM »

Oops. You're right. I was only looking at the default (non-blocking / async) WinSock implementation, which is in the rtcWinSocket.pas unit, but forgot about the blocking sockets implementation, which is the rtcSynAPI.pas unit. And there, the Listen method was setting the SO_REUSEADDR flag, which allows the same Port to be re-used. That was a bug. I've fixed it now and pushed an update to GitHub.

Best Regards,
Danijel Tkalcec
Logged
MartijnTonies
RTC License
***
Posts: 4


« Reply #4 on: October 21, 2022, 08:18:36 AM »

Hi Danijel,

Ah, good to hear it wasn't me Wink

Thanks.

With regards,

Martijn
Logged
MartijnTonies
RTC License
***
Posts: 4


« Reply #5 on: October 26, 2022, 10:02:41 AM »

Hi Danijel,

Is the current github source stable? I currently have 9.50 installed.

With regards,

Martijn
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #6 on: October 26, 2022, 10:19:26 AM »

Since the RTC SDK has been in maintenance-only mode (no new features, only minor bug fixes) for several years now, the current GitHub version should not be any less stable than the version you are already using.

Best Regards,
Danijel Tkalcec
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.025 seconds with 16 queries.