Skip to content

Commit

Permalink
Support for loopback IP addresses (IPv4).
Browse files Browse the repository at this point in the history
Support for loopback IP addresses (IPv4).
New web server configuration parameters: IP address (IPv4) and TCP port.
  • Loading branch information
coffeegreg committed Jul 26, 2023
1 parent ba49c7a commit f8e9da3
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 57 deletions.
27 changes: 19 additions & 8 deletions cfg/ytuner.ini
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
[Configuration]
;v1.0
; Please do not change this value !
INIVersion=1.0.1

;Force the use of the selected IP address of one of the existing interfaces.
;Leave this line commented with semicolon character when you have one IP address only or you are not sure what to do.
;Leave this parameter with "default" value when you have one IP address only or you are not sure what to do.
;The application will find the IP address itself.
;IPAddress=192.168.1.2

;Web server TCP port. Don't change it if it's not necessary. ; Default = 80
WebServerPort=80
IPAddress=default

;Use SSL. 1-Yes 0-No ; Default = 1
UseSSL=1
Expand Down Expand Up @@ -38,7 +37,9 @@ MyStationsFile=stations.ini
;Enables support for radio-browser.info . 1-Yes 0-No ; Default = 1
Enable=1

;Radio-browser.info API URL. Default = http://all.api.radio-browser.info
;Radio-browser.info API URL. Default = http://all.api.radio-browser.info ;
;Warning! Using an IP address instead of a domain name results in faster performance, however, such a domain IP address may change
;and result in loss of connection to radio-browser.info. It is always worth checking the current list of servers at: https://api.radio-browser.info/net.html.
RBAPIURL=http://95.179.139.106

;Radio-browser.info most popular stations limit. Default = 100
Expand All @@ -58,15 +59,25 @@ RBUUIDsCacheAutoRefresh=0
Enable=1

;One common bookmark file (bookmark.xml) for all AVR devices. Otherwise, each AVR will own its own bookmark file. 1-Yes 0-No ; Default = 0
CommonBookmark=1
CommonBookmark=0

;Bookmark stations limit. ; Default = 100
BookmarkStationsLimit=100

[WebServer]
;Web server IP address. Don't change it if it's not necessary. ; "default" mean the same value as entered in IPAddress in Configuration section above.
WebServerIPAddress=default

;Web server TCP port. Don't change it if it's not necessary. ; Default = 80
WebServerPort=80

[DNSServer]
;Enable build-in DNS proxy serwer. 1-Yes 0-No ; Default = 1
Enable=1

;DNS server IP address. Don't change it if it's not necessary. ; "default" mean the same value as entered in IPAddress in Configuration section above.
DNSServerIPAddress=default

;DNS server UDP port. Don't change it if it's not necessary. ; Default = 53
DNSServerPort=53

Expand Down
96 changes: 62 additions & 34 deletions src/common.pas
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ interface

const
APP_NAME = 'YTuner';
APP_VERSION = 'v1.0.0';
APP_VERSION = '1.0.1';
APP_COPYRIGHT = 'Copyright (c) 2023 Greg P. (https://github.com/coffeegreg)';
INI_VERSION = '1.0.1';

YTUNER_USER_AGENT = 'YTuner';
YTUNER_HOST = 'ytunerhost';
Expand All @@ -40,6 +41,7 @@ interface
INI_RADIOBROWSER = 'RadioBrowser';
INI_MYSTATIONS = 'MyStations';
INI_BOOKMARK = 'Bookmark';
INI_WEBSERVER = 'WebServer';
INI_DNSSERVER = 'DNSServer';

HTTP_HEADER_ACCEPT = 'Accept';
Expand All @@ -52,14 +54,15 @@ interface
HTTP_CODE_FOUND = 302;
HTTP_CODE_NOT_FOUND = 404;

DEFAULT_STRING = 'default';
var
MyIPAddress: string = '0.0.0.0';
LogType: TLogType = ltInfo;
MyIPAddress: string = DEFAULT_STRING;
LogType: TLogType = ltError;
MyAppPath: string;
UseSSL: boolean = True;

procedure Logging(ALogType: TLogType; ALogMessage: string);
function GetLocalIP(ADefaultIP: string='0.0.0.0'): string;
function GetLocalIP(ADefaultIP: string): string;
function StripHttps(URL: string):string;

implementation
Expand All @@ -70,43 +73,68 @@ procedure Logging(ALogType: TLogType; ALogMessage: string);
Writeln(DateTimeToStr(Now)+' : '+LOG_TYPE_MSG[ALogType]+' : '+ALogMessage+'.');
end;

function GetLocalIP(ADefaultIP: string='0.0.0.0'): string;
function GetLocalIP(ADefaultIP: string): string;
var
IPList: TIdStackLocalAddressList;
i: integer = 0;

function IsIP_v4(AIP_v4: string): Boolean;
var
i: LongInt;

function TryStrToByte(const s: String; out i: LongInt): Boolean;
begin
Result:=((TryStrToInt(s,i)) and (i>=0) and (i<=255));
end;

begin
Result:=((Length(AIP_v4.Split(['.']))=4)
and (TryStrToByte(AIP_v4.Split(['.'])[0],i))
and (TryStrToByte(AIP_v4.Split(['.'])[1],i))
and (TryStrToByte(AIP_v4.Split(['.'])[2],i))
and (TryStrToByte(AIP_v4.Split(['.'])[3],i)));
end;
begin
Result:='';
try
IPList := TIdStackLocalAddressList.Create;
try
TIdStack.IncUsage;
// Due to the filtering out of loopback interface IP addresses in the GetLocalAddressList procedure of the Indy library, we add it manually at this moment.
// For more information look at: https://github.com/IndySockets/Indy/issues/494
// Be careful! As you can see below, the given loopback IP address is not verified with the list of available IP addresses.
if IsIP_v4(ADefaultIP) and (ADefaultIP.Split(['.'])[0]='127') then
Result:=ADefaultIP
else
begin
Result:='';
try
GStack.GetLocalAddressList(IPList);
finally
TIdStack.DecUsage;
IPList := TIdStackLocalAddressList.Create;
try
TIdStack.IncUsage;
try
GStack.GetLocalAddressList(IPList);
finally
TIdStack.DecUsage;
end;

if IPList.Count > 0 then
while (i<=IPList.Count-1) and (Result<>ADefaultIP) do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
if Result='' then
Result:=IPList[i].IPAddress;
if IPList[i].IPAddress = ADefaultIP then
Result:=ADefaultIP;
end;
i:=i+1;
end
else
Logging(ltError, 'No entries on IP List');
finally
IPList.Free;
end;
except
On E: Exception do
Logging(ltError, 'IP error: ' + E.message);
end;

if IPList.Count > 0 then
while (i<=IPList.Count-1) and (Result<>ADefaultIP) do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
if Result='' then
Result:=IPList[i].IPAddress;
if IPList[i].IPAddress = ADefaultIP then
Result:=ADefaultIP;
end;
i:=i+1;
end
else
Logging(ltError, 'No entries on IP List.');
finally
IPList.Free;
end;
except
On E: Exception do
Logging(ltError, 'IP error: ' + E.message);
end;
end;

function StripHttps(URL: string):string;
Expand Down
3 changes: 2 additions & 1 deletion src/dnsserver.pas
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ TIdDNSServerProxy = class(TObject)

var
IdDNSServerProxy: TIdDNSServerProxy;
DNSServerIPAddress: string;
DNSServerPort: integer = 53;
DNSServerEnabled: boolean = True;
DNSServers: string = '8.8.8.8,9.9.9.9';
Expand Down Expand Up @@ -57,7 +58,7 @@ function StartDNSServer:boolean;
end;
with IdDNSServerProxy.IdDNSServer.UDPTunnel.Bindings.Add do
begin
IP:=MyIPAddress;
IP:=DNSServerIPAddress;
IPVersion:=Id_IPv4;
end;
IdDNSServerProxy.IdDNSServer.Active:=True;
Expand Down
11 changes: 6 additions & 5 deletions src/httpserver.pas
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ interface
ICON_CACHE_PATH = 'cache';

var
WebServerIPAddress: string;
WebServerPort: integer = 80;
IconSize: integer = 200;
IconCache: boolean = False;
Expand Down Expand Up @@ -780,9 +781,9 @@ function SetVTunerStation(LStation: TStation; AReq: TRequest): TVTunerStation;
Name:=Station.MSName;
Description:='My favorite "'+Station.MSName+'"';
URL:=StripHttps(Station.MSURL);
Icon:=PATH_HTTP+AReq.Host+'/'+PATH_ROOT+'/'+PATH_ICON+'?'+PATH_PARAM_ID+'='+Station.MSID;
Icon:=PATH_HTTP+MyIPAddress+'/'+PATH_ROOT+'/'+PATH_ICON+'?'+PATH_PARAM_ID+'='+Station.MSID;
Genre:=Category;
Bookmark:=PATH_HTTP+AReq.Host+'/'+PATH_SETUPAPP+'/'+PATH_FAVXML_ASP+'?'+PATH_PARAM_ID+'='+Station.MSID+'&'+PATH_FAVACTION+'='+PATH_FAVACTION_ADD;
Bookmark:=PATH_HTTP+MyIPAddress+'/'+PATH_SETUPAPP+'/'+PATH_FAVXML_ASP+'?'+PATH_PARAM_ID+'='+Station.MSID+'&'+PATH_FAVACTION+'='+PATH_FAVACTION_ADD;
end;
end;

Expand All @@ -799,8 +800,8 @@ function SetVTunerStation(LRBStation: TRBStation; AReq: TRequest): TVTunerStatio
Location:=RBSCountry;
Mime:=RBSCodec.ToUpper;
Bitrate:=RBSBitrate;
Icon:=PATH_HTTP+AReq.Host+'/'+PATH_ROOT+'/'+PATH_ICON+'?'+PATH_PARAM_ID+'='+UID;
Bookmark:=PATH_HTTP+AReq.Host+'/'+PATH_SETUPAPP+'/'+PATH_FAVXML_ASP+'?'+PATH_PARAM_ID+'='+UID+'&'+PATH_FAVACTION+'='+PATH_FAVACTION_ADD;
Icon:=PATH_HTTP+MyIPAddress+'/'+PATH_ROOT+'/'+PATH_ICON+'?'+PATH_PARAM_ID+'='+UID;
Bookmark:=PATH_HTTP+MyIPAddress+'/'+PATH_SETUPAPP+'/'+PATH_FAVXML_ASP+'?'+PATH_PARAM_ID+'='+UID+'&'+PATH_FAVACTION+'='+PATH_FAVACTION_ADD;
end;
end;

Expand All @@ -810,7 +811,7 @@ function SetVTunerDirectory(ATitle, ADestination: string; AItemCount: integer):
with Result do
begin
Title:=ATitle;
Destination:=PATH_HTTP+MyIPAddress+':'+WebServerPort.ToString+'/'+ADestination;
Destination:=PATH_HTTP+MyIPAddress+'/'+ADestination;
ItemCount:=AItemCount;
end;
end;
Expand Down
25 changes: 16 additions & 9 deletions src/ytuner.pas
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ procedure ReadINIConfiguration;
begin
with TIniFile.Create(MyAppPath+'ytuner.ini') do
try
MyIPAddress:=GetLocalIP(ReadString(INI_CONFIGURATION,'IPAddress',MyIPAddress));
WebServerPort:=ReadInteger(INI_CONFIGURATION,'WebServerPort',WebServerPort);
UseSSL:=ReadBool(INI_CONFIGURATION,'UseSSL',True);
try
LogType:=TLogType(ReadInteger(INI_CONFIGURATION,'MessageInfoLevel',1));
LogType:=TLogType(ReadInteger(INI_CONFIGURATION,'MessageInfoLevel',3));
except
LogType:=ltInfo;
LogType:=ltError;
end;
if ReadString(INI_CONFIGURATION,'INIVersion','')<>INI_VERSION then
Logging(ltWarning, 'You are running out of INI file or your ytuner.ini file is outdated! Some features may not work properly! Check https://github.com/coffeegreg/YTuner for the correct INI file for your version of YTuner');
MyIPAddress:=GetLocalIP(ReadString(INI_CONFIGURATION,'IPAddress',MyIPAddress));
UseSSL:=ReadBool(INI_CONFIGURATION,'UseSSL',True);
IconSize:=ReadInteger(INI_CONFIGURATION,'IconSize',IconSize);
IconCache:=ReadBool(INI_CONFIGURATION,'IconCache',True);
LToken:=ReadString(INI_CONFIGURATION,'MyToken',MyToken);
Expand All @@ -80,7 +81,11 @@ procedure ReadINIConfiguration;
CommonBookmark:=ReadBool(INI_BOOKMARK,'CommonBookmark',False);
BookmarkStationsLimit:=ReadInteger(INI_BOOKMARK,'BookmarkStationsLimit',BookmarkStationsLimit);

WebServerIPAddress:=GetLocalIP(ReadString(INI_WEBSERVER,'WebServerIPAddress',MyIPAddress).Replace(DEFAULT_STRING,MyIPAddress));
WebServerPort:=ReadInteger(INI_WEBSERVER,'WebServerPort',WebServerPort);

DNSServerEnabled:=ReadBool(INI_DNSSERVER,'Enable',True);
DNSServerIPAddress:=GetLocalIP(ReadString(INI_DNSSERVER,'DNSServerIPAddress',MyIPAddress).Replace(DEFAULT_STRING,MyIPAddress));
DNSServerPort:=ReadInteger(INI_DNSSERVER,'DNSServerPort',DNSServerPort);
InterceptDNs:=ReadString(INI_DNSSERVER,'InterceptDNs',InterceptDNs);
DNSServers:=ReadString(INI_DNSSERVER,'DNSServers',DNSServers);
Expand All @@ -101,8 +106,8 @@ procedure ReadINIConfiguration;
{$ENDIF DEBUG}

MyAppPath:=Application.Location;
Writeln(APP_NAME+' v'+APP_VERSION+' '+APP_COPYRIGHT);
ReadINIConfiguration;
writeln(APP_NAME+' '+APP_VERSION+' '+APP_COPYRIGHT);
Logging(ltInfo, 'Starting services..');
if UseSSL then InitSSLInterface;
if RadioBrowserEnabled then
Expand All @@ -127,15 +132,17 @@ procedure ReadINIConfiguration;
end;

if DNSServerEnabled and StartDNSServer then
Logging(ltInfo, 'DNS server listening on: '+MyIPAddress+':'+DNSServerPort.ToString);
Logging(ltInfo, 'DNS server listening on: '+DNSServerIPAddress+':'+DNSServerPort.ToString);

Application.Address:=MyIPAddress;
Application.Address:=WebServerIPAddress;
Application.Port:=WebServerPort;
Application.LookupHostNames:=False;
RegisterServerRoutes;
Application.Threaded:=True;
Application.Initialize;
Logging(ltInfo, 'Web server listening on: '+MyIPAddress+':'+WebServerPort.ToString);
Logging(ltInfo, 'Web server listening on: '+WebServerIPAddress+':'+WebServerPort.ToString);
if MyIPAddress <> WebServerIPAddress then
Logging(ltInfo, 'AVRs HTTP requests IP target: '+MyIPAddress);
Application.Run;
end.

0 comments on commit f8e9da3

Please sign in to comment.