Skip to content

Commit 633ee44

Browse files
committed
fix: fails to run netstat or netstat.exe on Windows, try a cross-platform socket approach
todo: test on Linux and macOS Refs #2359
1 parent 4864900 commit 633ee44

File tree

2 files changed

+25
-17
lines changed

2 files changed

+25
-17
lines changed

source/apphelpers.pas

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface
1010
Character, DateUtils, laz.VirtualTrees, SynEdit, SynCompletion, fphttpclient,
1111
{$IFDEF WINDOWS} Windows, {$ENDIF} DelphiCompat,
1212
dbconnection, dbstructures, jsonregistry, lazaruscompat, fpjson, SynEditKeyCmds, LazFileUtils, gettext, LazUTF8,
13-
IniFiles, GraphType;
13+
IniFiles, GraphType, Sockets;
1414

1515
type
1616

@@ -414,7 +414,7 @@ TAppSettings = class(TObject)
414414
function GetOutputFilenamePlaceholders: TStringList;
415415
function GetExecutableBits: Byte;
416416
procedure Help(Sender: TObject; Anchor: String);
417-
function PortOpen(Port: Word): Boolean;
417+
function IsPortFree(APort: Word; const AIP: string = '127.0.0.1'): Boolean;
418418
function GetThemeColor(Color: TColor): TColor;
419419
function ThemeIsDark(ThemeName: String=''): Boolean;
420420
function ProcessExists(pid: Cardinal; ExeNamePattern: String): Boolean;
@@ -2786,23 +2786,31 @@ procedure Help(Sender: TObject; Anchor: String);
27862786
ShellExec(APPDOMAIN+'help.php?place='+EncodeURLParam(Place)+Anchor);
27872787
end;
27882788

2789-
function PortOpen(Port: Word): Boolean;
2789+
function IsPortFree(APort: Word; const AIP: string = '127.0.0.1'): Boolean;
27902790
var
2791-
Output: String;
2792-
CmdResult: Boolean;
2791+
s: LongInt;
2792+
addr: TInetSockAddr;
27932793
begin
2794-
{$IfDef UNIX}
2795-
// Netcat on Linux, macOS and FreeBSD
2796-
CmdResult := Process.RunCommandInDir('', 'nc', ['-w 1 -zv 127.0.0.1 '+Port.ToString], Output);
2797-
Result := not CmdResult;
2798-
{$EndIf}
2799-
{$IfDef WINDOWS}
2800-
// netstat on Windows
2801-
CmdResult := Process.RunCommandInDir('', 'netstat', ['-na -p TCP'], Output);
2802-
Result := (not CmdResult) or (not Output.Contains(':' + Port.ToString + ' '));
2803-
{$EndIf}
2804-
end;
2794+
Result := False;
2795+
2796+
s := fpSocket(AF_INET, SOCK_STREAM, 0);
2797+
if s < 0 then
2798+
Exit;
28052799

2800+
try
2801+
FillChar(addr, SizeOf(addr), 0);
2802+
addr.sin_family := AF_INET;
2803+
addr.sin_port := htons(APort);
2804+
addr.sin_addr := StrToNetAddr(AIP);
2805+
2806+
if fpBind(s, @addr, SizeOf(addr)) = 0 then
2807+
Result := True
2808+
else
2809+
Result := False;
2810+
finally
2811+
CloseSocket(s);
2812+
end;
2813+
end;
28062814

28072815
function GetThemeColor(Color: TColor): TColor;
28082816
begin

source/dbconnection.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ procedure TSecureShellCmd.Connect;
10941094
begin
10951095
// Check if local port is open
10961096
PortChecks := 0;
1097-
while not PortOpen(FConnection.Parameters.SSHLocalPort) do begin
1097+
while not IsPortFree(FConnection.Parameters.SSHLocalPort) do begin
10981098
Inc(PortChecks);
10991099
if PortChecks >= 20 then
11001100
raise EDbError.CreateFmt(_('Could not execute SSH command: Port %d already in use.'), [FConnection.Parameters.SSHLocalPort]);

0 commit comments

Comments
 (0)