From 18e6cd429ae026d87259eb05c45bf049616235dc Mon Sep 17 00:00:00 2001
From: SenorSmartyPants
Date: Sat, 22 Jun 2019 16:11:47 -0500
Subject: [PATCH 01/36] Update TVDB provider to search based on series display
order
---
.../TV/TheTVDB/TvDbClientManager.cs | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
index 1d1fbd00f1..9fd72b65c1 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
@@ -158,8 +158,20 @@ namespace MediaBrowser.Providers.TV.TheTVDB
// Prefer SxE over premiere date as it is more robust
if (searchInfo.IndexNumber.HasValue && searchInfo.ParentIndexNumber.HasValue)
{
- episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
- episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
+ switch (searchInfo.SeriesDisplayOrder)
+ {
+ case "dvd":
+ episodeQuery.DvdEpisode = searchInfo.IndexNumber.Value;
+ episodeQuery.DvdSeason = searchInfo.ParentIndexNumber.Value;
+ break;
+ case "absolute":
+ episodeQuery.AbsoluteNumber = searchInfo.IndexNumber.Value;
+ break;
+ default: //aired order
+ episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
+ episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
+ break;
+ }
}
else if (searchInfo.PremiereDate.HasValue)
{
From 0f897589ed6349bb3c88919b06861daa80aec1be Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Tue, 21 May 2019 19:28:34 +0200
Subject: [PATCH 02/36] Streamline authentication proccess
---
.../Cryptography/CryptographyProvider.cs | 88 +++---
.../Library/DefaultAuthenticationProvider.cs | 115 ++++----
.../Library/DefaultPasswordResetProvider.cs | 257 +++++++++---------
.../Library/InvalidAuthProvider.cs | 11 +-
.../Library/UserManager.cs | 49 ++--
MediaBrowser.Api/LiveTv/LiveTvService.cs | 19 --
.../Authentication/AuthenticationException.cs | 28 ++
.../Authentication/IAuthenticationProvider.cs | 3 +-
.../Authentication/IPasswordResetProvider.cs | 1 +
.../Cryptography/ICryptoProvider.cs | 6 +-
.../Cryptography/PasswordHash.cs | 164 ++++++-----
11 files changed, 372 insertions(+), 369 deletions(-)
create mode 100644 MediaBrowser.Controller/Authentication/AuthenticationException.cs
diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
index 6d7193ce20..f726dae2ee 100644
--- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
+++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Model.Cryptography;
namespace Emby.Server.Implementations.Cryptography
{
- public class CryptographyProvider : ICryptoProvider
+ public class CryptographyProvider : ICryptoProvider, IDisposable
{
private static readonly HashSet _supportedHashMethods = new HashSet()
{
@@ -28,26 +28,28 @@ namespace Emby.Server.Implementations.Cryptography
"System.Security.Cryptography.SHA512"
};
- public string DefaultHashMethod => "PBKDF2";
-
private RandomNumberGenerator _randomNumberGenerator;
private const int _defaultIterations = 1000;
+ private bool _disposed = false;
+
public CryptographyProvider()
{
- //FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
- //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
- //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
- //Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1
+ // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
+ // Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
+ // there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
+ // Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1
_randomNumberGenerator = RandomNumberGenerator.Create();
}
- public Guid GetMD5(string str)
- {
- return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
- }
+ public string DefaultHashMethod => "PBKDF2";
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
+ public Guid GetMD5(string str)
+ => new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
+
+ [Obsolete("Use System.Security.Cryptography.SHA1 directly")]
public byte[] ComputeSHA1(byte[] bytes)
{
using (var provider = SHA1.Create())
@@ -56,6 +58,7 @@ namespace Emby.Server.Implementations.Cryptography
}
}
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
public byte[] ComputeMD5(Stream str)
{
using (var provider = MD5.Create())
@@ -64,6 +67,7 @@ namespace Emby.Server.Implementations.Cryptography
}
}
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
public byte[] ComputeMD5(byte[] bytes)
{
using (var provider = MD5.Create())
@@ -73,9 +77,7 @@ namespace Emby.Server.Implementations.Cryptography
}
public IEnumerable GetSupportedHashMethods()
- {
- return _supportedHashMethods;
- }
+ => _supportedHashMethods;
private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations)
{
@@ -93,14 +95,10 @@ namespace Emby.Server.Implementations.Cryptography
}
public byte[] ComputeHash(string hashMethod, byte[] bytes)
- {
- return ComputeHash(hashMethod, bytes, Array.Empty());
- }
+ => ComputeHash(hashMethod, bytes, Array.Empty());
public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
- {
- return ComputeHash(DefaultHashMethod, bytes);
- }
+ => ComputeHash(DefaultHashMethod, bytes);
public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt)
{
@@ -125,37 +123,27 @@ namespace Emby.Server.Implementations.Cryptography
}
}
}
- else
- {
- throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
- }
+
+ throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
+
}
public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
- {
- return PBKDF2(DefaultHashMethod, bytes, salt, _defaultIterations);
- }
+ => PBKDF2(DefaultHashMethod, bytes, salt, _defaultIterations);
public byte[] ComputeHash(PasswordHash hash)
{
int iterations = _defaultIterations;
if (!hash.Parameters.ContainsKey("iterations"))
{
- hash.Parameters.Add("iterations", _defaultIterations.ToString(CultureInfo.InvariantCulture));
+ hash.Parameters.Add("iterations", iterations.ToString(CultureInfo.InvariantCulture));
}
- else
+ else if (!int.TryParse(hash.Parameters["iterations"], out iterations))
{
- try
- {
- iterations = int.Parse(hash.Parameters["iterations"]);
- }
- catch (Exception e)
- {
- throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}", e);
- }
+ throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}");
}
- return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes, iterations);
+ return PBKDF2(hash.Id, hash.Hash, hash.Salt, iterations);
}
public byte[] GenerateSalt()
@@ -164,5 +152,29 @@ namespace Emby.Server.Implementations.Cryptography
_randomNumberGenerator.GetBytes(salt);
return salt;
}
+
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _randomNumberGenerator.Dispose();
+ }
+
+ _randomNumberGenerator = null;
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
index fe09b07ff6..b07244fda1 100644
--- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
+++ b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
@@ -11,9 +11,9 @@ namespace Emby.Server.Implementations.Library
public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
{
private readonly ICryptoProvider _cryptographyProvider;
- public DefaultAuthenticationProvider(ICryptoProvider crypto)
+ public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider)
{
- _cryptographyProvider = crypto;
+ _cryptographyProvider = cryptographyProvider;
}
public string Name => "Default";
@@ -28,17 +28,17 @@ namespace Emby.Server.Implementations.Library
throw new NotImplementedException();
}
- // This is the verson that we need to use for local users. Because reasons.
+ // This is the version that we need to use for local users. Because reasons.
public Task Authenticate(string username, string password, User resolvedUser)
{
bool success = false;
if (resolvedUser == null)
{
- throw new Exception("Invalid username or password");
+ throw new ArgumentNullException(nameof(resolvedUser));
}
// As long as jellyfin supports passwordless users, we need this little block here to accomodate
- if (IsPasswordEmpty(resolvedUser, password))
+ if (!HasPassword(resolvedUser) && string.IsNullOrEmpty(password))
{
return Task.FromResult(new ProviderAuthenticationResult
{
@@ -50,37 +50,24 @@ namespace Emby.Server.Implementations.Library
byte[] passwordbytes = Encoding.UTF8.GetBytes(password);
PasswordHash readyHash = new PasswordHash(resolvedUser.Password);
- byte[] calculatedHash;
- string calculatedHashString;
- if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
+ if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id)
+ || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
{
- if (string.IsNullOrEmpty(readyHash.Salt))
- {
- calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes);
- calculatedHashString = BitConverter.ToString(calculatedHash).Replace("-", string.Empty);
- }
- else
- {
- calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.SaltBytes);
- calculatedHashString = BitConverter.ToString(calculatedHash).Replace("-", string.Empty);
- }
+ byte[] calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.Salt);
- if (calculatedHashString == readyHash.Hash)
+ if (calculatedHash.SequenceEqual(readyHash.Hash))
{
success = true;
- // throw new Exception("Invalid username or password");
}
}
else
{
- throw new Exception(string.Format($"Requested crypto method not available in provider: {readyHash.Id}"));
+ throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}");
}
- // var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase);
-
if (!success)
{
- throw new Exception("Invalid username or password");
+ throw new AuthenticationException("Invalid username or password");
}
return Task.FromResult(new ProviderAuthenticationResult
@@ -98,29 +85,22 @@ namespace Emby.Server.Implementations.Library
return;
}
- if (!user.Password.Contains("$"))
+ if (user.Password.IndexOf('$') == -1)
{
string hash = user.Password;
user.Password = string.Format("$SHA1${0}", hash);
}
- if (user.EasyPassword != null && !user.EasyPassword.Contains("$"))
+ if (user.EasyPassword != null
+ && user.EasyPassword.IndexOf('$') == -1)
{
string hash = user.EasyPassword;
user.EasyPassword = string.Format("$SHA1${0}", hash);
}
}
- public Task HasPassword(User user)
- {
- var hasConfiguredPassword = !IsPasswordEmpty(user, GetPasswordHash(user));
- return Task.FromResult(hasConfiguredPassword);
- }
-
- private bool IsPasswordEmpty(User user, string password)
- {
- return (string.IsNullOrEmpty(user.Password) && string.IsNullOrEmpty(password));
- }
+ public bool HasPassword(User user)
+ => !string.IsNullOrEmpty(user.Password);
public Task ChangePassword(User user, string newPassword)
{
@@ -129,30 +109,24 @@ namespace Emby.Server.Implementations.Library
if (string.IsNullOrEmpty(user.Password))
{
PasswordHash newPasswordHash = new PasswordHash(_cryptographyProvider);
- newPasswordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- newPasswordHash.Salt = PasswordHash.ConvertToByteString(newPasswordHash.SaltBytes);
+ newPasswordHash.Salt = _cryptographyProvider.GenerateSalt();
newPasswordHash.Id = _cryptographyProvider.DefaultHashMethod;
- newPasswordHash.Hash = GetHashedStringChangeAuth(newPassword, newPasswordHash);
+ newPasswordHash.Hash = GetHashedChangeAuth(newPassword, newPasswordHash);
user.Password = newPasswordHash.ToString();
return Task.CompletedTask;
}
PasswordHash passwordHash = new PasswordHash(user.Password);
- if (passwordHash.Id == "SHA1" && string.IsNullOrEmpty(passwordHash.Salt))
+ if (passwordHash.Id == "SHA1"
+ && passwordHash.Salt.Length == 0)
{
- passwordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- passwordHash.Salt = PasswordHash.ConvertToByteString(passwordHash.SaltBytes);
+ passwordHash.Salt = _cryptographyProvider.GenerateSalt();
passwordHash.Id = _cryptographyProvider.DefaultHashMethod;
- passwordHash.Hash = GetHashedStringChangeAuth(newPassword, passwordHash);
+ passwordHash.Hash = GetHashedChangeAuth(newPassword, passwordHash);
}
else if (newPassword != null)
{
- passwordHash.Hash = GetHashedString(user, newPassword);
- }
-
- if (string.IsNullOrWhiteSpace(passwordHash.Hash))
- {
- throw new ArgumentNullException(nameof(passwordHash.Hash));
+ passwordHash.Hash = GetHashed(user, newPassword);
}
user.Password = passwordHash.ToString();
@@ -160,11 +134,6 @@ namespace Emby.Server.Implementations.Library
return Task.CompletedTask;
}
- public string GetPasswordHash(User user)
- {
- return user.Password;
- }
-
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
ConvertPasswordFormat(user);
@@ -190,13 +159,13 @@ namespace Emby.Server.Implementations.Library
return string.IsNullOrEmpty(user.EasyPassword)
? null
- : (new PasswordHash(user.EasyPassword)).Hash;
+ : PasswordHash.ConvertToByteString(new PasswordHash(user.EasyPassword).Hash);
}
- public string GetHashedStringChangeAuth(string newPassword, PasswordHash passwordHash)
+ internal byte[] GetHashedChangeAuth(string newPassword, PasswordHash passwordHash)
{
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(newPassword);
- return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
+ passwordHash.Hash = Encoding.UTF8.GetBytes(newPassword);
+ return _cryptographyProvider.ComputeHash(passwordHash);
}
///
@@ -215,10 +184,10 @@ namespace Emby.Server.Implementations.Library
passwordHash = new PasswordHash(user.Password);
}
- if (passwordHash.SaltBytes != null)
+ if (passwordHash.Salt != null)
{
// the password is modern format with PBKDF and we should take advantage of that
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(str);
+ passwordHash.Hash = Encoding.UTF8.GetBytes(str);
return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
}
else
@@ -227,5 +196,31 @@ namespace Emby.Server.Implementations.Library
return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str)));
}
}
+
+ public byte[] GetHashed(User user, string str)
+ {
+ PasswordHash passwordHash;
+ if (string.IsNullOrEmpty(user.Password))
+ {
+ passwordHash = new PasswordHash(_cryptographyProvider);
+ }
+ else
+ {
+ ConvertPasswordFormat(user);
+ passwordHash = new PasswordHash(user.Password);
+ }
+
+ if (passwordHash.Salt != null)
+ {
+ // the password is modern format with PBKDF and we should take advantage of that
+ passwordHash.Hash = Encoding.UTF8.GetBytes(str);
+ return _cryptographyProvider.ComputeHash(passwordHash);
+ }
+ else
+ {
+ // the password has no salt and should be called with the older method for safety
+ return _cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str));
+ }
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
index e218749d90..c7044820c7 100644
--- a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
+++ b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
@@ -1,132 +1,125 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Users;
-
-namespace Emby.Server.Implementations.Library
-{
- public class DefaultPasswordResetProvider : IPasswordResetProvider
- {
- public string Name => "Default Password Reset Provider";
-
- public bool IsEnabled => true;
-
- private readonly string _passwordResetFileBase;
- private readonly string _passwordResetFileBaseDir;
- private readonly string _passwordResetFileBaseName = "passwordreset";
-
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IUserManager _userManager;
- private readonly ICryptoProvider _crypto;
-
- public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IUserManager userManager, ICryptoProvider cryptoProvider)
- {
- _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
- _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, _passwordResetFileBaseName);
- _jsonSerializer = jsonSerializer;
- _userManager = userManager;
- _crypto = cryptoProvider;
- }
-
- public async Task RedeemPasswordResetPin(string pin)
- {
- SerializablePasswordReset spr;
- HashSet usersreset = new HashSet();
- foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{_passwordResetFileBaseName}*"))
- {
- using (var str = File.OpenRead(resetfile))
- {
- spr = await _jsonSerializer.DeserializeFromStreamAsync(str).ConfigureAwait(false);
- }
-
- if (spr.ExpirationDate < DateTime.Now)
- {
- File.Delete(resetfile);
- }
- else if (spr.Pin.Replace("-", "").Equals(pin.Replace("-", ""), StringComparison.InvariantCultureIgnoreCase))
- {
- var resetUser = _userManager.GetUserByName(spr.UserName);
- if (resetUser == null)
- {
- throw new Exception($"User with a username of {spr.UserName} not found");
- }
-
- await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
- usersreset.Add(resetUser.Name);
- File.Delete(resetfile);
- }
- }
-
- if (usersreset.Count < 1)
- {
- throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
- }
- else
- {
- return new PinRedeemResult
- {
- Success = true,
- UsersReset = usersreset.ToArray()
- };
- }
- }
-
- public async Task StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork)
- {
- string pin = string.Empty;
- using (var cryptoRandom = System.Security.Cryptography.RandomNumberGenerator.Create())
- {
- byte[] bytes = new byte[4];
- cryptoRandom.GetBytes(bytes);
- pin = BitConverter.ToString(bytes);
- }
-
- DateTime expireTime = DateTime.Now.AddMinutes(30);
- string filePath = _passwordResetFileBase + user.InternalId + ".json";
- SerializablePasswordReset spr = new SerializablePasswordReset
- {
- ExpirationDate = expireTime,
- Pin = pin,
- PinFile = filePath,
- UserName = user.Name
- };
-
- try
- {
- using (FileStream fileStream = File.OpenWrite(filePath))
- {
- _jsonSerializer.SerializeToStream(spr, fileStream);
- await fileStream.FlushAsync().ConfigureAwait(false);
- }
- }
- catch (Exception e)
- {
- throw new Exception($"Error serializing or writing password reset for {user.Name} to location: {filePath}", e);
- }
-
- return new ForgotPasswordResult
- {
- Action = ForgotPasswordAction.PinCode,
- PinExpirationDate = expireTime,
- PinFile = filePath
- };
- }
-
- private class SerializablePasswordReset : PasswordPinCreationResult
- {
- public string Pin { get; set; }
-
- public string UserName { get; set; }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Authentication;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Cryptography;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Users;
+
+namespace Emby.Server.Implementations.Library
+{
+ public class DefaultPasswordResetProvider : IPasswordResetProvider
+ {
+ public string Name => "Default Password Reset Provider";
+
+ public bool IsEnabled => true;
+
+ private readonly string _passwordResetFileBase;
+ private readonly string _passwordResetFileBaseDir;
+ private readonly string _passwordResetFileBaseName = "passwordreset";
+
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly IUserManager _userManager;
+ private readonly ICryptoProvider _crypto;
+
+ public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IUserManager userManager, ICryptoProvider cryptoProvider)
+ {
+ _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
+ _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, _passwordResetFileBaseName);
+ _jsonSerializer = jsonSerializer;
+ _userManager = userManager;
+ _crypto = cryptoProvider;
+ }
+
+ public async Task RedeemPasswordResetPin(string pin)
+ {
+ SerializablePasswordReset spr;
+ HashSet usersreset = new HashSet();
+ foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{_passwordResetFileBaseName}*"))
+ {
+ using (var str = File.OpenRead(resetfile))
+ {
+ spr = await _jsonSerializer.DeserializeFromStreamAsync(str).ConfigureAwait(false);
+ }
+
+ if (spr.ExpirationDate < DateTime.Now)
+ {
+ File.Delete(resetfile);
+ }
+ else if (spr.Pin.Replace("-", "").Equals(pin.Replace("-", ""), StringComparison.InvariantCultureIgnoreCase))
+ {
+ var resetUser = _userManager.GetUserByName(spr.UserName);
+ if (resetUser == null)
+ {
+ throw new Exception($"User with a username of {spr.UserName} not found");
+ }
+
+ await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
+ usersreset.Add(resetUser.Name);
+ File.Delete(resetfile);
+ }
+ }
+
+ if (usersreset.Count < 1)
+ {
+ throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
+ }
+ else
+ {
+ return new PinRedeemResult
+ {
+ Success = true,
+ UsersReset = usersreset.ToArray()
+ };
+ }
+ }
+
+ public async Task StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork)
+ {
+ string pin = string.Empty;
+ using (var cryptoRandom = System.Security.Cryptography.RandomNumberGenerator.Create())
+ {
+ byte[] bytes = new byte[4];
+ cryptoRandom.GetBytes(bytes);
+ pin = BitConverter.ToString(bytes);
+ }
+
+ DateTime expireTime = DateTime.Now.AddMinutes(30);
+ string filePath = _passwordResetFileBase + user.InternalId + ".json";
+ SerializablePasswordReset spr = new SerializablePasswordReset
+ {
+ ExpirationDate = expireTime,
+ Pin = pin,
+ PinFile = filePath,
+ UserName = user.Name
+ };
+
+ using (FileStream fileStream = File.OpenWrite(filePath))
+ {
+ _jsonSerializer.SerializeToStream(spr, fileStream);
+ await fileStream.FlushAsync().ConfigureAwait(false);
+ }
+
+ return new ForgotPasswordResult
+ {
+ Action = ForgotPasswordAction.PinCode,
+ PinExpirationDate = expireTime,
+ PinFile = filePath
+ };
+ }
+
+ private class SerializablePasswordReset : PasswordPinCreationResult
+ {
+ public string Pin { get; set; }
+
+ public string UserName { get; set; }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
index 25d2331373..6956369dc1 100644
--- a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
+++ b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Entities;
@@ -16,12 +13,12 @@ namespace Emby.Server.Implementations.Library
public Task Authenticate(string username, string password)
{
- throw new SecurityException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
+ throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
}
- public Task HasPassword(User user)
+ public bool HasPassword(User user)
{
- return Task.FromResult(true);
+ return true;
}
public Task ChangePassword(User user, string newPassword)
@@ -31,7 +28,7 @@ namespace Emby.Server.Implementations.Library
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
- // Nothing here
+ // Nothing here
}
public string GetPasswordHash(User user)
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 1701ced426..c8c8a108d5 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -266,6 +266,7 @@ namespace Emby.Server.Implementations.Library
builder.Append(c);
}
}
+
return builder.ToString();
}
@@ -286,17 +287,17 @@ namespace Emby.Server.Implementations.Library
if (user != null)
{
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.Item1;
- updatedUsername = authResult.Item2;
- success = authResult.Item3;
+ authenticationProvider = authResult.authenticationProvider;
+ updatedUsername = authResult.username;
+ success = authResult.success;
}
else
{
// user is null
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, null, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.Item1;
- updatedUsername = authResult.Item2;
- success = authResult.Item3;
+ authenticationProvider = authResult.authenticationProvider;
+ updatedUsername = authResult.username;
+ success = authResult.success;
if (success && authenticationProvider != null && !(authenticationProvider is DefaultAuthenticationProvider))
{
@@ -331,22 +332,25 @@ namespace Emby.Server.Implementations.Library
if (user == null)
{
- throw new SecurityException("Invalid username or password entered.");
+ throw new AuthenticationException("Invalid username or password entered.");
}
if (user.Policy.IsDisabled)
{
- throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
+ throw new AuthenticationException(string.Format(
+ CultureInfo.InvariantCulture,
+ "The {0} account is currently disabled. Please consult with your administrator.",
+ user.Name));
}
if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint))
{
- throw new SecurityException("Forbidden.");
+ throw new AuthenticationException("Forbidden.");
}
if (!user.IsParentalScheduleAllowed())
{
- throw new SecurityException("User is not allowed access at this time.");
+ throw new AuthenticationException("User is not allowed access at this time.");
}
// Update LastActivityDate and LastLoginDate, then save
@@ -357,6 +361,7 @@ namespace Emby.Server.Implementations.Library
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
UpdateUser(user);
}
+
UpdateInvalidLoginAttemptCount(user, 0);
}
else
@@ -429,7 +434,7 @@ namespace Emby.Server.Implementations.Library
return providers;
}
- private async Task> AuthenticateWithProvider(IAuthenticationProvider provider, string username, string password, User resolvedUser)
+ private async Task<(string username, bool success)> AuthenticateWithProvider(IAuthenticationProvider provider, string username, string password, User resolvedUser)
{
try
{
@@ -444,23 +449,23 @@ namespace Emby.Server.Implementations.Library
authenticationResult = await provider.Authenticate(username, password).ConfigureAwait(false);
}
- if(authenticationResult.Username != username)
+ if (authenticationResult.Username != username)
{
_logger.LogDebug("Authentication provider provided updated username {1}", authenticationResult.Username);
username = authenticationResult.Username;
}
- return new Tuple(username, true);
+ return (username, true);
}
- catch (Exception ex)
+ catch (AuthenticationException ex)
{
- _logger.LogError(ex, "Error authenticating with provider {provider}", provider.Name);
+ _logger.LogError(ex, "Error authenticating with provider {Provider}", provider.Name);
- return new Tuple(username, false);
+ return (username, false);
}
}
- private async Task> AuthenticateLocalUser(string username, string password, string hashedPassword, User user, string remoteEndPoint)
+ private async Task<(IAuthenticationProvider authenticationProvider, string username, bool success)> AuthenticateLocalUser(string username, string password, string hashedPassword, User user, string remoteEndPoint)
{
string updatedUsername = null;
bool success = false;
@@ -475,15 +480,15 @@ namespace Emby.Server.Implementations.Library
if (password == null)
{
// legacy
- success = string.Equals(GetAuthenticationProvider(user).GetPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
+ success = string.Equals(user.Password, hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
}
else
{
foreach (var provider in GetAuthenticationProviders(user))
{
var providerAuthResult = await AuthenticateWithProvider(provider, username, password, user).ConfigureAwait(false);
- updatedUsername = providerAuthResult.Item1;
- success = providerAuthResult.Item2;
+ updatedUsername = providerAuthResult.username;
+ success = providerAuthResult.success;
if (success)
{
@@ -510,7 +515,7 @@ namespace Emby.Server.Implementations.Library
}
}
- return new Tuple(authenticationProvider, username, success);
+ return (authenticationProvider, username, success);
}
private void UpdateInvalidLoginAttemptCount(User user, int newValue)
@@ -593,7 +598,7 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(user));
}
- bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result;
+ bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user);
bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetAuthenticationProvider(user).GetEasyPasswordHash(user));
bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index e41ad540ad..8a4d6e2161 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -599,7 +599,6 @@ namespace MediaBrowser.Api.LiveTv
{
public bool ValidateLogin { get; set; }
public bool ValidateListings { get; set; }
- public string Pw { get; set; }
}
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
@@ -867,28 +866,10 @@ namespace MediaBrowser.Api.LiveTv
public async Task
public interface IResolverIgnoreRule
{
+ ///
+ /// Checks whether or not the file should be ignored.
+ ///
+ /// The file information.
+ /// The parent BaseItem.
+ /// True if the file should be ignored.
bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent);
}
}
From 59518ec87e828aff21e5f0f67e82f00fc8fa13ba Mon Sep 17 00:00:00 2001
From: Khinenw
Date: Sun, 14 Jul 2019 23:05:45 +0900
Subject: [PATCH 04/36] Fixed SMI to SRT UTF-16 Encoding bug
---
CONTRIBUTORS.md | 1 +
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 9168dccc8c..c96228f31d 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -27,6 +27,7 @@
- [pjeanjean](https://github.com/pjeanjean)
- [DrPandemic](https://github.com/drpandemic)
- [joern-h](https://github.com/joern-h)
+ - [Khinenw](https://github.com/HelloWorld017)
# Emby Contributors
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 8677b363fb..9ddfb9b01e 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -425,7 +425,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);
- if (!string.IsNullOrEmpty(encodingParam))
+ // FFmpeg automatically convert character encoding when it is UTF-16
+ // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event"
+ if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && (encodingParam == "UTF-16BE" || encodingParam == "UTF-16LE"))
+ {
+ encodingParam = "";
+ }
+ else if (!string.IsNullOrEmpty(encodingParam))
{
encodingParam = " -sub_charenc " + encodingParam;
}
From 67e32a2c4418cb2129f5e71eec71eae904599228 Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Sun, 21 Jul 2019 01:07:39 +0200
Subject: [PATCH 05/36] Add Stale app configuration starting point
Link: https://github.com/apps/stale
---
.github/stale.yml | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 .github/stale.yml
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 0000000000..3e76aa75d1
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,20 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 60
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - regression
+ - security
+ - dotnet-3.0-future
+ - roadmap
+ - future
+# Label to use when marking an issue as stale
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
From ddd1a282ea6398ee26d74321338d0445d0a0c796 Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Sun, 7 Jul 2019 21:03:26 +0200
Subject: [PATCH 06/36] Remove IpAddressInfo and IpEndPointInfo classes
---
Emby.Dlna/Main/DlnaEntryPoint.cs | 3 +-
Emby.Dlna/PlayTo/PlayToManager.cs | 4 +-
.../ApplicationHost.cs | 53 ++--
.../TunerHosts/HdHomerun/HdHomerunHost.cs | 9 +-
.../TunerHosts/HdHomerun/HdHomerunManager.cs | 16 +-
.../HdHomerun/HdHomerunUdpStream.cs | 17 +-
.../Net/SocketFactory.cs | 14 +-
Emby.Server.Implementations/Net/UdpSocket.cs | 30 +--
.../Networking/NetworkManager.cs | 232 ++++--------------
Emby.Server.Implementations/Udp/UdpServer.cs | 15 +-
Jellyfin.Server/Program.cs | 2 +-
MediaBrowser.Common/Net/INetworkManager.cs | 14 +-
.../IServerApplicationHost.cs | 6 +-
MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs | 4 +-
MediaBrowser.Model/Net/ISocket.cs | 5 +-
MediaBrowser.Model/Net/ISocketFactory.cs | 11 +-
MediaBrowser.Model/Net/IpAddressInfo.cs | 38 ---
MediaBrowser.Model/Net/IpEndPointInfo.cs | 29 ---
MediaBrowser.Model/Net/SocketReceiveResult.cs | 6 +-
RSSDP/DeviceAvailableEventArgs.cs | 51 ++--
RSSDP/ISsdpCommunicationsServer.cs | 8 +-
RSSDP/RequestReceivedEventArgs.cs | 12 +-
RSSDP/ResponseReceivedEventArgs.cs | 12 +-
RSSDP/SsdpCommunicationsServer.cs | 52 ++--
RSSDP/SsdpDevice.cs | 3 -
RSSDP/SsdpDeviceLocator.cs | 17 +-
RSSDP/SsdpDevicePublisher.cs | 32 ++-
RSSDP/SsdpRootDevice.cs | 10 +-
28 files changed, 261 insertions(+), 444 deletions(-)
delete mode 100644 MediaBrowser.Model/Net/IpAddressInfo.cs
delete mode 100644 MediaBrowser.Model/Net/IpEndPointInfo.cs
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 5fbe70dedb..206a873e1d 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,4 +1,5 @@
using System;
+using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Emby.Dlna.PlayTo;
@@ -247,7 +248,7 @@ namespace Emby.Dlna.Main
foreach (var address in addresses)
{
- if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
// Not support IPv6 right now
continue;
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 28e70d0469..c0a4418711 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -14,7 +15,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
@@ -172,7 +172,7 @@ namespace Emby.Dlna.PlayTo
_sessionManager.UpdateDeviceName(sessionInfo.Id, deviceName);
string serverAddress;
- if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Any))
+ if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IPAddress.Any) || info.LocalIpAddress.Equals(IPAddress.IPv6Any))
{
serverAddress = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 120aade392..c6ba2326aa 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
@@ -1546,14 +1547,22 @@ namespace Emby.Server.Implementations
return null;
}
- public string GetLocalApiUrl(IpAddressInfo ipAddress)
+ public string GetLocalApiUrl(IPAddress ipAddress)
{
- if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- return GetLocalApiUrl("[" + ipAddress.Address + "]");
+ // Remove the scope id from IPv6 addresses
+ var str = ipAddress.ToString();
+ var index = str.IndexOf('%');
+ if (index != -1)
+ {
+ str = str.Substring(0, index);
+ }
+
+ return GetLocalApiUrl("[" + str + "]");
}
- return GetLocalApiUrl(ipAddress.Address);
+ return GetLocalApiUrl(ipAddress.ToString());
}
public string GetLocalApiUrl(string host)
@@ -1564,19 +1573,28 @@ namespace Emby.Server.Implementations
host,
HttpsPort.ToString(CultureInfo.InvariantCulture));
}
+
return string.Format("http://{0}:{1}",
host,
HttpPort.ToString(CultureInfo.InvariantCulture));
}
- public string GetWanApiUrl(IpAddressInfo ipAddress)
+ public string GetWanApiUrl(IPAddress ipAddress)
{
- if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- return GetWanApiUrl("[" + ipAddress.Address + "]");
+ // Remove the scope id from IPv6 addresses
+ var str = ipAddress.ToString();
+ var index = str.IndexOf('%');
+ if (index != -1)
+ {
+ str = str.Substring(0, index);
+ }
+
+ return GetWanApiUrl("[" + str + "]");
}
- return GetWanApiUrl(ipAddress.Address);
+ return GetWanApiUrl(ipAddress.ToString());
}
public string GetWanApiUrl(string host)
@@ -1587,17 +1605,18 @@ namespace Emby.Server.Implementations
host,
ServerConfigurationManager.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture));
}
+
return string.Format("http://{0}:{1}",
host,
ServerConfigurationManager.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture));
}
- public Task> GetLocalIpAddresses(CancellationToken cancellationToken)
+ public Task> GetLocalIpAddresses(CancellationToken cancellationToken)
{
return GetLocalIpAddressesInternal(true, 0, cancellationToken);
}
- private async Task> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
+ private async Task> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
{
var addresses = ServerConfigurationManager
.Configuration
@@ -1611,13 +1630,13 @@ namespace Emby.Server.Implementations
addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
}
- var resultList = new List();
+ var resultList = new List();
foreach (var address in addresses)
{
if (!allowLoopback)
{
- if (address.Equals(IpAddressInfo.Loopback) || address.Equals(IpAddressInfo.IPv6Loopback))
+ if (address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback))
{
continue;
}
@@ -1638,7 +1657,7 @@ namespace Emby.Server.Implementations
return resultList;
}
- private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
+ private IPAddress NormalizeConfiguredLocalAddress(string address)
{
var index = address.Trim('/').IndexOf('/');
@@ -1647,7 +1666,7 @@ namespace Emby.Server.Implementations
address = address.Substring(index + 1);
}
- if (NetworkManager.TryParseIpAddress(address.Trim('/'), out IpAddressInfo result))
+ if (IPAddress.TryParse(address.Trim('/'), out IPAddress result))
{
return result;
}
@@ -1657,10 +1676,10 @@ namespace Emby.Server.Implementations
private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
- private async Task IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken)
+ private async Task IsIpAddressValidAsync(IPAddress address, CancellationToken cancellationToken)
{
- if (address.Equals(IpAddressInfo.Loopback) ||
- address.Equals(IpAddressInfo.IPv6Loopback))
+ if (address.Equals(IPAddress.Loopback) ||
+ address.Equals(IPAddress.IPv6Loopback))
{
return true;
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 761275f8f3..ed524cae30 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -11,7 +12,6 @@ using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -20,7 +20,6 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
@@ -259,7 +258,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
using (var manager = new HdHomerunManager(_socketFactory, Logger))
{
// Legacy HdHomeruns are IPv4 only
- var ipInfo = _networkManager.ParseIpAddress(uri.Host);
+ var ipInfo = IPAddress.Parse(uri.Host);
for (int i = 0; i < model.TunerCount; ++i)
{
@@ -675,13 +674,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Need a way to set the Receive timeout on the socket otherwise this might never timeout?
try
{
- await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IpEndPointInfo(new IpAddressInfo("255.255.255.255", IpAddressFamily.InterNetwork), 65001), cancellationToken);
+ await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken);
var receiveBuffer = new byte[8192];
while (!cancellationToken.IsCancellationRequested)
{
var response = await udpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
- var deviceIp = response.RemoteEndPoint.IpAddress.Address;
+ var deviceIp = response.RemoteEndPoint.Address.ToString();
// check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte
if (response.ReceivedBytes > 13 && response.Buffer[1] == 3)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 2205c0ecca..6e79441dab 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -89,7 +89,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private uint? _lockkey = null;
private int _activeTuner = -1;
private readonly ISocketFactory _socketFactory;
- private IpAddressInfo _remoteIp;
+ private IPAddress _remoteIp;
private ILogger _logger;
private ISocket _currentTcpSocket;
@@ -114,7 +114,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- public async Task CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+ public async Task CheckTunerAvailability(IPAddress remoteIp, int tuner, CancellationToken cancellationToken)
{
using (var socket = _socketFactory.CreateTcpSocket(remoteIp, HdHomeRunPort))
{
@@ -122,9 +122,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- private static async Task CheckTunerAvailability(ISocket socket, IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+ private static async Task CheckTunerAvailability(ISocket socket, IPAddress remoteIp, int tuner, CancellationToken cancellationToken)
{
- var ipEndPoint = new IpEndPointInfo(remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(remoteIp, HdHomeRunPort);
var lockkeyMsg = CreateGetMessage(tuner, "lockkey");
await socket.SendToAsync(lockkeyMsg, 0, lockkeyMsg.Length, ipEndPoint, cancellationToken);
@@ -137,7 +137,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase);
}
- public async Task StartStreaming(IpAddressInfo remoteIp, IPAddress localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
+ public async Task StartStreaming(IPAddress remoteIp, IPAddress localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
{
_remoteIp = remoteIp;
@@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var lockKeyValue = _lockkey.Value;
- var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(_remoteIp, HdHomeRunPort);
for (int i = 0; i < numTuners; ++i)
{
@@ -217,7 +217,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
foreach (Tuple command in commandList)
{
var channelMsg = CreateSetMessage(_activeTuner, command.Item1, command.Item2, _lockkey);
- await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, new IPEndPoint(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
var response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out string returnVal))
@@ -242,7 +242,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
_logger.LogInformation("HdHomerunManager.ReleaseLockkey {0}", lockKeyValue);
- var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(_remoteIp, HdHomeRunPort);
var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", lockKeyValue);
await tcpClient.SendToAsync(releaseTarget, 0, releaseTarget.Length, ipEndPoint, CancellationToken.None).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 7f426ea31f..ec708cf20f 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -25,7 +25,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly int _numTuners;
private readonly INetworkManager _networkManager;
- public HdHomerunUdpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, MediaBrowser.Model.Net.ISocketFactory socketFactory, INetworkManager networkManager)
+ public HdHomerunUdpStream(
+ MediaSourceInfo mediaSource,
+ TunerHostInfo tunerHostInfo,
+ string originalStreamId,
+ IHdHomerunChannelCommands channelCommands,
+ int numTuners,
+ IFileSystem fileSystem,
+ IHttpClient httpClient,
+ ILogger logger,
+ IServerApplicationPaths appPaths,
+ IServerApplicationHost appHost,
+ MediaBrowser.Model.Net.ISocketFactory socketFactory,
+ INetworkManager networkManager)
: base(mediaSource, tunerHostInfo, fileSystem, logger, appPaths)
{
_appHost = appHost;
@@ -58,7 +70,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Logger.LogInformation("Opening HDHR UDP Live stream from {host}", uri.Host);
var remoteAddress = IPAddress.Parse(uri.Host);
- var embyRemoteAddress = _networkManager.ParseIpAddress(uri.Host);
IPAddress localAddress = null;
using (var tcpSocket = CreateSocket(remoteAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
@@ -81,7 +92,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
// send url to start streaming
- await hdHomerunManager.StartStreaming(embyRemoteAddress, localAddress, localPort, _channelCommands, _numTuners, openCancellationToken).ConfigureAwait(false);
+ await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, openCancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index 492f48abe8..42ffa4e221 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -16,14 +16,14 @@ namespace Emby.Server.Implementations.Net
// but that wasn't really the point so kept to YAGNI principal for now, even if the
// interfaces are a bit ugly, specific and make assumptions.
- public ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort)
+ public ISocket CreateTcpSocket(IPAddress remoteAddress, int remotePort)
{
if (remotePort < 0)
{
throw new ArgumentException("remotePort cannot be less than zero.", nameof(remotePort));
}
- var addressFamily = remoteAddress.AddressFamily == IpAddressFamily.InterNetwork
+ var addressFamily = remoteAddress.AddressFamily == AddressFamily.InterNetwork
? AddressFamily.InterNetwork
: AddressFamily.InterNetworkV6;
@@ -40,7 +40,7 @@ namespace Emby.Server.Implementations.Net
try
{
- return new UdpSocket(retVal, new IpEndPointInfo(remoteAddress, remotePort));
+ return new UdpSocket(retVal, new IPEndPoint(remoteAddress, remotePort));
}
catch
{
@@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Net
/// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
///
/// An implementation of the interface used by RSSDP components to perform acceptSocket operations.
- public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
+ public ISocket CreateSsdpUdpSocket(IPAddress localIpAddress, int localPort)
{
if (localPort < 0)
{
@@ -115,10 +115,8 @@ namespace Emby.Server.Implementations.Net
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
- var localIp = NetworkManager.ToIPAddress(localIpAddress);
-
- retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIp));
- return new UdpSocket(retVal, localPort, localIp);
+ retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIpAddress));
+ return new UdpSocket(retVal, localPort, localIpAddress);
}
catch
{
diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 6c55085c83..2908ee9afd 100644
--- a/Emby.Server.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.Net
public Socket Socket => _socket;
- public IpAddressInfo LocalIPAddress { get; }
+ public IPAddress LocalIPAddress { get; }
private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs()
{
@@ -40,7 +40,7 @@ namespace Emby.Server.Implementations.Net
_socket = socket;
_localPort = localPort;
- LocalIPAddress = NetworkManager.ToIpAddressInfo(ip);
+ LocalIPAddress = ip;
_socket.Bind(new IPEndPoint(ip, _localPort));
@@ -71,7 +71,7 @@ namespace Emby.Server.Implementations.Net
{
Buffer = e.Buffer,
ReceivedBytes = e.BytesTransferred,
- RemoteEndPoint = ToIpEndPointInfo(e.RemoteEndPoint as IPEndPoint),
+ RemoteEndPoint = e.RemoteEndPoint as IPEndPoint,
LocalIPAddress = LocalIPAddress
});
}
@@ -100,12 +100,12 @@ namespace Emby.Server.Implementations.Net
}
}
- public UdpSocket(Socket socket, IpEndPointInfo endPoint)
+ public UdpSocket(Socket socket, IPEndPoint endPoint)
{
if (socket == null) throw new ArgumentNullException(nameof(socket));
_socket = socket;
- _socket.Connect(NetworkManager.ToIPEndPoint(endPoint));
+ _socket.Connect(endPoint);
InitReceiveSocketAsyncEventArgs();
}
@@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.Net
return new SocketReceiveResult
{
ReceivedBytes = receivedBytes,
- RemoteEndPoint = ToIpEndPointInfo((IPEndPoint)remoteEndPoint),
+ RemoteEndPoint = (IPEndPoint)remoteEndPoint,
Buffer = buffer,
LocalIPAddress = LocalIPAddress
};
@@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.Net
return ReceiveAsync(buffer, 0, buffer.Length, cancellationToken);
}
- public Task SendToAsync(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, CancellationToken cancellationToken)
+ public Task SendToAsync(byte[] buffer, int offset, int size, IPEndPoint endPoint, CancellationToken cancellationToken)
{
ThrowIfDisposed();
@@ -227,13 +227,11 @@ namespace Emby.Server.Implementations.Net
return taskCompletion.Task;
}
- public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, AsyncCallback callback, object state)
+ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IPEndPoint endPoint, AsyncCallback callback, object state)
{
ThrowIfDisposed();
- var ipEndPoint = NetworkManager.ToIPEndPoint(endPoint);
-
- return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, ipEndPoint, callback, state);
+ return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, endPoint, callback, state);
}
public int EndSendTo(IAsyncResult result)
@@ -268,15 +266,5 @@ namespace Emby.Server.Implementations.Net
_disposed = true;
}
-
- private static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
-
- return NetworkManager.ToIpEndPointInfo(endpoint);
- }
}
}
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index c102f9eb55..3cacacf075 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -9,55 +9,38 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
-using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
namespace Emby.Server.Implementations.Networking
{
public class NetworkManager : INetworkManager
{
- protected ILogger Logger { get; private set; }
+ private readonly ILogger _logger;
- public event EventHandler NetworkChanged;
- public Func LocalSubnetsFn { get; set; }
+ private IPAddress[] _localIpAddresses;
+ private readonly object _localIpAddressSyncLock = new object();
- public NetworkManager(ILoggerFactory loggerFactory)
+ public NetworkManager(ILogger logger)
{
- Logger = loggerFactory.CreateLogger(nameof(NetworkManager));
+ _logger = logger;
- // In FreeBSD these events cause a crash
- if (OperatingSystem.Id != OperatingSystemId.BSD)
- {
- try
- {
- NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error binding to NetworkAddressChanged event");
- }
-
- try
- {
- NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error binding to NetworkChange_NetworkAvailabilityChanged event");
- }
- }
+ NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged;
+ NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
}
- private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
+ public Func LocalSubnetsFn { get; set; }
+
+ public event EventHandler NetworkChanged;
+
+ private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
- Logger.LogDebug("NetworkAvailabilityChanged");
+ _logger.LogDebug("NetworkAvailabilityChanged");
OnNetworkChanged();
}
- private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
+ private void OnNetworkAddressChanged(object sender, EventArgs e)
{
- Logger.LogDebug("NetworkAddressChanged");
+ _logger.LogDebug("NetworkAddressChanged");
OnNetworkChanged();
}
@@ -68,39 +51,35 @@ namespace Emby.Server.Implementations.Networking
_localIpAddresses = null;
_macAddresses = null;
}
+
if (NetworkChanged != null)
{
NetworkChanged(this, EventArgs.Empty);
}
}
- private IpAddressInfo[] _localIpAddresses;
- private readonly object _localIpAddressSyncLock = new object();
-
- public IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
+ public IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
{
lock (_localIpAddressSyncLock)
{
if (_localIpAddresses == null)
{
- var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).Result.Select(ToIpAddressInfo).ToArray();
+ var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).ToArray();
_localIpAddresses = addresses;
-
- return addresses;
}
+
return _localIpAddresses;
}
}
- private async Task> GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
+ private List GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
{
- var list = GetIPsDefault(ignoreVirtualInterface)
- .ToList();
+ var list = GetIPsDefault(ignoreVirtualInterface).ToList();
if (list.Count == 0)
{
- list.AddRange(await GetLocalIpAddressesFallback().ConfigureAwait(false));
+ list = GetLocalIpAddressesFallback().GetAwaiter().GetResult().ToList();
}
var listClone = list.ToList();
@@ -351,13 +330,13 @@ namespace Emby.Server.Implementations.Networking
try
{
var host = uri.DnsSafeHost;
- Logger.LogDebug("Resolving host {0}", host);
+ _logger.LogDebug("Resolving host {0}", host);
address = GetIpAddresses(host).Result.FirstOrDefault();
if (address != null)
{
- Logger.LogDebug("{0} resolved to {1}", host, address);
+ _logger.LogDebug("{0} resolved to {1}", host, address);
return IsInLocalNetworkInternal(address.ToString(), false);
}
@@ -368,7 +347,7 @@ namespace Emby.Server.Implementations.Networking
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error resolving hostname");
+ _logger.LogError(ex, "Error resolving hostname");
}
}
}
@@ -381,56 +360,41 @@ namespace Emby.Server.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName);
}
- private List GetIPsDefault(bool ignoreVirtualInterface)
+ private IEnumerable GetIPsDefault(bool ignoreVirtualInterface)
{
- NetworkInterface[] interfaces;
+ IEnumerable interfaces;
try
{
- var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown };
-
interfaces = NetworkInterface.GetAllNetworkInterfaces()
- .Where(i => validStatuses.Contains(i.OperationalStatus))
- .ToArray();
+ .Where(x => x.OperationalStatus == OperationalStatus.Up
+ || x.OperationalStatus == OperationalStatus.Unknown);
}
- catch (Exception ex)
+ catch (NetworkInformationException ex)
{
- Logger.LogError(ex, "Error in GetAllNetworkInterfaces");
- return new List();
+ _logger.LogError(ex, "Error in GetAllNetworkInterfaces");
+ return Enumerable.Empty();
}
return interfaces.SelectMany(network =>
{
+ var ipProperties = network.GetIPProperties();
- try
+ // Try to exclude virtual adapters
+ // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
+ var addr = ipProperties.GatewayAddresses.FirstOrDefault();
+ if (addr == null
+ || (ignoreVirtualInterface
+ && (addr.Address.Equals(IPAddress.Any) || addr.Address.Equals(IPAddress.IPv6Any))))
{
- // suppress logging because it might be causing nas device wake up
- //logger.LogDebug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
-
- var ipProperties = network.GetIPProperties();
-
- // Try to exclude virtual adapters
- // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
- var addr = ipProperties.GatewayAddresses.FirstOrDefault();
- if (addr == null || ignoreVirtualInterface && string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
- {
- return new List();
- }
-
- return ipProperties.UnicastAddresses
- .Select(i => i.Address)
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6)
- .ToList();
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error querying network interface");
- return new List();
+ return Enumerable.Empty();
}
+ return ipProperties.UnicastAddresses
+ .Select(i => i.Address)
+ .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6);
}).GroupBy(i => i.ToString())
- .Select(x => x.First())
- .ToList();
+ .Select(x => x.First());
}
private static async Task> GetLocalIpAddressesFallback()
@@ -612,32 +576,10 @@ namespace Emby.Server.Implementations.Networking
return hosts[0];
}
- public IpAddressInfo ParseIpAddress(string ipAddress)
+ public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask)
{
- if (TryParseIpAddress(ipAddress, out var info))
- {
- return info;
- }
-
- throw new ArgumentException("Invalid ip address: " + ipAddress);
- }
-
- public bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo)
- {
- if (IPAddress.TryParse(ipAddress, out var address))
- {
- ipAddressInfo = ToIpAddressInfo(address);
- return true;
- }
-
- ipAddressInfo = null;
- return false;
- }
-
- public bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask)
- {
- IPAddress network1 = GetNetworkAddress(ToIPAddress(address1), ToIPAddress(subnetMask));
- IPAddress network2 = GetNetworkAddress(ToIPAddress(address2), ToIPAddress(subnetMask));
+ IPAddress network1 = GetNetworkAddress(address1, subnetMask);
+ IPAddress network2 = GetNetworkAddress(address2, subnetMask);
return network1.Equals(network2);
}
@@ -656,13 +598,13 @@ namespace Emby.Server.Implementations.Networking
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
+
return new IPAddress(broadcastAddress);
}
- public IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address)
+ public IPAddress GetLocalIpSubnetMask(IPAddress address)
{
NetworkInterface[] interfaces;
- IPAddress ipaddress = ToIPAddress(address);
try
{
@@ -674,7 +616,7 @@ namespace Emby.Server.Implementations.Networking
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error in GetAllNetworkInterfaces");
+ _logger.LogError(ex, "Error in GetAllNetworkInterfaces");
return null;
}
@@ -684,85 +626,17 @@ namespace Emby.Server.Implementations.Networking
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
- if (ip.Address.Equals(ipaddress) && ip.IPv4Mask != null)
+ if (ip.Address.Equals(address) && ip.IPv4Mask != null)
{
- return ToIpAddressInfo(ip.IPv4Mask);
+ return ip.IPv4Mask;
}
}
}
}
+
return null;
}
- public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
-
- return new IpEndPointInfo(ToIpAddressInfo(endpoint.Address), endpoint.Port);
- }
-
- public static IPEndPoint ToIPEndPoint(IpEndPointInfo endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
-
- return new IPEndPoint(ToIPAddress(endpoint.IpAddress), endpoint.Port);
- }
-
- public static IPAddress ToIPAddress(IpAddressInfo address)
- {
- if (address.Equals(IpAddressInfo.Any))
- {
- return IPAddress.Any;
- }
- if (address.Equals(IpAddressInfo.IPv6Any))
- {
- return IPAddress.IPv6Any;
- }
- if (address.Equals(IpAddressInfo.Loopback))
- {
- return IPAddress.Loopback;
- }
- if (address.Equals(IpAddressInfo.IPv6Loopback))
- {
- return IPAddress.IPv6Loopback;
- }
-
- return IPAddress.Parse(address.Address);
- }
-
- public static IpAddressInfo ToIpAddressInfo(IPAddress address)
- {
- if (address.Equals(IPAddress.Any))
- {
- return IpAddressInfo.Any;
- }
- if (address.Equals(IPAddress.IPv6Any))
- {
- return IpAddressInfo.IPv6Any;
- }
- if (address.Equals(IPAddress.Loopback))
- {
- return IpAddressInfo.Loopback;
- }
- if (address.Equals(IPAddress.IPv6Loopback))
- {
- return IpAddressInfo.IPv6Loopback;
- }
- return new IpAddressInfo(address.ToString(), address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork);
- }
-
- public async Task GetHostAddressesAsync(string host)
- {
- var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
- return addresses.Select(ToIpAddressInfo).ToArray();
- }
-
///
/// Gets the network shares.
///
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index e7cda2993f..185a282ac4 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Udp
private bool _isDisposed;
- private readonly List>> _responders = new List>>();
+ private readonly List>> _responders = new List>>();
private readonly IServerApplicationHost _appHost;
private readonly IJsonSerializer _json;
@@ -43,9 +44,9 @@ namespace Emby.Server.Implementations.Udp
AddMessageResponder("who is JellyfinServer?", true, RespondToV2Message);
}
- private void AddMessageResponder(string message, bool isSubstring, Func responder)
+ private void AddMessageResponder(string message, bool isSubstring, Func responder)
{
- _responders.Add(new Tuple>(message, isSubstring, responder));
+ _responders.Add(new Tuple>(message, isSubstring, responder));
}
///
@@ -83,7 +84,7 @@ namespace Emby.Server.Implementations.Udp
}
}
- private Tuple>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
+ private Tuple>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
{
var text = encoding.GetString(buffer, 0, bytesReceived);
var responder = _responders.FirstOrDefault(i =>
@@ -99,10 +100,10 @@ namespace Emby.Server.Implementations.Udp
{
return null;
}
- return new Tuple>>(text, responder);
+ return new Tuple>>(text, responder);
}
- private async Task RespondToV2Message(string messageText, IpEndPointInfo endpoint, Encoding encoding, CancellationToken cancellationToken)
+ private async Task RespondToV2Message(string messageText, IPEndPoint endpoint, Encoding encoding, CancellationToken cancellationToken)
{
var parts = messageText.Split('|');
@@ -254,7 +255,7 @@ namespace Emby.Server.Implementations.Udp
}
}
- public async Task SendAsync(byte[] bytes, IpEndPointInfo remoteEndPoint, CancellationToken cancellationToken)
+ public async Task SendAsync(byte[] bytes, IPEndPoint remoteEndPoint, CancellationToken cancellationToken)
{
if (_isDisposed)
{
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 94308a98e8..08c0983bef 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -143,7 +143,7 @@ namespace Jellyfin.Server
options,
new ManagedFileSystem(_loggerFactory.CreateLogger(), appPaths),
new NullImageEncoder(),
- new NetworkManager(_loggerFactory),
+ new NetworkManager(_loggerFactory.CreateLogger()),
appConfig))
{
await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false);
diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs
index 34c6f58665..61f2bc2f9f 100644
--- a/MediaBrowser.Common/Net/INetworkManager.cs
+++ b/MediaBrowser.Common/Net/INetworkManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@@ -53,17 +54,12 @@ namespace MediaBrowser.Common.Net
/// true if [is in local network] [the specified endpoint]; otherwise, false.
bool IsInLocalNetwork(string endpoint);
- IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface);
-
- IpAddressInfo ParseIpAddress(string ipAddress);
-
- bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo);
-
- Task GetHostAddressesAsync(string host);
+ IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface);
bool IsAddressInSubnets(string addressString, string[] subnets);
- bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask);
- IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address);
+ bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask);
+
+ IPAddress GetLocalIpSubnetMask(IPAddress address);
}
}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 81b9ff0a57..3f8cc0b83f 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
namespace MediaBrowser.Controller
@@ -59,7 +59,7 @@ namespace MediaBrowser.Controller
/// Gets the local ip address.
///
/// The local ip address.
- Task> GetLocalIpAddresses(CancellationToken cancellationToken);
+ Task> GetLocalIpAddresses(CancellationToken cancellationToken);
///
/// Gets the local API URL.
@@ -77,7 +77,7 @@ namespace MediaBrowser.Controller
///
/// Gets the local API URL.
///
- string GetLocalApiUrl(IpAddressInfo address);
+ string GetLocalApiUrl(IPAddress address);
void LaunchUrl(string url);
diff --git a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
index 4edbb503bb..c443a8ad18 100644
--- a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
+++ b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace MediaBrowser.Model.Dlna
{
@@ -8,7 +8,7 @@ namespace MediaBrowser.Model.Dlna
{
public Uri Location { get; set; }
public Dictionary Headers { get; set; }
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
public int LocalPort { get; set; }
}
}
diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs
index 992ccb49b0..f80de5524c 100644
--- a/MediaBrowser.Model/Net/ISocket.cs
+++ b/MediaBrowser.Model/Net/ISocket.cs
@@ -1,4 +1,5 @@
using System;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
@@ -9,7 +10,7 @@ namespace MediaBrowser.Model.Net
///
public interface ISocket : IDisposable
{
- IpAddressInfo LocalIPAddress { get; }
+ IPAddress LocalIPAddress { get; }
Task ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
@@ -21,6 +22,6 @@ namespace MediaBrowser.Model.Net
///
/// Sends a UDP message to a particular end point (uni or multicast).
///
- Task SendToAsync(byte[] buffer, int offset, int bytes, IpEndPointInfo endPoint, CancellationToken cancellationToken);
+ Task SendToAsync(byte[] buffer, int offset, int bytes, IPEndPoint endPoint, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs
index 69fe134bc7..e58f4cc14d 100644
--- a/MediaBrowser.Model/Net/ISocketFactory.cs
+++ b/MediaBrowser.Model/Net/ISocketFactory.cs
@@ -1,4 +1,5 @@
using System.IO;
+using System.Net;
namespace MediaBrowser.Model.Net
{
@@ -8,7 +9,7 @@ namespace MediaBrowser.Model.Net
public interface ISocketFactory
{
///
- /// Createa a new unicast socket using the specified local port number.
+ /// Creates a new unicast socket using the specified local port number.
///
/// The local port to bind to.
/// A implementation.
@@ -16,15 +17,15 @@ namespace MediaBrowser.Model.Net
ISocket CreateUdpBroadcastSocket(int localPort);
- ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
+ ISocket CreateTcpSocket(IPAddress remoteAddress, int remotePort);
///
- /// Createa a new unicast socket using the specified local port number.
+ /// Creates a new unicast socket using the specified local port number.
///
- ISocket CreateSsdpUdpSocket(IpAddressInfo localIp, int localPort);
+ ISocket CreateSsdpUdpSocket(IPAddress localIp, int localPort);
///
- /// Createa a new multicast socket using the specified multicast IP address, multicast time to live and local port.
+ /// Creates a new multicast socket using the specified multicast IP address, multicast time to live and local port.
///
/// The multicast IP address to bind to.
/// The multicast time to live value. Actually a maximum number of network hops for UDP packets.
diff --git a/MediaBrowser.Model/Net/IpAddressInfo.cs b/MediaBrowser.Model/Net/IpAddressInfo.cs
deleted file mode 100644
index 87fa55bcae..0000000000
--- a/MediaBrowser.Model/Net/IpAddressInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Net
-{
- public class IpAddressInfo
- {
- public static IpAddressInfo Any = new IpAddressInfo("0.0.0.0", IpAddressFamily.InterNetwork);
- public static IpAddressInfo IPv6Any = new IpAddressInfo("00000000000000000000", IpAddressFamily.InterNetworkV6);
- public static IpAddressInfo Loopback = new IpAddressInfo("127.0.0.1", IpAddressFamily.InterNetwork);
- public static IpAddressInfo IPv6Loopback = new IpAddressInfo("::1", IpAddressFamily.InterNetworkV6);
-
- public string Address { get; set; }
- public IpAddressInfo SubnetMask { get; set; }
- public IpAddressFamily AddressFamily { get; set; }
-
- public IpAddressInfo(string address, IpAddressFamily addressFamily)
- {
- Address = address;
- AddressFamily = addressFamily;
- }
-
- public bool Equals(IpAddressInfo address)
- {
- return string.Equals(address.Address, Address, StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ToString()
- {
- return Address;
- }
- }
-
- public enum IpAddressFamily
- {
- InterNetwork,
- InterNetworkV6
- }
-}
diff --git a/MediaBrowser.Model/Net/IpEndPointInfo.cs b/MediaBrowser.Model/Net/IpEndPointInfo.cs
deleted file mode 100644
index f8c125144c..0000000000
--- a/MediaBrowser.Model/Net/IpEndPointInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Globalization;
-
-namespace MediaBrowser.Model.Net
-{
- public class IpEndPointInfo
- {
- public IpAddressInfo IpAddress { get; set; }
-
- public int Port { get; set; }
-
- public IpEndPointInfo()
- {
-
- }
-
- public IpEndPointInfo(IpAddressInfo address, int port)
- {
- IpAddress = address;
- Port = port;
- }
-
- public override string ToString()
- {
- var ipAddresString = IpAddress == null ? string.Empty : IpAddress.ToString();
-
- return ipAddresString + ":" + Port.ToString(CultureInfo.InvariantCulture);
- }
- }
-}
diff --git a/MediaBrowser.Model/Net/SocketReceiveResult.cs b/MediaBrowser.Model/Net/SocketReceiveResult.cs
index 8c394f7c7d..cd7a2e55f8 100644
--- a/MediaBrowser.Model/Net/SocketReceiveResult.cs
+++ b/MediaBrowser.Model/Net/SocketReceiveResult.cs
@@ -1,3 +1,5 @@
+using System.Net;
+
namespace MediaBrowser.Model.Net
{
///
@@ -18,7 +20,7 @@ namespace MediaBrowser.Model.Net
///
/// The the data was received from.
///
- public IpEndPointInfo RemoteEndPoint { get; set; }
- public IpAddressInfo LocalIPAddress { get; set; }
+ public IPEndPoint RemoteEndPoint { get; set; }
+ public IPAddress LocalIPAddress { get; set; }
}
}
diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs
index 9106e27e53..21ac7c6311 100644
--- a/RSSDP/DeviceAvailableEventArgs.cs
+++ b/RSSDP/DeviceAvailableEventArgs.cs
@@ -1,8 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace Rssdp
{
@@ -11,12 +8,12 @@ namespace Rssdp
///
public sealed class DeviceAvailableEventArgs : EventArgs
{
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
#region Fields
private readonly DiscoveredSsdpDevice _DiscoveredDevice;
- private readonly bool _IsNewlyDiscovered;
+ private readonly bool _IsNewlyDiscovered;
#endregion
@@ -29,34 +26,34 @@ namespace Rssdp
/// A boolean value indicating whether or not this device came from the cache. See for more detail.
/// Thrown if the parameter is null.
public DeviceAvailableEventArgs(DiscoveredSsdpDevice discoveredDevice, bool isNewlyDiscovered)
- {
- if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice));
+ {
+ if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice));
- _DiscoveredDevice = discoveredDevice;
- _IsNewlyDiscovered = isNewlyDiscovered;
- }
+ _DiscoveredDevice = discoveredDevice;
+ _IsNewlyDiscovered = isNewlyDiscovered;
+ }
- #endregion
+ #endregion
- #region Public Properties
+ #region Public Properties
- ///
- /// Returns true if the device was discovered due to an alive notification, or a search and was not already in the cache. Returns false if the item came from the cache but matched the current search request.
- ///
- public bool IsNewlyDiscovered
- {
- get { return _IsNewlyDiscovered; }
- }
+ ///
+ /// Returns true if the device was discovered due to an alive notification, or a search and was not already in the cache. Returns false if the item came from the cache but matched the current search request.
+ ///
+ public bool IsNewlyDiscovered
+ {
+ get { return _IsNewlyDiscovered; }
+ }
///
/// A reference to a instance containing the discovered details and allowing access to the full device description.
///
public DiscoveredSsdpDevice DiscoveredDevice
- {
- get { return _DiscoveredDevice; }
- }
+ {
+ get { return _DiscoveredDevice; }
+ }
- #endregion
-
- }
-}
\ No newline at end of file
+ #endregion
+
+ }
+}
diff --git a/RSSDP/ISsdpCommunicationsServer.cs b/RSSDP/ISsdpCommunicationsServer.cs
index c99d684a13..8cf65df116 100644
--- a/RSSDP/ISsdpCommunicationsServer.cs
+++ b/RSSDP/ISsdpCommunicationsServer.cs
@@ -1,7 +1,7 @@
using System;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -40,13 +40,13 @@ namespace Rssdp.Infrastructure
///
/// Sends a message to a particular address (uni or multicast) and port.
///
- Task SendMessage(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMessage(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
///
/// Sends a message to the SSDP multicast address and port.
///
- Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
- Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMulticastMessage(string message, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
#endregion
diff --git a/RSSDP/RequestReceivedEventArgs.cs b/RSSDP/RequestReceivedEventArgs.cs
index fd3cd9e3a2..b753950f0a 100644
--- a/RSSDP/RequestReceivedEventArgs.cs
+++ b/RSSDP/RequestReceivedEventArgs.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Net;
using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -16,18 +12,18 @@ namespace Rssdp.Infrastructure
#region Fields
private readonly HttpRequestMessage _Message;
- private readonly IpEndPointInfo _ReceivedFrom;
+ private readonly IPEndPoint _ReceivedFrom;
#endregion
- public IpAddressInfo LocalIpAddress { get; private set; }
+ public IPAddress LocalIpAddress { get; private set; }
#region Constructors
///
/// Full constructor.
///
- public RequestReceivedEventArgs(HttpRequestMessage message, IpEndPointInfo receivedFrom, IpAddressInfo localIpAddress)
+ public RequestReceivedEventArgs(HttpRequestMessage message, IPEndPoint receivedFrom, IPAddress localIpAddress)
{
_Message = message;
_ReceivedFrom = receivedFrom;
@@ -49,7 +45,7 @@ namespace Rssdp.Infrastructure
///
/// The the request came from.
///
- public IpEndPointInfo ReceivedFrom
+ public IPEndPoint ReceivedFrom
{
get { return _ReceivedFrom; }
}
diff --git a/RSSDP/ResponseReceivedEventArgs.cs b/RSSDP/ResponseReceivedEventArgs.cs
index 5ed9664eda..f9f9c3040c 100644
--- a/RSSDP/ResponseReceivedEventArgs.cs
+++ b/RSSDP/ResponseReceivedEventArgs.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Net;
using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -14,12 +10,12 @@ namespace Rssdp.Infrastructure
public sealed class ResponseReceivedEventArgs : EventArgs
{
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
#region Fields
private readonly HttpResponseMessage _Message;
- private readonly IpEndPointInfo _ReceivedFrom;
+ private readonly IPEndPoint _ReceivedFrom;
#endregion
@@ -28,7 +24,7 @@ namespace Rssdp.Infrastructure
///
/// Full constructor.
///
- public ResponseReceivedEventArgs(HttpResponseMessage message, IpEndPointInfo receivedFrom)
+ public ResponseReceivedEventArgs(HttpResponseMessage message, IPEndPoint receivedFrom)
{
_Message = message;
_ReceivedFrom = receivedFrom;
@@ -49,7 +45,7 @@ namespace Rssdp.Infrastructure
///
/// The the response came from.
///
- public IpEndPointInfo ReceivedFrom
+ public IPEndPoint ReceivedFrom
{
get { return _ReceivedFrom; }
}
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index 5d2afc37a0..0aa985a261 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
@@ -163,7 +164,7 @@ namespace Rssdp.Infrastructure
///
/// Sends a message to a particular address (uni or multicast) and port.
///
- public async Task SendMessage(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public async Task SendMessage(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
if (messageData == null) throw new ArgumentNullException(nameof(messageData));
@@ -186,7 +187,7 @@ namespace Rssdp.Infrastructure
}
}
- private async Task SendFromSocket(ISocket socket, byte[] messageData, IpEndPointInfo destination, CancellationToken cancellationToken)
+ private async Task SendFromSocket(ISocket socket, byte[] messageData, IPEndPoint destination, CancellationToken cancellationToken)
{
try
{
@@ -206,7 +207,7 @@ namespace Rssdp.Infrastructure
}
}
- private List GetSendSockets(IpAddressInfo fromLocalIpAddress, IpEndPointInfo destination)
+ private List GetSendSockets(IPAddress fromLocalIpAddress, IPEndPoint destination)
{
EnsureSendSocketCreated();
@@ -215,24 +216,24 @@ namespace Rssdp.Infrastructure
var sockets = _sendSockets.Where(i => i.LocalIPAddress.AddressFamily == fromLocalIpAddress.AddressFamily);
// Send from the Any socket and the socket with the matching address
- if (fromLocalIpAddress.AddressFamily == IpAddressFamily.InterNetwork)
+ if (fromLocalIpAddress.AddressFamily == AddressFamily.InterNetwork)
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
// If sending to the loopback address, filter the socket list as well
- if (destination.IpAddress.Equals(IpAddressInfo.Loopback))
+ if (destination.Address.Equals(IPAddress.Loopback))
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.Any) || i.LocalIPAddress.Equals(IpAddressInfo.Loopback));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.Any) || i.LocalIPAddress.Equals(IPAddress.Loopback));
}
}
- else if (fromLocalIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ else if (fromLocalIpAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.IPv6Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.IPv6Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
// If sending to the loopback address, filter the socket list as well
- if (destination.IpAddress.Equals(IpAddressInfo.IPv6Loopback))
+ if (destination.Address.Equals(IPAddress.IPv6Loopback))
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.IPv6Any) || i.LocalIPAddress.Equals(IpAddressInfo.IPv6Loopback));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.IPv6Any) || i.LocalIPAddress.Equals(IPAddress.IPv6Loopback));
}
}
@@ -240,7 +241,7 @@ namespace Rssdp.Infrastructure
}
}
- public Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public Task SendMulticastMessage(string message, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
return SendMulticastMessage(message, SsdpConstants.UdpResendCount, fromLocalIpAddress, cancellationToken);
}
@@ -248,7 +249,7 @@ namespace Rssdp.Infrastructure
///
/// Sends a message to the SSDP multicast address and port.
///
- public async Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public async Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
if (message == null) throw new ArgumentNullException(nameof(message));
@@ -263,12 +264,13 @@ namespace Rssdp.Infrastructure
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
for (var i = 0; i < sendCount; i++)
{
- await SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo
- {
- IpAddress = new IpAddressInfo(SsdpConstants.MulticastLocalAdminAddress, IpAddressFamily.InterNetwork),
- Port = SsdpConstants.MulticastPort
-
- }, fromLocalIpAddress, cancellationToken).ConfigureAwait(false);
+ await SendMessageIfSocketNotDisposed(
+ messageData,
+ new IPEndPoint(
+ IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress),
+ SsdpConstants.MulticastPort),
+ fromLocalIpAddress,
+ cancellationToken).ConfigureAwait(false);
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
@@ -336,7 +338,7 @@ namespace Rssdp.Infrastructure
#region Private Methods
- private Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ private Task SendMessageIfSocketNotDisposed(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
var sockets = _sendSockets;
if (sockets != null)
@@ -364,13 +366,13 @@ namespace Rssdp.Infrastructure
{
var sockets = new List();
- sockets.Add(_SocketFactory.CreateSsdpUdpSocket(IpAddressInfo.Any, _LocalPort));
+ sockets.Add(_SocketFactory.CreateSsdpUdpSocket(IPAddress.Any, _LocalPort));
if (_enableMultiSocketBinding)
{
foreach (var address in _networkManager.GetLocalIpAddresses(_config.Configuration.IgnoreVirtualInterfaces))
{
- if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
// Not support IPv6 right now
continue;
@@ -439,7 +441,7 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessMessage(string data, IpEndPointInfo endPoint, IpAddressInfo receivedOnLocalIpAddress)
+ private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress receivedOnLocalIpAddress)
{
// Responses start with the HTTP version, prefixed with HTTP/ while
// requests start with a method which can vary and might be one we haven't
@@ -481,7 +483,7 @@ namespace Rssdp.Infrastructure
}
}
- private void OnRequestReceived(HttpRequestMessage data, IpEndPointInfo remoteEndPoint, IpAddressInfo receivedOnLocalIpAddress)
+ private void OnRequestReceived(HttpRequestMessage data, IPEndPoint remoteEndPoint, IPAddress receivedOnLocalIpAddress)
{
//SSDP specification says only * is currently used but other uri's might
//be implemented in the future and should be ignored unless understood.
@@ -496,7 +498,7 @@ namespace Rssdp.Infrastructure
handlers(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnLocalIpAddress));
}
- private void OnResponseReceived(HttpResponseMessage data, IpEndPointInfo endPoint, IpAddressInfo localIpAddress)
+ private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIpAddress)
{
var handlers = this.ResponseReceived;
if (handlers != null)
diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs
index b4c4a88fdd..09f729e83a 100644
--- a/RSSDP/SsdpDevice.cs
+++ b/RSSDP/SsdpDevice.cs
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Text;
-using System.Threading.Tasks;
-using System.Xml;
using Rssdp.Infrastructure;
namespace Rssdp
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index e17e14c1a6..59a2710d58 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
using System.Linq;
+using System.Net;
using System.Net.Http;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -213,7 +210,7 @@ namespace Rssdp.Infrastructure
/// Raises the event.
///
///
- protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
+ protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (this.IsDisposed) return;
@@ -295,7 +292,7 @@ namespace Rssdp.Infrastructure
#region Discovery/Device Add
- private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IpAddressInfo localIpAddress)
+ private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IPAddress localIpAddress)
{
bool isNewDevice = false;
lock (_Devices)
@@ -316,7 +313,7 @@ namespace Rssdp.Infrastructure
DeviceFound(device, isNewDevice, localIpAddress);
}
- private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
+ private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (!NotificationTypeMatchesFilter(device)) return;
@@ -357,7 +354,7 @@ namespace Rssdp.Infrastructure
return _CommunicationsServer.SendMulticastMessage(message, null, cancellationToken);
}
- private void ProcessSearchResponseMessage(HttpResponseMessage message, IpAddressInfo localIpAddress)
+ private void ProcessSearchResponseMessage(HttpResponseMessage message, IPAddress localIpAddress)
{
if (!message.IsSuccessStatusCode) return;
@@ -378,7 +375,7 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessNotificationMessage(HttpRequestMessage message, IpAddressInfo localIpAddress)
+ private void ProcessNotificationMessage(HttpRequestMessage message, IPAddress localIpAddress)
{
if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0) return;
@@ -389,7 +386,7 @@ namespace Rssdp.Infrastructure
ProcessByeByeNotification(message);
}
- private void ProcessAliveNotification(HttpRequestMessage message, IpAddressInfo localIpAddress)
+ private void ProcessAliveNotification(HttpRequestMessage message, IPAddress localIpAddress)
{
var location = GetFirstHeaderUriValue("Location", message);
if (location != null)
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs
index 921f33c212..7f3e56394b 100644
--- a/RSSDP/SsdpDevicePublisher.cs
+++ b/RSSDP/SsdpDevicePublisher.cs
@@ -2,13 +2,10 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Net.Http;
-using System.Text;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
using MediaBrowser.Common.Net;
-using Rssdp;
namespace Rssdp.Infrastructure
{
@@ -199,7 +196,12 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessSearchRequest(string mx, string searchTarget, IpEndPointInfo remoteEndPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private void ProcessSearchRequest(
+ string mx,
+ string searchTarget,
+ IPEndPoint remoteEndPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
if (String.IsNullOrEmpty(searchTarget))
{
@@ -258,7 +260,7 @@ namespace Rssdp.Infrastructure
foreach (var device in deviceList)
{
if (!_sendOnlyMatchedHost ||
- _networkManager.IsInSameSubnet(device.ToRootDevice().Address, remoteEndPoint.IpAddress, device.ToRootDevice().SubnetMask))
+ _networkManager.IsInSameSubnet(device.ToRootDevice().Address, remoteEndPoint.Address, device.ToRootDevice().SubnetMask))
{
SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIpAddress, cancellationToken);
}
@@ -276,7 +278,11 @@ namespace Rssdp.Infrastructure
return _Devices.Union(_Devices.SelectManyRecursive((d) => d.Devices));
}
- private void SendDeviceSearchResponses(SsdpDevice device, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private void SendDeviceSearchResponses(
+ SsdpDevice device,
+ IPEndPoint endPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
bool isRootDevice = (device as SsdpRootDevice) != null;
if (isRootDevice)
@@ -296,7 +302,13 @@ namespace Rssdp.Infrastructure
return String.Format("{0}::{1}", udn, fullDeviceType);
}
- private async void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private async void SendSearchResponse(
+ string searchTarget,
+ SsdpDevice device,
+ string uniqueServiceName,
+ IPEndPoint endPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
var rootDevice = device.ToRootDevice();
@@ -333,7 +345,7 @@ namespace Rssdp.Infrastructure
//WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device);
}
- private bool IsDuplicateSearchRequest(string searchTarget, IpEndPointInfo endPoint)
+ private bool IsDuplicateSearchRequest(string searchTarget, IPEndPoint endPoint)
{
var isDuplicateRequest = false;
@@ -556,7 +568,7 @@ namespace Rssdp.Infrastructure
private class SearchRequest
{
- public IpEndPointInfo EndPoint { get; set; }
+ public IPEndPoint EndPoint { get; set; }
public DateTime Received { get; set; }
public string SearchTarget { get; set; }
diff --git a/RSSDP/SsdpRootDevice.cs b/RSSDP/SsdpRootDevice.cs
index d918b9040d..0f2de7b156 100644
--- a/RSSDP/SsdpRootDevice.cs
+++ b/RSSDP/SsdpRootDevice.cs
@@ -1,9 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-using Rssdp.Infrastructure;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace Rssdp
{
@@ -56,12 +52,12 @@ namespace Rssdp
///
/// Gets or sets the Address used to check if the received message from same interface with this device/tree. Required.
///
- public IpAddressInfo Address { get; set; }
+ public IPAddress Address { get; set; }
///
/// Gets or sets the SubnetMask used to check if the received message from same interface with this device/tree. Required.
///
- public IpAddressInfo SubnetMask { get; set; }
+ public IPAddress SubnetMask { get; set; }
///
/// The base URL to use for all relative url's provided in other propertise (and those of child devices). Optional.
From 8270d0cc91783c0c8c052b43af0d633edb8b6b04 Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Thu, 25 Jul 2019 00:23:56 +0200
Subject: [PATCH 07/36] Move IPv6 scope id removal logic to it's own function
---
.../ApplicationHost.cs | 32 +++++++++++--------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index c6ba2326aa..ef2f59d303 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1547,17 +1547,27 @@ namespace Emby.Server.Implementations
return null;
}
+ ///
+ /// Removes the scope id from IPv6 addresses.
+ ///
+ /// The IPv6 address.
+ /// The IPv6 address without the scope id.
+ private string RemoveScopeId(string address)
+ {
+ var index = address.IndexOf('%');
+ if (index == -1)
+ {
+ return address;
+ }
+
+ return address.Substring(0, index);
+ }
+
public string GetLocalApiUrl(IPAddress ipAddress)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- // Remove the scope id from IPv6 addresses
- var str = ipAddress.ToString();
- var index = str.IndexOf('%');
- if (index != -1)
- {
- str = str.Substring(0, index);
- }
+ var str = RemoveScopeId(ipAddress.ToString());
return GetLocalApiUrl("[" + str + "]");
}
@@ -1583,13 +1593,7 @@ namespace Emby.Server.Implementations
{
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- // Remove the scope id from IPv6 addresses
- var str = ipAddress.ToString();
- var index = str.IndexOf('%');
- if (index != -1)
- {
- str = str.Substring(0, index);
- }
+ var str = RemoveScopeId(ipAddress.ToString());
return GetWanApiUrl("[" + str + "]");
}
From d39decf9185a8221eb8f28ca752a233446f54ceb Mon Sep 17 00:00:00 2001
From: Anthony Lavado
Date: Sat, 27 Jul 2019 02:30:42 -0400
Subject: [PATCH 08/36] Adds null check on studio/network name
---
MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 5ea73dfbf5..80f2ceae69 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -355,7 +355,10 @@ namespace MediaBrowser.Providers.TV.TheTVDB
series.AddGenre(genre);
}
- series.AddStudio(tvdbSeries.Network);
+ if (!String.IsNullOrEmpty(tvdbSeries.Network))
+ {
+ series.AddStudio(tvdbSeries.Network);
+ }
if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended)
{
From 7faf3ab04aafc02a916b6fb7e010d73d3211e1ef Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Sun, 28 Jul 2019 19:41:36 +0200
Subject: [PATCH 09/36] Delete feature_request.md
---
.github/ISSUE_TEMPLATE/feature_request.md | 14 --------------
1 file changed, 14 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 3cbc8cbb91..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-name: Feature request
-about: Suggest a new feature
-title: ''
-labels: feature
-assignees: ''
-
----
-
-**Describe the feature you'd like**
-
-
-**Additional context**
-
From 8b1bd7ac6ba8ca9f1d8a57542a46e66107277ceb Mon Sep 17 00:00:00 2001
From: Bond-009
Date: Wed, 13 Feb 2019 16:37:18 +0100
Subject: [PATCH 10/36] Use a dictionary to look up mimetypes
---
Emby.Dlna/Didl/DidlBuilder.cs | 30 +-
Emby.Dlna/Profiles/DishHopperJoeyProfile.cs | 2 +-
Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml | 2 +-
MediaBrowser.Model/Net/MimeTypes.cs | 374 ++++++--------------
4 files changed, 123 insertions(+), 285 deletions(-)
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index 992a50e676..a21aff9f91 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -181,19 +181,6 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private string GetMimeType(string input)
- {
- var mime = MimeTypes.GetMimeType(input);
-
- // TODO: Instead of being hard-coded here, this should probably be moved into all of the existing profiles
- if (string.Equals(mime, "video/mp2t", StringComparison.OrdinalIgnoreCase))
- {
- mime = "video/mpeg";
- }
-
- return mime;
- }
-
private void AddVideoResource(DlnaOptions options, XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
{
if (streamInfo == null)
@@ -384,7 +371,7 @@ namespace Emby.Dlna.Didl
var filename = url.Substring(0, url.IndexOf('?'));
var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
- ? GetMimeType(filename)
+ ? MimeTypes.GetMimeType(filename)
: mediaProfile.MimeType;
writer.WriteAttributeString("protocolInfo", string.Format(
@@ -520,7 +507,7 @@ namespace Emby.Dlna.Didl
var filename = url.Substring(0, url.IndexOf('?'));
var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
- ? GetMimeType(filename)
+ ? MimeTypes.GetMimeType(filename)
: mediaProfile.MimeType;
var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
@@ -545,17 +532,10 @@ namespace Emby.Dlna.Didl
}
public static bool IsIdRoot(string id)
- {
- if (string.IsNullOrWhiteSpace(id)
+ => string.IsNullOrWhiteSpace(id)
|| string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
// Samsung sometimes uses 1 as root
- || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- }
+ || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase);
public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string requestedId = null)
{
@@ -971,7 +951,7 @@ namespace Emby.Dlna.Didl
writer.WriteAttributeString("protocolInfo", string.Format(
"http-get:*:{0}:{1}",
- GetMimeType("file." + format),
+ MimeTypes.GetMimeType("file." + format),
contentFeatures
));
diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
index d501cce0d2..8d8ab41cad 100644
--- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
+++ b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
@@ -9,7 +9,7 @@ namespace Emby.Dlna.Profiles
{
Name = "Dish Hopper-Joey";
- ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*";
+ ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*";
Identification = new DeviceIdentification
{
diff --git a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
index 5ff4975604..5b299577e1 100644
--- a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
+++ b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
@@ -28,7 +28,7 @@
140000000
192000
- http-get:*:video/mp2t:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*
+ http-get:*:video/mp2t:http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*
0
false
false
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 659abe84c9..d7bf956bbd 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -12,113 +12,133 @@ namespace MediaBrowser.Model.Net
public static class MimeTypes
{
///
- /// Any extension in this list is considered a video file - can be added to at runtime for extensibility
+ /// Any extension in this list is considered a video file
///
- private static readonly string[] VideoFileExtensions = new string[]
- {
- ".mkv",
- ".m2t",
- ".m2ts",
- ".img",
- ".iso",
- ".mk3d",
- ".ts",
- ".rmvb",
- ".mov",
- ".avi",
- ".mpg",
- ".mpeg",
- ".wmv",
- ".mp4",
- ".divx",
- ".dvr-ms",
- ".wtv",
- ".ogm",
- ".ogv",
- ".asf",
- ".m4v",
- ".flv",
- ".f4v",
- ".3gp",
- ".webm",
- ".mts",
- ".m2v",
- ".rec"
- };
-
- private static Dictionary GetVideoFileExtensionsDictionary()
+ private static readonly HashSet _videoFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase)
{
- var dict = new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- foreach (string ext in VideoFileExtensions)
- {
- dict[ext] = ext;
- }
-
- return dict;
- }
-
- private static readonly Dictionary VideoFileExtensionsDictionary = GetVideoFileExtensionsDictionary();
+ ".mkv",
+ ".m2t",
+ ".m2ts",
+ ".img",
+ ".iso",
+ ".mk3d",
+ ".ts",
+ ".rmvb",
+ ".mov",
+ ".avi",
+ ".mpg",
+ ".mpeg",
+ ".wmv",
+ ".mp4",
+ ".divx",
+ ".dvr-ms",
+ ".wtv",
+ ".ogm",
+ ".ogv",
+ ".asf",
+ ".m4v",
+ ".flv",
+ ".f4v",
+ ".3gp",
+ ".webm",
+ ".mts",
+ ".m2v",
+ ".rec"
+ };
// http://en.wikipedia.org/wiki/Internet_media_type
// Add more as needed
-
- private static Dictionary GetMimeTypeLookup()
+ private static readonly Dictionary _mimeTypeLookup = new Dictionary(StringComparer.OrdinalIgnoreCase)
{
- var dict = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ // Type application
+ { ".cbz", "application/x-cbz" },
+ { ".cbr", "application/epub+zip" },
+ { ".eot", "application/vnd.ms-fontobject" },
+ { ".epub", "application/epub+zip" },
+ { ".js", "application/x-javascript" },
+ { ".json", "application/json" },
+ { ".map", "application/x-javascript" },
+ { ".pdf", "application/pdf" },
+ { ".ttml", "application/ttml+xml" },
+ { ".m3u8", "application/x-mpegURL" },
+ { ".mobi", "application/x-mobipocket-ebook" },
+ { ".xml", "application/xml" },
- dict.Add(".jpg", "image/jpeg");
- dict.Add(".jpeg", "image/jpeg");
- dict.Add(".tbn", "image/jpeg");
- dict.Add(".png", "image/png");
- dict.Add(".gif", "image/gif");
- dict.Add(".tiff", "image/tiff");
- dict.Add(".webp", "image/webp");
- dict.Add(".ico", "image/vnd.microsoft.icon");
- dict.Add(".mpg", "video/mpeg");
- dict.Add(".mpeg", "video/mpeg");
- dict.Add(".ogv", "video/ogg");
- dict.Add(".mov", "video/quicktime");
- dict.Add(".webm", "video/webm");
- dict.Add(".mkv", "video/x-matroska");
- dict.Add(".wmv", "video/x-ms-wmv");
- dict.Add(".flv", "video/x-flv");
- dict.Add(".avi", "video/x-msvideo");
- dict.Add(".asf", "video/x-ms-asf");
- dict.Add(".m4v", "video/x-m4v");
- dict.Add(".m4s", "video/mp4");
- dict.Add(".cbz", "application/x-cbz");
- dict.Add(".cbr", "application/epub+zip");
- dict.Add(".epub", "application/epub+zip");
- dict.Add(".pdf", "application/pdf");
- dict.Add(".mobi", "application/x-mobipocket-ebook");
+ // Type image
+ { ".jpg", "image/jpeg" },
+ { ".jpeg", "image/jpeg" },
+ { ".tbn", "image/jpeg" },
+ { ".png", "image/png" },
+ { ".gif", "image/gif" },
+ { ".tiff", "image/tiff" },
+ { ".webp", "image/webp" },
+ { ".ico", "image/vnd.microsoft.icon" },
+ { ".svg", "image/svg+xml" },
+ { ".svgz", "image/svg+xml" },
- dict.Add(".ass", "text/x-ssa");
- dict.Add(".ssa", "text/x-ssa");
+ // Type font
+ { ".ttf" , "font/ttf" },
+ { ".woff" , "font/woff" },
- return dict;
- }
+ // Type text
+ { ".ass", "text/x-ssa" },
+ { ".ssa", "text/x-ssa" },
+ { ".css", "text/css" },
+ { ".csv", "text/csv" },
+ { ".txt", "text/plain" },
+ { ".vtt", "text/vtt" },
- private static readonly Dictionary MimeTypeLookup = GetMimeTypeLookup();
+ // Type video
+ { ".mpg", "video/mpeg" },
+ { ".ogv", "video/ogg" },
+ { ".mov", "video/quicktime" },
+ { ".webm", "video/webm" },
+ { ".mkv", "video/x-matroska" },
+ { ".wmv", "video/x-ms-wmv" },
+ { ".flv", "video/x-flv" },
+ { ".avi", "video/x-msvideo" },
+ { ".asf", "video/x-ms-asf" },
+ { ".m4v", "video/x-m4v" },
+ { ".m4s", "video/mp4" },
+ { ".3gp", "video/3gpp" },
+ { ".3g2", "video/3gpp2" },
+ { ".mpd", "video/vnd.mpeg.dash.mpd" },
+ { ".ts", "video/mp2t" },
- private static readonly Dictionary ExtensionLookup = CreateExtensionLookup();
+ // Type audio
+ { ".mp3", "audio/mpeg" },
+ { ".m4a", "audio/mp4" },
+ { ".aac", "audio/mp4" },
+ { ".webma", "audio/webm" },
+ { ".wav", "audio/wav" },
+ { ".wma", "audio/x-ms-wma" },
+ { ".ogg", "audio/ogg" },
+ { ".oga", "audio/ogg" },
+ { ".opus", "audio/ogg" },
+ { ".ac3", "audio/ac3" },
+ { ".dsf", "audio/dsf" },
+ { ".m4b", "audio/m4b" },
+ { ".xsp", "audio/xsp" },
+ { ".dsp", "audio/dsp" },
+ };
+
+ private static readonly Dictionary _extensionLookup = CreateExtensionLookup();
private static Dictionary CreateExtensionLookup()
{
- var dict = MimeTypeLookup
+ var dict = _mimeTypeLookup
.GroupBy(i => i.Value)
.ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
dict["image/jpg"] = ".jpg";
dict["image/x-png"] = ".png";
+ dict["audio/x-aac"] = ".aac";
+
return dict;
}
- public static string GetMimeType(string path)
- {
- return GetMimeType(path, true);
- }
+ public static string GetMimeType(string path) => GetMimeType(path, true);
///
/// Gets the type of the MIME.
@@ -130,138 +150,31 @@ namespace MediaBrowser.Model.Net
throw new ArgumentNullException(nameof(path));
}
- var ext = Path.GetExtension(path) ?? string.Empty;
+ var ext = Path.GetExtension(path);
- if (MimeTypeLookup.TryGetValue(ext, out string result))
+ if (_mimeTypeLookup.TryGetValue(ext, out string result))
{
return result;
}
- // Type video
- if (StringHelper.EqualsIgnoreCase(ext, ".3gp"))
- {
- return "video/3gpp";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".3g2"))
- {
- return "video/3gpp2";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ts"))
- {
- return "video/mp2t";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".mpd"))
- {
- return "video/vnd.mpeg.dash.mpd";
- }
-
// Catch-all for all video types that don't require specific mime types
- if (VideoFileExtensionsDictionary.ContainsKey(ext))
+ if (_videoFileExtensions.Contains(ext))
{
- return "video/" + ext.TrimStart('.').ToLowerInvariant();
+ return "video/" + ext.Substring(1);
}
// Type text
- if (StringHelper.EqualsIgnoreCase(ext, ".css"))
- {
- return "text/css";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".csv"))
- {
- return "text/csv";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".html"))
+ if (StringHelper.EqualsIgnoreCase(ext, ".html")
+ || StringHelper.EqualsIgnoreCase(ext, ".htm"))
{
return "text/html; charset=UTF-8";
}
- if (StringHelper.EqualsIgnoreCase(ext, ".htm"))
- {
- return "text/html; charset=UTF-8";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".txt"))
+
+ if (StringHelper.EqualsIgnoreCase(ext, ".log")
+ || StringHelper.EqualsIgnoreCase(ext, ".srt"))
{
return "text/plain";
}
- if (StringHelper.EqualsIgnoreCase(ext, ".log"))
- {
- return "text/plain";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".xml"))
- {
- return "application/xml";
- }
-
- // Type audio
- if (StringHelper.EqualsIgnoreCase(ext, ".mp3"))
- {
- return "audio/mpeg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".m4a"))
- {
- return "audio/mp4";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".aac"))
- {
- return "audio/mp4";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".webma"))
- {
- return "audio/webm";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".wav"))
- {
- return "audio/wav";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".wma"))
- {
- return "audio/x-ms-wma";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".flac"))
- {
- return "audio/flac";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".aac"))
- {
- return "audio/x-aac";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ogg"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".oga"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".opus"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ac3"))
- {
- return "audio/ac3";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".dsf"))
- {
- return "audio/dsf";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".m4b"))
- {
- return "audio/m4b";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".xsp"))
- {
- return "audio/xsp";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".dsp"))
- {
- return "audio/dsp";
- }
-
- // Playlists
- if (StringHelper.EqualsIgnoreCase(ext, ".m3u8"))
- {
- return "application/x-mpegURL";
- }
// Misc
if (StringHelper.EqualsIgnoreCase(ext, ".dll"))
@@ -269,63 +182,7 @@ namespace MediaBrowser.Model.Net
return "application/octet-stream";
}
- // Web
- if (StringHelper.EqualsIgnoreCase(ext, ".js"))
- {
- return "application/x-javascript";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".json"))
- {
- return "application/json";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".map"))
- {
- return "application/x-javascript";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".woff"))
- {
- return "font/woff";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".ttf"))
- {
- return "font/ttf";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".eot"))
- {
- return "application/vnd.ms-fontobject";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".svg"))
- {
- return "image/svg+xml";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".svgz"))
- {
- return "image/svg+xml";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".srt"))
- {
- return "text/plain";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".vtt"))
- {
- return "text/vtt";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".ttml"))
- {
- return "application/ttml+xml";
- }
-
- if (enableStreamDefault)
- {
- return "application/octet-stream";
- }
-
- return null;
+ return enableStreamDefault ? "application/octet-stream" : null;
}
public static string ToExtension(string mimeType)
@@ -338,10 +195,11 @@ namespace MediaBrowser.Model.Net
// handle text/html; charset=UTF-8
mimeType = mimeType.Split(';')[0];
- if (ExtensionLookup.TryGetValue(mimeType, out string result))
+ if (_extensionLookup.TryGetValue(mimeType, out string result))
{
return result;
}
+
return null;
}
}
From 9faf03541361d0d5e2adca14575dfd94807b29bf Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Sun, 28 Jul 2019 21:01:18 +0200
Subject: [PATCH 11/36] Add the --azure-pipelines switch to the compat checker
---
.ci/azure-pipelines.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index efd69680e4..46db0d9fe5 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -190,7 +190,7 @@ jobs:
- task: CmdLine@2
displayName: Execute ABI compatibility check tool
inputs:
- script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName)'
+ script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines'
workingDirectory: $(System.ArtifactsDirectory) # Optional
#failOnStderr: false # Optional
From b4f446fe42eb86b6edf6e29cc7c9dba15c4feacd Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Sun, 28 Jul 2019 22:50:41 +0200
Subject: [PATCH 12/36] Delete enhancement-request.md
---
.github/ISSUE_TEMPLATE/enhancement-request.md | 20 -------------------
1 file changed, 20 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/enhancement-request.md
diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md
deleted file mode 100644
index a655b60f53..0000000000
--- a/.github/ISSUE_TEMPLATE/enhancement-request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Enhancement request
-about: Suggest an modification to an existing feature
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-
-
-**Describe the solution you'd like**
-
-
-**Describe alternatives you've considered**
-
-
-**Additional context**
-
From e6ef6088fffd8d532bd59c2bf2aca1f68cae2137 Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Mon, 29 Jul 2019 00:43:57 +0200
Subject: [PATCH 13/36] Fix #1388 and #1472
---
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 2984efec37..b9ccc93efc 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -573,7 +573,9 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// TODO: Perhaps also use original_size=1920x800 ??
- return string.Format("subtitles=filename='{0}'{1}{2}{3}",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "subtitles=filename='{0}'{1}{2}",
_mediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
charsetParam,
// fallbackFontParam,
@@ -582,7 +584,9 @@ namespace MediaBrowser.Controller.MediaEncoding
var mediaPath = state.MediaPath ?? string.Empty;
- return string.Format("subtitles='{0}:si={1}'{2}",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "subtitles='{0}:si={1}'{2}",
_mediaEncoder.EscapeSubtitleFilterPath(mediaPath),
state.InternalSubtitleStreamOffset.ToString(_usCulture),
// fallbackFontParam,
From 5c9d0414234d49a94f323228ac65cf191e80949b Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Mon, 29 Jul 2019 13:57:36 +0200
Subject: [PATCH 14/36] Ignore Ipv6 link-local addresses
---
Emby.Server.Implementations/Networking/NetworkManager.cs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 3cacacf075..da06dc5c57 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -95,9 +95,8 @@ namespace Emby.Server.Implementations.Networking
private static bool FilterIpAddress(IPAddress address)
{
- var addressString = address.ToString();
-
- if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ if (address.IsIPv6LinkLocal
+ || address.ToString().StartsWith("169.", StringComparison.OrdinalIgnoreCase))
{
return false;
}
From 998017a76d7e0fcc340bf9dbc3436caef583f6b4 Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Mon, 29 Jul 2019 16:01:14 +0200
Subject: [PATCH 15/36] Include library via NuGet instead of via source
---
.../Emby.Server.Implementations.csproj | 1 +
Emby.Server.Implementations/Net/UdpSocket.cs | 1 -
.../Networking/IPNetwork/BigIntegerExt.cs | 167 --
.../IPNetwork/IPAddressCollection.cs | 94 -
.../Networking/IPNetwork/IPNetwork.cs | 2008 -----------------
.../IPNetwork/IPNetworkCollection.cs | 129 --
.../Networking/IPNetwork/LICENSE.txt | 24 -
.../Networking/NetworkManager.cs | 2 +-
8 files changed, 2 insertions(+), 2424 deletions(-)
delete mode 100644 Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
delete mode 100644 Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
delete mode 100644 Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
delete mode 100644 Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
delete mode 100644 Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 49015a07ec..abbaef26b8 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -20,6 +20,7 @@
+
diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 2908ee9afd..dde4a2a34c 100644
--- a/Emby.Server.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -3,7 +3,6 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.Networking;
using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.Net
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
deleted file mode 100644
index e4e944839a..0000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-using System.Text;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- ///
- /// Extension methods to convert
- /// instances to hexadecimal, octal, and binary strings.
- ///
- public static class BigIntegerExtensions
- {
- ///
- /// Converts a to a binary string.
- ///
- /// A .
- ///
- /// A containing a binary
- /// representation of the supplied .
- ///
- public static string ToBinaryString(this BigInteger bigint)
- {
- var bytes = bigint.ToByteArray();
- var idx = bytes.Length - 1;
-
- // Create a StringBuilder having appropriate capacity.
- var base2 = new StringBuilder(bytes.Length * 8);
-
- // Convert first byte to binary.
- var binary = Convert.ToString(bytes[idx], 2);
-
- // Ensure leading zero exists if value is positive.
- if (binary[0] != '0' && bigint.Sign == 1)
- {
- base2.Append('0');
- }
-
- // Append binary string to StringBuilder.
- base2.Append(binary);
-
- // Convert remaining bytes adding leading zeros.
- for (idx--; idx >= 0; idx--)
- {
- base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
- }
-
- return base2.ToString();
- }
-
- ///
- /// Converts a to a hexadecimal string.
- ///
- /// A .
- ///
- /// A containing a hexadecimal
- /// representation of the supplied .
- ///
- public static string ToHexadecimalString(this BigInteger bigint)
- {
- return bigint.ToString("X");
- }
-
- ///
- /// Converts a to a octal string.
- ///
- /// A .
- ///
- /// A containing an octal
- /// representation of the supplied .
- ///
- public static string ToOctalString(this BigInteger bigint)
- {
- var bytes = bigint.ToByteArray();
- var idx = bytes.Length - 1;
-
- // Create a StringBuilder having appropriate capacity.
- var base8 = new StringBuilder(((bytes.Length / 3) + 1) * 8);
-
- // Calculate how many bytes are extra when byte array is split
- // into three-byte (24-bit) chunks.
- var extra = bytes.Length % 3;
-
- // If no bytes are extra, use three bytes for first chunk.
- if (extra == 0)
- {
- extra = 3;
- }
-
- // Convert first chunk (24-bits) to integer value.
- int int24 = 0;
- for (; extra != 0; extra--)
- {
- int24 <<= 8;
- int24 += bytes[idx--];
- }
-
- // Convert 24-bit integer to octal without adding leading zeros.
- var octal = Convert.ToString(int24, 8);
-
- // Ensure leading zero exists if value is positive.
- if (octal[0] != '0')
- {
- if (bigint.Sign == 1)
- {
- base8.Append('0');
- }
- }
-
- // Append first converted chunk to StringBuilder.
- base8.Append(octal);
-
- // Convert remaining 24-bit chunks, adding leading zeros.
- for (; idx >= 0; idx -= 3)
- {
- int24 = (bytes[idx] << 16) + (bytes[idx - 1] << 8) + bytes[idx - 2];
- base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
- }
-
- return base8.ToString();
- }
-
- ///
- ///
- /// Reverse a Positive BigInteger ONLY
- /// Bitwise ~ operator
- ///
- /// Input : FF FF FF FF
- /// Width : 4
- /// Result : 00 00 00 00
- ///
- ///
- /// Input : 00 00 00 00
- /// Width : 4
- /// Result : FF FF FF FF
- ///
- /// Input : FF FF FF FF
- /// Width : 8
- /// Result : FF FF FF FF 00 00 00 00
- ///
- ///
- /// Input : 00 00 00 00
- /// Width : 8
- /// Result : FF FF FF FF FF FF FF FF
- ///
- ///
- ///
- ///
- ///
- public static BigInteger PositiveReverse(this BigInteger input, int width)
- {
-
- var result = new List();
- var bytes = input.ToByteArray();
- var work = new byte[width];
- Array.Copy(bytes, 0, work, 0, bytes.Length - 1); // Length -1 : positive BigInteger
-
- for (int i = 0; i < work.Length; i++)
- {
- result.Add((byte)(~work[i]));
- }
- result.Add(0); // positive BigInteger
- return new BigInteger(result.ToArray());
-
- }
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
deleted file mode 100644
index a0c5f73af2..0000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Net;
-using System.Numerics;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- public class IPAddressCollection : IEnumerable, IEnumerator
- {
-
- private IPNetwork _ipnetwork;
- private BigInteger _enumerator;
-
- internal IPAddressCollection(IPNetwork ipnetwork)
- {
- this._ipnetwork = ipnetwork;
- this._enumerator = -1;
- }
-
-
- #region Count, Array, Enumerator
-
- public BigInteger Count => this._ipnetwork.Total;
-
- public IPAddress this[BigInteger i]
- {
- get
- {
- if (i >= this.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(i));
- }
- byte width = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? (byte)32 : (byte)128;
- var ipn = this._ipnetwork.Subnet(width);
- return ipn[i].Network;
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- #region IEnumerator Members
-
- public IPAddress Current => this[this._enumerator];
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- // nothing to dispose
- return;
- }
-
- #endregion
-
- #region IEnumerator Members
-
- object IEnumerator.Current => this.Current;
-
- public bool MoveNext()
- {
- this._enumerator++;
- if (this._enumerator >= this.Count)
- {
- return false;
- }
- return true;
-
- }
-
- public void Reset()
- {
- this._enumerator = -1;
- }
-
- #endregion
-
- #endregion
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
deleted file mode 100644
index d6de61c0c9..0000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
+++ /dev/null
@@ -1,2008 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Numerics;
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- ///
- /// IP Network utility class.
- /// Use IPNetwork.Parse to create instances.
- ///
- public class IPNetwork : IComparable
- {
-
- #region properties
-
- //private uint _network;
- private BigInteger _ipaddress;
- private AddressFamily _family;
- //private uint _netmask;
- //private uint _broadcast;
- //private uint _firstUsable;
- //private uint _lastUsable;
- //private uint _usable;
- private byte _cidr;
-
- #endregion
-
- #region accessors
-
- private BigInteger _network
- {
- get
- {
- var uintNetwork = this._ipaddress & this._netmask;
- return uintNetwork;
- }
- }
-
- ///
- /// Network address
- ///
- public IPAddress Network => IPNetwork.ToIPAddress(this._network, this._family);
-
- ///
- /// Address Family
- ///
- public AddressFamily AddressFamily => this._family;
-
- private BigInteger _netmask => IPNetwork.ToUint(this._cidr, this._family);
-
- ///
- /// Netmask
- ///
- public IPAddress Netmask => IPNetwork.ToIPAddress(this._netmask, this._family);
-
- private BigInteger _broadcast
- {
- get
- {
-
- int width = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16;
- var uintBroadcast = this._network + this._netmask.PositiveReverse(width);
- return uintBroadcast;
- }
- }
-
- ///
- /// Broadcast address
- ///
- public IPAddress Broadcast
- {
- get
- {
- if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
- {
- return null;
- }
- return IPNetwork.ToIPAddress(this._broadcast, this._family);
- }
- }
-
- ///
- /// First usable IP adress in Network
- ///
- public IPAddress FirstUsable
- {
- get
- {
- var fisrt = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._network
- : (this.Usable <= 0) ? this._network : this._network + 1;
- return IPNetwork.ToIPAddress(fisrt, this._family);
- }
- }
-
- ///
- /// Last usable IP adress in Network
- ///
- public IPAddress LastUsable
- {
- get
- {
- var last = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._broadcast
- : (this.Usable <= 0) ? this._network : this._broadcast - 1;
- return IPNetwork.ToIPAddress(last, this._family);
- }
- }
-
- ///
- /// Number of usable IP adress in Network
- ///
- public BigInteger Usable
- {
- get
- {
-
- if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
- {
- return this.Total;
- }
- byte[] mask = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x00 };
- var bmask = new BigInteger(mask);
- var usableIps = (_cidr > 30) ? 0 : ((bmask >> _cidr) - 1);
- return usableIps;
- }
- }
-
- ///
- /// Number of IP adress in Network
- ///
- public BigInteger Total
- {
- get
- {
-
- int max = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- var count = BigInteger.Pow(2, (max - _cidr));
- return count;
- }
- }
-
-
- ///
- /// The CIDR netmask notation
- ///
- public byte Cidr => this._cidr;
-
- #endregion
-
- #region constructor
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
-
- IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
- {
-
- int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
-
- this._ipaddress = ipaddress;
- this._family = family;
- this._cidr = cidr;
-
- }
-
- #endregion
-
- #region parsers
-
- ///
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- public static IPNetwork Parse(string ipaddress, string netmask)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
- return ipnetwork;
- }
-
- ///
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- public static IPNetwork Parse(string ipaddress, byte cidr)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, cidr, out ipnetwork);
- return ipnetwork;
-
- }
-
- ///
- /// 192.168.168.100 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- public static IPNetwork Parse(IPAddress ipaddress, IPAddress netmask)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
- return ipnetwork;
-
- }
-
- ///
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- ///
- ///
- ///
- public static IPNetwork Parse(string network)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, network, out ipnetwork);
- return ipnetwork;
-
- }
-
- #endregion
-
- #region TryParse
-
-
-
- ///
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- public static bool TryParse(string ipaddress, string netmask, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
-
-
- ///
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- public static bool TryParse(string ipaddress, byte cidr, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, cidr, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
- ///
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- ///
- ///
- ///
- ///
- public static bool TryParse(string network, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, network, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
- ///
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- ///
- ///
- ///
- ///
- ///
- public static bool TryParse(IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
-
- #endregion
-
- #region InternalParse
-
- ///
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- private static void InternalParse(bool tryParse, string ipaddress, string netmask, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(ipaddress))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
- if (string.IsNullOrEmpty(netmask))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress ip = null;
- bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
- if (ipaddressParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("ipaddress");
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress mask = null;
- bool netmaskParsed = IPAddress.TryParse(netmask, out mask);
- if (netmaskParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- ipnetwork = null;
- return;
- }
-
- IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
- }
-
- private static void InternalParse(bool tryParse, string network, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(network))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(network));
- }
- ipnetwork = null;
- return;
- }
-
- network = Regex.Replace(network, @"[^0-9a-fA-F\.\/\s\:]+", "");
- network = Regex.Replace(network, @"\s{2,}", " ");
- network = network.Trim();
- string[] args = network.Split(new char[] { ' ', '/' });
- byte cidr = 0;
- if (args.Length == 1)
- {
-
- if (IPNetwork.TryGuessCidr(args[0], out cidr))
- {
- IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
- return;
- }
-
- if (tryParse == false)
- {
- throw new ArgumentException("network");
- }
- ipnetwork = null;
- return;
- }
-
- if (byte.TryParse(args[1], out cidr))
- {
- IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
- return;
- }
-
- IPNetwork.InternalParse(tryParse, args[0], args[1], out ipnetwork);
- return;
-
- }
-
-
-
- ///
- /// 192.168.168.100 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- private static void InternalParse(bool tryParse, IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
- {
-
- if (ipaddress == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
- if (netmask == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- ipnetwork = null;
- return;
- }
-
- var uintIpAddress = IPNetwork.ToBigInteger(ipaddress);
- bool parsed = IPNetwork.TryToCidr(netmask, out var cidr2);
- if (parsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- ipnetwork = null;
- return;
- }
- byte cidr = (byte)cidr2;
-
- var ipnet = new IPNetwork(uintIpAddress, ipaddress.AddressFamily, cidr);
- ipnetwork = ipnet;
-
- return;
- }
-
-
-
- ///
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- ///
- ///
- ///
- ///
- private static void InternalParse(bool tryParse, string ipaddress, byte cidr, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(ipaddress))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
-
- IPAddress ip = null;
- bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
- if (ipaddressParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("ipaddress");
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress mask = null;
- bool parsedNetmask = IPNetwork.TryToNetmask(cidr, ip.AddressFamily, out mask);
- if (parsedNetmask == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("cidr");
- }
- ipnetwork = null;
- return;
- }
-
-
- IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
- }
-
- #endregion
-
- #region converters
-
- #region ToUint
-
- ///
- /// Convert an ipadress to decimal
- /// 0.0.0.0 -> 0
- /// 0.0.1.0 -> 256
- ///
- ///
- ///
- public static BigInteger ToBigInteger(IPAddress ipaddress)
- {
- IPNetwork.InternalToBigInteger(false, ipaddress, out var uintIpAddress);
- return (BigInteger)uintIpAddress;
-
- }
-
- ///
- /// Convert an ipadress to decimal
- /// 0.0.0.0 -> 0
- /// 0.0.1.0 -> 256
- ///
- ///
- ///
- public static bool TryToBigInteger(IPAddress ipaddress, out BigInteger? uintIpAddress)
- {
- IPNetwork.InternalToBigInteger(true, ipaddress, out var uintIpAddress2);
- bool parsed = (uintIpAddress2 != null);
- uintIpAddress = uintIpAddress2;
- return parsed;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToBigInteger(bool tryParse, IPAddress ipaddress, out BigInteger? uintIpAddress)
- {
-
- if (ipaddress == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- uintIpAddress = null;
- return;
- }
-
- byte[] bytes = ipaddress.GetAddressBytes();
- /// 20180217 lduchosal
- /// code impossible to reach, GetAddressBytes returns either 4 or 16 bytes length addresses
- /// if (bytes.Length != 4 && bytes.Length != 16) {
- /// if (tryParse == false) {
- /// throw new ArgumentException("bytes");
- /// }
- /// uintIpAddress = null;
- /// return;
- /// }
-
- Array.Reverse(bytes);
- var unsigned = new List(bytes);
- unsigned.Add(0);
- uintIpAddress = new BigInteger(unsigned.ToArray());
- return;
- }
-
-
- ///
- /// Convert a cidr to BigInteger netmask
- ///
- ///
- ///
- public static BigInteger ToUint(byte cidr, AddressFamily family)
- {
- IPNetwork.InternalToBigInteger(false, cidr, family, out var uintNetmask);
- return (BigInteger)uintNetmask;
- }
-
-
- ///
- /// Convert a cidr to uint netmask
- ///
- ///
- ///
- public static bool TryToUint(byte cidr, AddressFamily family, out BigInteger? uintNetmask)
- {
- IPNetwork.InternalToBigInteger(true, cidr, family, out var uintNetmask2);
- bool parsed = (uintNetmask2 != null);
- uintNetmask = uintNetmask2;
- return parsed;
- }
-
- ///
- /// Convert a cidr to uint netmask
- ///
- ///
- ///
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToBigInteger(bool tryParse, byte cidr, AddressFamily family, out BigInteger? uintNetmask)
- {
-
- if (family == AddressFamily.InterNetwork && cidr > 32)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- uintNetmask = null;
- return;
- }
-
- if (family == AddressFamily.InterNetworkV6 && cidr > 128)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- uintNetmask = null;
- return;
- }
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- if (tryParse == false)
- {
- throw new NotSupportedException(family.ToString());
- }
- uintNetmask = null;
- return;
- }
-
- if (family == AddressFamily.InterNetwork)
- {
-
- uintNetmask = cidr == 0 ? 0 : 0xffffffff << (32 - cidr);
- return;
- }
-
- var mask = new BigInteger(new byte[] {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x00
- });
-
- var masked = cidr == 0 ? 0 : mask << (128 - cidr);
- byte[] m = masked.ToByteArray();
- byte[] bmask = new byte[17];
- int copy = m.Length > 16 ? 16 : m.Length;
- Array.Copy(m, 0, bmask, 0, copy);
- uintNetmask = new BigInteger(bmask);
-
-
- }
-
- #endregion
-
- #region ToCidr
-
- ///
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- ///
- ///
- ///
- private static void InternalToCidr(bool tryParse, BigInteger netmask, AddressFamily family, out byte? cidr)
- {
-
- if (!IPNetwork.InternalValidNetmask(netmask, family))
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- cidr = null;
- return;
- }
-
- byte cidr2 = IPNetwork.BitsSet(netmask, family);
- cidr = cidr2;
- return;
-
- }
- ///
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- ///
- ///
- ///
- public static byte ToCidr(IPAddress netmask)
- {
- IPNetwork.InternalToCidr(false, netmask, out var cidr);
- return (byte)cidr;
- }
-
- ///
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- ///
- ///
- ///
- public static bool TryToCidr(IPAddress netmask, out byte? cidr)
- {
- IPNetwork.InternalToCidr(true, netmask, out var cidr2);
- bool parsed = (cidr2 != null);
- cidr = cidr2;
- return parsed;
- }
-
- private static void InternalToCidr(bool tryParse, IPAddress netmask, out byte? cidr)
- {
-
- if (netmask == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- cidr = null;
- return;
- }
-
- bool parsed = IPNetwork.TryToBigInteger(netmask, out var uintNetmask2);
-
- /// 20180217 lduchosal
- /// impossible to reach code.
- /// if (parsed == false) {
- /// if (tryParse == false) {
- /// throw new ArgumentException("netmask");
- /// }
- /// cidr = null;
- /// return;
- /// }
- var uintNetmask = (BigInteger)uintNetmask2;
-
- IPNetwork.InternalToCidr(tryParse, uintNetmask, netmask.AddressFamily, out var cidr2);
- cidr = cidr2;
-
- return;
-
- }
-
-
- #endregion
-
- #region ToNetmask
-
- ///
- /// Convert CIDR to netmask
- /// 24 -> 255.255.255.0
- /// 16 -> 255.255.0.0
- /// 8 -> 255.0.0.0
- ///
- ///
- ///
- ///
- public static IPAddress ToNetmask(byte cidr, AddressFamily family)
- {
-
- IPAddress netmask = null;
- IPNetwork.InternalToNetmask(false, cidr, family, out netmask);
- return netmask;
- }
-
- ///
- /// Convert CIDR to netmask
- /// 24 -> 255.255.255.0
- /// 16 -> 255.255.0.0
- /// 8 -> 255.0.0.0
- ///
- ///
- ///
- ///
- public static bool TryToNetmask(byte cidr, AddressFamily family, out IPAddress netmask)
- {
-
- IPAddress netmask2 = null;
- IPNetwork.InternalToNetmask(true, cidr, family, out netmask2);
- bool parsed = (netmask2 != null);
- netmask = netmask2;
- return parsed;
- }
-
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToNetmask(bool tryParse, byte cidr, AddressFamily family, out IPAddress netmask)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("family");
- }
- netmask = null;
- return;
- }
-
- /// 20180217 lduchosal
- /// impossible to reach code, byte cannot be negative :
- ///
- /// if (cidr < 0) {
- /// if (tryParse == false) {
- /// throw new ArgumentOutOfRangeException("cidr");
- /// }
- /// netmask = null;
- /// return;
- /// }
-
- int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- netmask = null;
- return;
- }
-
- var mask = IPNetwork.ToUint(cidr, family);
- var netmask2 = IPNetwork.ToIPAddress(mask, family);
- netmask = netmask2;
-
- return;
- }
-
- #endregion
-
- #endregion
-
- #region utils
-
- #region BitsSet
-
- ///
- /// Count bits set to 1 in netmask
- ///
- ///
- ///
- ///
- private static byte BitsSet(BigInteger netmask, AddressFamily family)
- {
-
- string s = netmask.ToBinaryString();
- return (byte)s.Replace("0", "")
- .ToCharArray()
- .Length;
-
- }
-
-
- ///
- /// Count bits set to 1 in netmask
- ///
- ///
- ///
- public static uint BitsSet(IPAddress netmask)
- {
- var uintNetmask = IPNetwork.ToBigInteger(netmask);
- uint bits = IPNetwork.BitsSet(uintNetmask, netmask.AddressFamily);
- return bits;
- }
-
- #endregion
-
- #region ValidNetmask
-
- ///
- /// return true if netmask is a valid netmask
- /// 255.255.255.0, 255.0.0.0, 255.255.240.0, ...
- ///
- ///
- ///
- ///
- public static bool ValidNetmask(IPAddress netmask)
- {
-
- if (netmask == null)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- var uintNetmask = IPNetwork.ToBigInteger(netmask);
- bool valid = IPNetwork.InternalValidNetmask(uintNetmask, netmask.AddressFamily);
- return valid;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static bool InternalValidNetmask(BigInteger netmask, AddressFamily family)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- throw new ArgumentException("family");
- }
-
- var mask = family == AddressFamily.InterNetwork
- ? new BigInteger(0x0ffffffff)
- : new BigInteger(new byte[]{
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x00
- });
-
- var neg = ((~netmask) & (mask));
- bool isNetmask = ((neg + 1) & neg) == 0;
- return isNetmask;
-
- }
-
- #endregion
-
- #region ToIPAddress
-
- ///
- /// Transform a uint ipaddress into IPAddress object
- ///
- ///
- ///
- public static IPAddress ToIPAddress(BigInteger ipaddress, AddressFamily family)
- {
-
- int width = family == AddressFamily.InterNetwork ? 4 : 16;
- byte[] bytes = ipaddress.ToByteArray();
- byte[] bytes2 = new byte[width];
- int copy = bytes.Length > width ? width : bytes.Length;
- Array.Copy(bytes, 0, bytes2, 0, copy);
- Array.Reverse(bytes2);
-
- byte[] sized = Resize(bytes2, family);
- var ip = new IPAddress(sized);
- return ip;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static byte[] Resize(byte[] bytes, AddressFamily family)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- throw new ArgumentException("family");
- }
-
- int width = family == AddressFamily.InterNetwork ? 4 : 16;
-
- if (bytes.Length > width)
- {
- throw new ArgumentException("bytes");
- }
-
- byte[] result = new byte[width];
- Array.Copy(bytes, 0, result, 0, bytes.Length);
- return result;
- }
-
- #endregion
-
- #endregion
-
- #region contains
-
- ///
- /// return true if ipaddress is contained in network
- ///
- ///
- ///
- public bool Contains(IPAddress ipaddress)
- {
-
- if (ipaddress == null)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
-
- if (AddressFamily != ipaddress.AddressFamily)
- {
- return false;
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
- var uintAddress = IPNetwork.ToBigInteger(ipaddress);
-
- bool contains = (uintAddress >= uintNetwork
- && uintAddress <= uintBroadcast);
-
- return contains;
-
- }
-
- ///
- /// return true is network2 is fully contained in network
- ///
- ///
- ///
- public bool Contains(IPNetwork network2)
- {
-
- if (network2 == null)
- {
- throw new ArgumentNullException(nameof(network2));
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
-
- var uintFirst = network2._network;
- var uintLast = network2._broadcast;
-
- bool contains = (uintFirst >= uintNetwork
- && uintLast <= uintBroadcast);
-
- return contains;
- }
-
- #endregion
-
- #region overlap
-
- ///
- /// return true is network2 overlap network
- ///
- ///
- ///
- public bool Overlap(IPNetwork network2)
- {
-
- if (network2 == null)
- {
- throw new ArgumentNullException(nameof(network2));
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
-
- var uintFirst = network2._network;
- var uintLast = network2._broadcast;
-
- bool overlap =
- (uintFirst >= uintNetwork && uintFirst <= uintBroadcast)
- || (uintLast >= uintNetwork && uintLast <= uintBroadcast)
- || (uintFirst <= uintNetwork && uintLast >= uintBroadcast)
- || (uintFirst >= uintNetwork && uintLast <= uintBroadcast);
-
- return overlap;
- }
-
- #endregion
-
- #region ToString
-
- public override string ToString()
- {
- return string.Format("{0}/{1}", this.Network, this.Cidr);
- }
-
- #endregion
-
- #region IANA block
-
- private static readonly Lazy _iana_ablock_reserved = new Lazy(() => IPNetwork.Parse("10.0.0.0/8"));
- private static readonly Lazy _iana_bblock_reserved = new Lazy(() => IPNetwork.Parse("172.16.0.0/12"));
- private static readonly Lazy _iana_cblock_reserved = new Lazy(() => IPNetwork.Parse("192.168.0.0/16"));
-
- ///
- /// 10.0.0.0/8
- ///
- ///
- public static IPNetwork IANA_ABLK_RESERVED1 => _iana_ablock_reserved.Value;
-
- ///
- /// 172.12.0.0/12
- ///
- ///
- public static IPNetwork IANA_BBLK_RESERVED1 => _iana_bblock_reserved.Value;
-
- ///
- /// 192.168.0.0/16
- ///
- ///
- public static IPNetwork IANA_CBLK_RESERVED1 => _iana_cblock_reserved.Value;
-
- ///
- /// return true if ipaddress is contained in
- /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
- ///
- ///
- ///
- public static bool IsIANAReserved(IPAddress ipaddress)
- {
-
- if (ipaddress == null)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
-
- return IPNetwork.IANA_ABLK_RESERVED1.Contains(ipaddress)
- || IPNetwork.IANA_BBLK_RESERVED1.Contains(ipaddress)
- || IPNetwork.IANA_CBLK_RESERVED1.Contains(ipaddress);
- }
-
- ///
- /// return true if ipnetwork is contained in
- /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
- ///
- ///
- public bool IsIANAReserved()
- {
- return IPNetwork.IANA_ABLK_RESERVED1.Contains(this)
- || IPNetwork.IANA_BBLK_RESERVED1.Contains(this)
- || IPNetwork.IANA_CBLK_RESERVED1.Contains(this);
- }
-
- #endregion
-
- #region Subnet
-
- ///
- /// Subnet a network into multiple nets of cidr mask
- /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
- /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
- ///
- ///
- ///
- public IPNetworkCollection Subnet(byte cidr)
- {
- IPNetworkCollection ipnetworkCollection = null;
- IPNetwork.InternalSubnet(false, this, cidr, out ipnetworkCollection);
- return ipnetworkCollection;
- }
-
- ///
- /// Subnet a network into multiple nets of cidr mask
- /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
- /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
- ///
- ///
- ///
- public bool TrySubnet(byte cidr, out IPNetworkCollection ipnetworkCollection)
- {
- IPNetworkCollection inc = null;
- IPNetwork.InternalSubnet(true, this, cidr, out inc);
- if (inc == null)
- {
- ipnetworkCollection = null;
- return false;
- }
-
- ipnetworkCollection = inc;
- return true;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalSubnet(bool trySubnet, IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
- {
-
- if (network == null)
- {
- if (trySubnet == false)
- {
- throw new ArgumentNullException(nameof(network));
- }
- ipnetworkCollection = null;
- return;
- }
-
- int maxCidr = network._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- if (trySubnet == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- ipnetworkCollection = null;
- return;
- }
-
- if (cidr < network.Cidr)
- {
- if (trySubnet == false)
- {
- throw new ArgumentException("cidr");
- }
- ipnetworkCollection = null;
- return;
- }
-
- ipnetworkCollection = new IPNetworkCollection(network, cidr);
- return;
- }
-
-
-
- #endregion
-
- #region Supernet
-
- ///
- /// Supernet two consecutive cidr equal subnet into a single one
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
- /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
- ///
- ///
- ///
- public IPNetwork Supernet(IPNetwork network2)
- {
- IPNetwork supernet = null;
- IPNetwork.InternalSupernet(false, this, network2, out supernet);
- return supernet;
- }
-
- ///
- /// Try to supernet two consecutive cidr equal subnet into a single one
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
- /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
- ///
- ///
- ///
- public bool TrySupernet(IPNetwork network2, out IPNetwork supernet)
- {
-
- IPNetwork outSupernet = null;
- IPNetwork.InternalSupernet(true, this, network2, out outSupernet);
- bool parsed = (outSupernet != null);
- supernet = outSupernet;
- return parsed;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalSupernet(bool trySupernet, IPNetwork network1, IPNetwork network2, out IPNetwork supernet)
- {
-
- if (network1 == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(network1));
- }
- supernet = null;
- return;
- }
-
- if (network2 == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(network2));
- }
- supernet = null;
- return;
- }
-
-
- if (network1.Contains(network2))
- {
- supernet = new IPNetwork(network1._network, network1._family, network1.Cidr);
- return;
- }
-
- if (network2.Contains(network1))
- {
- supernet = new IPNetwork(network2._network, network2._family, network2.Cidr);
- return;
- }
-
- if (network1._cidr != network2._cidr)
- {
- if (trySupernet == false)
- {
- throw new ArgumentException("cidr");
- }
- supernet = null;
- return;
- }
-
- var first = (network1._network < network2._network) ? network1 : network2;
- var last = (network1._network > network2._network) ? network1 : network2;
-
- /// Starting from here :
- /// network1 and network2 have the same cidr,
- /// network1 does not contain network2,
- /// network2 does not contain network1,
- /// first is the lower subnet
- /// last is the higher subnet
-
-
- if ((first._broadcast + 1) != last._network)
- {
- if (trySupernet == false)
- {
- throw new ArgumentOutOfRangeException(nameof(trySupernet), "TrySupernet was false while the first and last networks are not adjacent.");
- }
- supernet = null;
- return;
- }
-
- var uintSupernet = first._network;
- byte cidrSupernet = (byte)(first._cidr - 1);
-
- var networkSupernet = new IPNetwork(uintSupernet, first._family, cidrSupernet);
- if (networkSupernet._network != first._network)
- {
- if (trySupernet == false)
- {
- throw new ArgumentException("network");
- }
- supernet = null;
- return;
- }
- supernet = networkSupernet;
- return;
- }
-
- #endregion
-
- #region GetHashCode
-
- public override int GetHashCode()
- {
- return string.Format("{0}|{1}|{2}",
- this._ipaddress.GetHashCode(),
- this._network.GetHashCode(),
- this._cidr.GetHashCode()).GetHashCode();
- }
-
- #endregion
-
- #region SupernetArray
-
- ///
- /// Supernet a list of subnet
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
- ///
- /// The IP networks
- ///
- public static IPNetwork[] Supernet(IPNetwork[] ipnetworks)
- {
- InternalSupernet(false, ipnetworks, out var supernet);
- return supernet;
- }
-
- ///
- /// Supernet a list of subnet
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
- ///
- ///
- ///
- ///
- public static bool TrySupernet(IPNetwork[] ipnetworks, out IPNetwork[] supernet)
- {
- bool supernetted = InternalSupernet(true, ipnetworks, out supernet);
- return supernetted;
-
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static bool InternalSupernet(bool trySupernet, IPNetwork[] ipnetworks, out IPNetwork[] supernet)
- {
-
- if (ipnetworks == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(ipnetworks));
- }
- supernet = null;
- return false;
- }
-
- if (ipnetworks.Length <= 0)
- {
- supernet = new IPNetwork[0];
- return true;
- }
-
- var supernetted = new List();
- var ipns = IPNetwork.Array2List(ipnetworks);
- var current = IPNetwork.List2Stack(ipns);
- int previousCount = 0;
- int currentCount = current.Count;
-
- while (previousCount != currentCount)
- {
-
- supernetted.Clear();
- while (current.Count > 1)
- {
- var ipn1 = current.Pop();
- var ipn2 = current.Peek();
-
- IPNetwork outNetwork = null;
- bool success = ipn1.TrySupernet(ipn2, out outNetwork);
- if (success)
- {
- current.Pop();
- current.Push(outNetwork);
- }
- else
- {
- supernetted.Add(ipn1);
- }
- }
- if (current.Count == 1)
- {
- supernetted.Add(current.Pop());
- }
-
- previousCount = currentCount;
- currentCount = supernetted.Count;
- current = IPNetwork.List2Stack(supernetted);
-
- }
- supernet = supernetted.ToArray();
- return true;
- }
-
- private static Stack List2Stack(List list)
- {
- var stack = new Stack();
- list.ForEach(new Action(
- delegate (IPNetwork ipn)
- {
- stack.Push(ipn);
- }
- ));
- return stack;
- }
-
- private static List Array2List(IPNetwork[] array)
- {
- var ipns = new List();
- ipns.AddRange(array);
- IPNetwork.RemoveNull(ipns);
- ipns.Sort(new Comparison(
- delegate (IPNetwork ipn1, IPNetwork ipn2)
- {
- int networkCompare = ipn1._network.CompareTo(ipn2._network);
- if (networkCompare == 0)
- {
- int cidrCompare = ipn1._cidr.CompareTo(ipn2._cidr);
- return cidrCompare;
- }
- return networkCompare;
- }
- ));
- ipns.Reverse();
-
- return ipns;
- }
-
- private static void RemoveNull(List ipns)
- {
- ipns.RemoveAll(new Predicate(
- delegate (IPNetwork ipn)
- {
- if (ipn == null)
- {
- return true;
- }
- return false;
- }
- ));
-
- }
-
- #endregion
-
- #region WideSubnet
-
- public static IPNetwork WideSubnet(string start, string end)
- {
-
- if (string.IsNullOrEmpty(start))
- {
- throw new ArgumentNullException(nameof(start));
- }
-
- if (string.IsNullOrEmpty(end))
- {
- throw new ArgumentNullException(nameof(end));
- }
-
- if (!IPAddress.TryParse(start, out var startIP))
- {
- throw new ArgumentException("start");
- }
-
- if (!IPAddress.TryParse(end, out var endIP))
- {
- throw new ArgumentException("end");
- }
-
- if (startIP.AddressFamily != endIP.AddressFamily)
- {
- throw new NotSupportedException("MixedAddressFamily");
- }
-
- var ipnetwork = new IPNetwork(0, startIP.AddressFamily, 0);
- for (byte cidr = 32; cidr >= 0; cidr--)
- {
- var wideSubnet = IPNetwork.Parse(start, cidr);
- if (wideSubnet.Contains(endIP))
- {
- ipnetwork = wideSubnet;
- break;
- }
- }
- return ipnetwork;
-
- }
-
- public static bool TryWideSubnet(IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
- {
- IPNetwork ipn = null;
- IPNetwork.InternalWideSubnet(true, ipnetworks, out ipn);
- if (ipn == null)
- {
- ipnetwork = null;
- return false;
- }
- ipnetwork = ipn;
- return true;
- }
-
- public static IPNetwork WideSubnet(IPNetwork[] ipnetworks)
- {
- IPNetwork ipn = null;
- IPNetwork.InternalWideSubnet(false, ipnetworks, out ipn);
- return ipn;
- }
-
- internal static void InternalWideSubnet(bool tryWide, IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
- {
-
- if (ipnetworks == null)
- {
- if (tryWide == false)
- {
- throw new ArgumentNullException(nameof(ipnetworks));
- }
- ipnetwork = null;
- return;
- }
-
-
- IPNetwork[] nnin = Array.FindAll(ipnetworks, new Predicate(
- delegate (IPNetwork ipnet)
- {
- return ipnet != null;
- }
- ));
-
- if (nnin.Length <= 0)
- {
- if (tryWide == false)
- {
- throw new ArgumentException("ipnetworks");
- }
- ipnetwork = null;
- return;
- }
-
- if (nnin.Length == 1)
- {
- var ipn0 = nnin[0];
- ipnetwork = ipn0;
- return;
- }
-
- Array.Sort(nnin);
- var nnin0 = nnin[0];
- var uintNnin0 = nnin0._ipaddress;
-
- var nninX = nnin[nnin.Length - 1];
- var ipaddressX = nninX.Broadcast;
-
- var family = ipnetworks[0]._family;
- foreach (var ipnx in ipnetworks)
- {
- if (ipnx._family != family)
- {
- throw new ArgumentException("MixedAddressFamily");
- }
- }
-
- var ipn = new IPNetwork(0, family, 0);
- for (byte cidr = nnin0._cidr; cidr >= 0; cidr--)
- {
- var wideSubnet = new IPNetwork(uintNnin0, family, cidr);
- if (wideSubnet.Contains(ipaddressX))
- {
- ipn = wideSubnet;
- break;
- }
- }
-
- ipnetwork = ipn;
- return;
- }
-
- #endregion
-
- #region Print
-
- ///
- /// Print an ipnetwork in a clear representation string
- ///
- ///
- public string Print()
- {
-
- var sw = new StringWriter();
-
- sw.WriteLine("IPNetwork : {0}", ToString());
- sw.WriteLine("Network : {0}", Network);
- sw.WriteLine("Netmask : {0}", Netmask);
- sw.WriteLine("Cidr : {0}", Cidr);
- sw.WriteLine("Broadcast : {0}", Broadcast);
- sw.WriteLine("FirstUsable : {0}", FirstUsable);
- sw.WriteLine("LastUsable : {0}", LastUsable);
- sw.WriteLine("Usable : {0}", Usable);
-
- return sw.ToString();
- }
-
- #endregion
-
- #region TryGuessCidr
-
- ///
- ///
- /// Class Leading bits Default netmask
- /// A (CIDR /8) 00 255.0.0.0
- /// A (CIDR /8) 01 255.0.0.0
- /// B (CIDR /16) 10 255.255.0.0
- /// C (CIDR /24) 11 255.255.255.0
- ///
- ///
- ///
- ///
- ///
- public static bool TryGuessCidr(string ip, out byte cidr)
- {
-
- IPAddress ipaddress = null;
- bool parsed = IPAddress.TryParse(string.Format("{0}", ip), out ipaddress);
- if (parsed == false)
- {
- cidr = 0;
- return false;
- }
-
- if (ipaddress.AddressFamily == AddressFamily.InterNetworkV6)
- {
- cidr = 64;
- return true;
- }
- var uintIPAddress = IPNetwork.ToBigInteger(ipaddress);
- uintIPAddress = uintIPAddress >> 29;
- if (uintIPAddress <= 3)
- {
- cidr = 8;
- return true;
- }
- else if (uintIPAddress <= 5)
- {
- cidr = 16;
- return true;
- }
- else if (uintIPAddress <= 6)
- {
- cidr = 24;
- return true;
- }
-
- cidr = 0;
- return false;
-
- }
-
- ///
- /// Try to parse cidr. Have to be >= 0 and <= 32 or 128
- ///
- ///
- ///
- ///
- public static bool TryParseCidr(string sidr, AddressFamily family, out byte? cidr)
- {
-
- byte b = 0;
- if (!byte.TryParse(sidr, out b))
- {
- cidr = null;
- return false;
- }
-
- IPAddress netmask = null;
- if (!IPNetwork.TryToNetmask(b, family, out netmask))
- {
- cidr = null;
- return false;
- }
-
- cidr = b;
- return true;
- }
-
- #endregion
-
- #region ListIPAddress
-
- public IPAddressCollection ListIPAddress()
- {
- return new IPAddressCollection(this);
- }
-
- #endregion
-
- /**
- * Need a better way to do it
- *
-#region TrySubstractNetwork
-
- public static bool TrySubstractNetwork(IPNetwork[] ipnetworks, IPNetwork substract, out IEnumerable result) {
-
- if (ipnetworks == null) {
- result = null;
- return false;
- }
- if (ipnetworks.Length <= 0) {
- result = null;
- return false;
- }
- if (substract == null) {
- result = null;
- return false;
- }
- var results = new List();
- foreach (var ipn in ipnetworks) {
- if (!Overlap(ipn, substract)) {
- results.Add(ipn);
- continue;
- }
-
- var collection = ipn.Subnet(substract.Cidr);
- var rtemp = new List();
- foreach(var subnet in collection) {
- if (subnet != substract) {
- rtemp.Add(subnet);
- }
- }
- var supernets = Supernet(rtemp.ToArray());
- results.AddRange(supernets);
- }
- result = results;
- return true;
- }
-#endregion
- * **/
-
- #region IComparable Members
-
- public static int Compare(IPNetwork left, IPNetwork right)
- {
- // two null IPNetworks are equal
- if (ReferenceEquals(left, null) && ReferenceEquals(right, null)) return 0;
-
- // two same IPNetworks are equal
- if (ReferenceEquals(left, right)) return 0;
-
- // null is always sorted first
- if (ReferenceEquals(left, null)) return -1;
- if (ReferenceEquals(right, null)) return 1;
-
- // first test the network
- var result = left._network.CompareTo(right._network);
- if (result != 0) return result;
-
- // then test the cidr
- result = left._cidr.CompareTo(right._cidr);
- return result;
- }
-
- public int CompareTo(IPNetwork other)
- {
- return Compare(this, other);
- }
-
- public int CompareTo(object obj)
- {
- // null is at less
- if (obj == null) return 1;
-
- // convert to a proper Cidr object
- var other = obj as IPNetwork;
-
- // type problem if null
- if (other == null)
- {
- throw new ArgumentException(
- "The supplied parameter is an invalid type. Please supply an IPNetwork type.",
- nameof(obj));
- }
-
- // perform the comparision
- return CompareTo(other);
- }
-
- #endregion
-
- #region IEquatable Members
-
- public static bool Equals(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) == 0;
- }
-
- public bool Equals(IPNetwork other)
- {
- return Equals(this, other);
- }
-
- public override bool Equals(object obj)
- {
- return Equals(this, obj as IPNetwork);
- }
-
- #endregion
-
- #region Operators
-
- public static bool operator ==(IPNetwork left, IPNetwork right)
- {
- return Equals(left, right);
- }
-
- public static bool operator !=(IPNetwork left, IPNetwork right)
- {
- return !Equals(left, right);
- }
-
- public static bool operator <(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) < 0;
- }
-
- public static bool operator >(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) > 0;
- }
-
- #endregion
-
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
deleted file mode 100644
index 4cda421e57..0000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Numerics;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- public class IPNetworkCollection : IEnumerable, IEnumerator
- {
-
- private BigInteger _enumerator;
- private byte _cidrSubnet;
- private IPNetwork _ipnetwork;
-
- private byte _cidr => this._ipnetwork.Cidr;
-
- private BigInteger _broadcast => IPNetwork.ToBigInteger(this._ipnetwork.Broadcast);
-
- private BigInteger _lastUsable => IPNetwork.ToBigInteger(this._ipnetwork.LastUsable);
- private BigInteger _network => IPNetwork.ToBigInteger(this._ipnetwork.Network);
-#if TRAVISCI
- public
-#else
- internal
-#endif
- IPNetworkCollection(IPNetwork ipnetwork, byte cidrSubnet)
- {
-
- int maxCidr = ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidrSubnet > maxCidr)
- {
- throw new ArgumentOutOfRangeException(nameof(cidrSubnet));
- }
-
- if (cidrSubnet < ipnetwork.Cidr)
- {
- throw new ArgumentException("cidr");
- }
-
- this._cidrSubnet = cidrSubnet;
- this._ipnetwork = ipnetwork;
- this._enumerator = -1;
- }
-
- #region Count, Array, Enumerator
-
- public BigInteger Count
- {
- get
- {
- var count = BigInteger.Pow(2, this._cidrSubnet - this._cidr);
- return count;
- }
- }
-
- public IPNetwork this[BigInteger i]
- {
- get
- {
- if (i >= this.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(i));
- }
-
- var last = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._lastUsable : this._broadcast;
- var increment = (last - this._network) / this.Count;
- var uintNetwork = this._network + ((increment + 1) * i);
- var ipn = new IPNetwork(uintNetwork, this._ipnetwork.AddressFamily, this._cidrSubnet);
- return ipn;
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- #region IEnumerator Members
-
- public IPNetwork Current => this[this._enumerator];
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- // nothing to dispose
- return;
- }
-
- #endregion
-
- #region IEnumerator Members
-
- object IEnumerator.Current => this.Current;
-
- public bool MoveNext()
- {
- this._enumerator++;
- if (this._enumerator >= this.Count)
- {
- return false;
- }
- return true;
-
- }
-
- public void Reset()
- {
- this._enumerator = -1;
- }
-
- #endregion
-
- #endregion
-
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt b/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
deleted file mode 100644
index 45d7392ac4..0000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2015, lduchosal
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 3cacacf075..82add242ac 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Networking
if (normalizedSubnet.IndexOf('/') != -1)
{
- var ipnetwork = IPNetwork.IPNetwork.Parse(normalizedSubnet);
+ var ipnetwork = IPNetwork.Parse(normalizedSubnet);
if (ipnetwork.Contains(address))
{
return true;
From 9e1adec5e00dd9a6c058c16b10ea42fef999b996 Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Mon, 29 Jul 2019 19:42:38 +0200
Subject: [PATCH 16/36] Update message for stale issues and also ignore feature
and enhancement labels
---
.github/stale.yml | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/stale.yml b/.github/stale.yml
index 3e76aa75d1..011f763177 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -9,12 +9,14 @@ exemptLabels:
- dotnet-3.0-future
- roadmap
- future
+ - feature
+ - enhancement
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
+ Issues go stale after 60d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 7d of inactivity.
+ If this issue is safe to close now please do so.
+ If you have any questions you can reach us on [Matrix or Social Media](https://jellyfin.readthedocs.io/en/latest/getting-help/).
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
From 487ba2b928f800bcab0173067e0ad46ca8f18615 Mon Sep 17 00:00:00 2001
From: Erwin de Haan
Date: Mon, 29 Jul 2019 20:21:47 +0200
Subject: [PATCH 17/36] Add Fider to README
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 643c59a731..8106b6e4e7 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
+
From d05440d267821b1242ecb81d77ac94325c0d06d0 Mon Sep 17 00:00:00 2001
From: Anthony Lavado
Date: Wed, 31 Jul 2019 12:21:46 -0400
Subject: [PATCH 18/36] Update
MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
Co-Authored-By: Claus Vium
---
MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 80f2ceae69..c739f3f494 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -355,7 +355,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB
series.AddGenre(genre);
}
- if (!String.IsNullOrEmpty(tvdbSeries.Network))
+ if (!string.IsNullOrEmpty(tvdbSeries.Network))
{
series.AddStudio(tvdbSeries.Network);
}
From 358665d944a8bcf238b57f2fb1583796ed839dd4 Mon Sep 17 00:00:00 2001
From: Andrew Rabert
Date: Wed, 31 Jul 2019 16:58:36 -0400
Subject: [PATCH 19/36] Docker - make web version more configurable This allows
for building against jellyfin-web master. Ex.
docker build . --build-arg JELLYFIN_WEB_VERSION=master
---
Dockerfile | 4 ++--
Dockerfile.arm | 4 ++--
Dockerfile.arm64 | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 057d4b0413..1644a8967d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,8 +21,8 @@ RUN apt-get update \
COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
diff --git a/Dockerfile.arm b/Dockerfile.arm
index dad4da1f14..b0cf7a8a46 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -26,8 +26,8 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 5d4e86bff4..f8ff0612b9 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -26,8 +26,8 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
From 0e6417c9fa04ea58638a1594245365da6be6f8c1 Mon Sep 17 00:00:00 2001
From: Erik Larsson
Date: Sat, 3 Aug 2019 12:37:02 +0200
Subject: [PATCH 20/36] Set log level to debug for HTTP range requests
---
Emby.Server.Implementations/HttpServer/FileWriter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index c6b7d31a83..ec41cc0a91 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.HttpServer
var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
Headers[HeaderNames.ContentRange] = rangeString;
- Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+ Logger.LogDebug("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
}
///
From b637cdabaef9703063fed23719bcac5a1709373e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82?=
Date: Fri, 2 Aug 2019 15:32:42 +0000
Subject: [PATCH 21/36] Translated using Weblate (Polish)
Currently translated at 100.0% (94 of 94 strings)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pl/
---
.../Localization/Core/pl.json | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json
index 92b12409d1..e72f1a2621 100644
--- a/Emby.Server.Implementations/Localization/Core/pl.json
+++ b/Emby.Server.Implementations/Localization/Core/pl.json
@@ -18,11 +18,11 @@
"HeaderAlbumArtists": "Wykonawcy albumów",
"HeaderCameraUploads": "Przekazane obrazy",
"HeaderContinueWatching": "Kontynuuj odtwarzanie",
- "HeaderFavoriteAlbums": "Albumy ulubione",
- "HeaderFavoriteArtists": "Wykonawcy ulubieni",
- "HeaderFavoriteEpisodes": "Odcinki ulubione",
- "HeaderFavoriteShows": "Seriale ulubione",
- "HeaderFavoriteSongs": "Utwory ulubione",
+ "HeaderFavoriteAlbums": "Ulubione albumy",
+ "HeaderFavoriteArtists": "Ulubieni wykonawcy",
+ "HeaderFavoriteEpisodes": "Ulubione odcinki",
+ "HeaderFavoriteShows": "Ulubione seriale",
+ "HeaderFavoriteSongs": "Ulubione utwory",
"HeaderLiveTV": "Telewizja",
"HeaderNextUp": "Do obejrzenia",
"HeaderRecordingGroups": "Grupy nagrań",
@@ -41,26 +41,26 @@
"Movies": "Filmy",
"Music": "Muzyka",
"MusicVideos": "Teledyski",
- "NameInstallFailed": "Instalacja {0} nieudana.",
+ "NameInstallFailed": "Instalacja {0} nieudana",
"NameSeasonNumber": "Sezon {0}",
- "NameSeasonUnknown": "Sezon nieznany",
+ "NameSeasonUnknown": "Nieznany sezon",
"NewVersionIsAvailable": "Nowa wersja serwera Jellyfin jest dostępna do pobrania.",
"NotificationOptionApplicationUpdateAvailable": "Dostępna aktualizacja aplikacji",
- "NotificationOptionApplicationUpdateInstalled": "Zainstalowano aktualizację aplikacji",
+ "NotificationOptionApplicationUpdateInstalled": "Zaktualizowano aplikację",
"NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki",
"NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane",
- "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia mobilnego",
- "NotificationOptionInstallationFailed": "Niepowodzenie instalacji",
+ "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia przenośnego",
+ "NotificationOptionInstallationFailed": "Nieudana instalacja",
"NotificationOptionNewLibraryContent": "Dodano nową zawartość",
"NotificationOptionPluginError": "Awaria wtyczki",
"NotificationOptionPluginInstalled": "Zainstalowano wtyczkę",
"NotificationOptionPluginUninstalled": "Odinstalowano wtyczkę",
- "NotificationOptionPluginUpdateInstalled": "Zainstalowano aktualizację wtyczki",
+ "NotificationOptionPluginUpdateInstalled": "Zaktualizowano wtyczkę",
"NotificationOptionServerRestartRequired": "Wymagane ponowne uruchomienie serwera",
"NotificationOptionTaskFailed": "Awaria zaplanowanego zadania",
"NotificationOptionUserLockedOut": "Użytkownik zablokowany",
"NotificationOptionVideoPlayback": "Rozpoczęto odtwarzanie wideo",
- "NotificationOptionVideoPlaybackStopped": "Odtwarzanie wideo zatrzymane",
+ "NotificationOptionVideoPlaybackStopped": "Zatrzymano odtwarzanie wideo",
"Photos": "Zdjęcia",
"Playlists": "Listy odtwarzania",
"Plugin": "Wtyczka",
@@ -73,7 +73,7 @@
"ServerNameNeedsToBeRestarted": "{0} wymaga ponownego uruchomienia",
"Shows": "Seriale",
"Songs": "Utwory",
- "StartupEmbyServerIsLoading": "Twa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
+ "StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
"SubtitleDownloadFailureForItem": "Pobieranie napisów dla {0} zakończone niepowodzeniem",
"SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
"SubtitlesDownloadedForItem": "Pobrano napisy dla {0}",
@@ -91,7 +91,7 @@
"UserPolicyUpdatedWithName": "Zmieniono zasady użytkowania dla {0}",
"UserStartedPlayingItemWithValues": "{0} odtwarza {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} zakończył odtwarzanie {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} został dodany to biblioteki mediów",
+ "ValueHasBeenAddedToLibrary": "{0} został dodany do biblioteki mediów",
"ValueSpecialEpisodeName": "Specjalne - {0}",
"VersionNumber": "Wersja {0}"
}
From 20cbbd4f4c99d9a603756f83e0132caa71c16c13 Mon Sep 17 00:00:00 2001
From: AndersMachmueller
Date: Sun, 4 Aug 2019 19:18:50 +0000
Subject: [PATCH 22/36] Translated using Weblate (Danish)
Currently translated at 100.0% (94 of 94 strings)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/da/
---
Emby.Server.Implementations/Localization/Core/da.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index cb8f4576ad..b01abafa13 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -18,11 +18,11 @@
"HeaderAlbumArtists": "Albumkunstnere",
"HeaderCameraUploads": "Kamera Uploads",
"HeaderContinueWatching": "Fortsæt Afspilning",
- "HeaderFavoriteAlbums": "Favoritalbum",
+ "HeaderFavoriteAlbums": "Favoritalbummer",
"HeaderFavoriteArtists": "Favoritkunstnere",
- "HeaderFavoriteEpisodes": "Favorit-afsnit",
- "HeaderFavoriteShows": "Favorit-serier",
- "HeaderFavoriteSongs": "Favorit-sange",
+ "HeaderFavoriteEpisodes": "Favoritepisoder",
+ "HeaderFavoriteShows": "Favoritserier",
+ "HeaderFavoriteSongs": "Favoritsange",
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Næste",
"HeaderRecordingGroups": "Optagelsesgrupper",
From 5e6e52d3977c679871f5633c59d82cbb3f6c2cce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tam=C3=A1s=20Mogyor=C3=B3si?=
Date: Thu, 25 Jul 2019 13:56:40 +0000
Subject: [PATCH 23/36] Translated using Weblate (Hungarian)
Currently translated at 100.0% (94 of 94 strings)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
---
Emby.Server.Implementations/Localization/Core/hu.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index c0f988abec..a2fc126a25 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -19,9 +19,9 @@
"HeaderCameraUploads": "Kamera feltöltések",
"HeaderContinueWatching": "Folyamatban lévő filmek",
"HeaderFavoriteAlbums": "Kedvenc Albumok",
- "HeaderFavoriteArtists": "Kedvenc Művészek",
+ "HeaderFavoriteArtists": "Kedvenc Előadók",
"HeaderFavoriteEpisodes": "Kedvenc Epizódok",
- "HeaderFavoriteShows": "Kedvenc Műsorok",
+ "HeaderFavoriteShows": "Kedvenc Sorozatok",
"HeaderFavoriteSongs": "Kedvenc Dalok",
"HeaderLiveTV": "Élő TV",
"HeaderNextUp": "Következik",
From 89f592687ee7ae7f0e0fffd884dbf2890476410a Mon Sep 17 00:00:00 2001
From: Tradutor da Silva
Date: Tue, 23 Jul 2019 02:28:08 +0000
Subject: [PATCH 24/36] Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.7% (90 of 94 strings)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_BR/
---
.../Localization/Core/pt-BR.json | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index 5d68416e9f..c4ce16dc85 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -21,8 +21,8 @@
"HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",
- "HeaderFavoriteShows": "Shows Favoritos",
- "HeaderFavoriteSongs": "Musicas Favoritas",
+ "HeaderFavoriteShows": "Séries Favoritas",
+ "HeaderFavoriteSongs": "Músicas Favoritas",
"HeaderLiveTV": "TV ao Vivo",
"HeaderNextUp": "Próximos",
"HeaderRecordingGroups": "Grupos de Gravação",
@@ -32,19 +32,19 @@
"ItemRemovedWithName": "{0} foi removido da biblioteca",
"LabelIpAddressValue": "Endereço IP: {0}",
"LabelRunningTimeValue": "Tempo de execução: {0}",
- "Latest": "Recente",
- "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado",
- "MessageApplicationUpdatedTo": "O Servidor Jellyfin foi atualizado para {0}",
+ "Latest": "Recentes",
+ "MessageApplicationUpdated": "Servidor Jellyfin atualizado",
+ "MessageApplicationUpdatedTo": "Servidor Jellyfin atualizado para {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "A seção {0} da configuração do servidor foi atualizada",
"MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada",
"MixedContent": "Conteúdo misto",
"Movies": "Filmes",
"Music": "Música",
- "MusicVideos": "Vídeos musicais",
+ "MusicVideos": "Clipes",
"NameInstallFailed": "A instalação de {0} falhou",
"NameSeasonNumber": "Temporada {0}",
"NameSeasonUnknown": "Temporada Desconhecida",
- "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para download.",
+ "NewVersionIsAvailable": "Uma nova versão do Servidor Jellyfin está disponível para download.",
"NotificationOptionApplicationUpdateAvailable": "Atualização de aplicativo disponível",
"NotificationOptionApplicationUpdateInstalled": "Atualização de aplicativo instalada",
"NotificationOptionAudioPlayback": "Reprodução de áudio iniciada",
From ff93b162ee67b05c785a7f167277625700172471 Mon Sep 17 00:00:00 2001
From: Anthony Lavado
Date: Tue, 6 Aug 2019 12:59:45 -0400
Subject: [PATCH 25/36] Update the Stale-bot config
Updates the Stale bot to mark an issue after 90 days, and allows 14
days before closing the issue.
---
.github/stale.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/stale.yml b/.github/stale.yml
index 011f763177..ce9fb01a1a 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -1,7 +1,7 @@
# Number of days of inactivity before an issue becomes stale
-daysUntilStale: 60
+daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
-daysUntilClose: 7
+daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- regression
@@ -15,7 +15,7 @@ exemptLabels:
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
- Issues go stale after 60d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 7d of inactivity.
+ Issues go stale after 90d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 14d of inactivity.
If this issue is safe to close now please do so.
If you have any questions you can reach us on [Matrix or Social Media](https://jellyfin.readthedocs.io/en/latest/getting-help/).
# Comment to post when closing a stale issue. Set to `false` to disable
From da0137629457093f6dbbe997963ed2d65fd1dba7 Mon Sep 17 00:00:00 2001
From: Andrew Rabert
Date: Tue, 6 Aug 2019 23:57:39 -0400
Subject: [PATCH 26/36] Fix Docker build
---
Dockerfile | 2 +-
Dockerfile.arm | 2 +-
Dockerfile.arm64 | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 1644a8967d..f8e6fec318 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,7 +24,7 @@ COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=v10.3.7
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Dockerfile.arm b/Dockerfile.arm
index b0cf7a8a46..651bdeff49 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -29,7 +29,7 @@ COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=v10.3.7
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index f8ff0612b9..f6bd81e4c2 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -29,7 +29,7 @@ COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=v10.3.7
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
From cf0460c7f98938109cb63cd029dc35981d7b0496 Mon Sep 17 00:00:00 2001
From: dkanada
Date: Wed, 7 Aug 2019 02:24:56 -0700
Subject: [PATCH 27/36] move comment to separate line
---
MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
index 9fd72b65c1..3dcfba26aa 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
@@ -167,7 +167,8 @@ namespace MediaBrowser.Providers.TV.TheTVDB
case "absolute":
episodeQuery.AbsoluteNumber = searchInfo.IndexNumber.Value;
break;
- default: //aired order
+ default:
+ //aired order
episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
break;
From 6c58ac5c55180f12fe2428b315477659b71b59d4 Mon Sep 17 00:00:00 2001
From: "Mathias L. Baumann"
Date: Fri, 9 Aug 2019 10:00:16 +0200
Subject: [PATCH 28/36] Add link to feature request hub to readme
---
README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 8106b6e4e7..800a72da1d 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,10 @@ For more information about the project, please see our [about page](https://jell
Check out our documentation for guidelines.
-New idea or improvement? Something not working right?
+New idea or improvement?
+Check out our feature request hub.
+
+
+Something not working right?
Open an Issue.
From 9fff4b060e06569ca77636643901aa42767e318d Mon Sep 17 00:00:00 2001
From: Bond_009
Date: Sun, 28 Jul 2019 23:53:19 +0200
Subject: [PATCH 29/36] Replace custom code with Asp.Net Core code
---
.../ApplicationHost.cs | 6 +-
.../HttpServer/FileWriter.cs | 218 +++---
.../HttpServer/HttpListenerHost.cs | 154 ++---
.../HttpServer/ResponseFilter.cs | 26 +-
.../HttpServer/Security/AuthService.cs | 48 +-
.../Services/HttpResult.cs | 9 +-
.../Services/ResponseHelper.cs | 31 +-
.../Services/ServiceController.cs | 4 -
.../Services/ServiceExec.cs | 2 +-
.../Services/ServiceHandler.cs | 103 +--
.../SocketSharp/RequestMono.cs | 647 ------------------
.../SocketSharp/WebSocketSharpRequest.cs | 232 +++----
.../SocketSharp/WebSocketSharpResponse.cs | 98 ---
.../Playback/BaseStreamingService.cs | 2 +-
.../Net/AuthenticatedAttribute.cs | 3 +-
.../Services/IHasRequestFilter.cs | 4 +-
MediaBrowser.Model/Services/IRequest.cs | 30 +-
17 files changed, 393 insertions(+), 1224 deletions(-)
delete mode 100644 Emby.Server.Implementations/SocketSharp/RequestMono.cs
delete mode 100644 Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index ef2f59d303..a89cf95d3b 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -676,7 +676,7 @@ namespace Emby.Server.Implementations
var localPath = context.Request.Path.ToString();
var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
- await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false);
+ await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
}
public static IStreamHelper StreamHelper { get; set; }
@@ -785,7 +785,7 @@ namespace Emby.Server.Implementations
HttpServer = new HttpListenerHost(
this,
- LoggerFactory,
+ LoggerFactory.CreateLogger(),
ServerConfigurationManager,
_configuration,
NetworkManager,
@@ -873,7 +873,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton(authContext);
serviceCollection.AddSingleton(new SessionContext(UserManager, authContext, SessionManager));
- AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, SessionManager, NetworkManager);
+ AuthService = new AuthService(authContext, ServerConfigurationManager, SessionManager, NetworkManager);
serviceCollection.AddSingleton(AuthService);
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index ec41cc0a91..2890cca7ce 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -1,50 +1,43 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Net;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
public class FileWriter : IHttpResult
{
+ private static readonly CultureInfo UsCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
+
+ private static readonly string[] _skipLogExtensions = {
+ ".js",
+ ".html",
+ ".css"
+ };
+
private readonly IStreamHelper _streamHelper;
- private ILogger Logger { get; set; }
+ private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
- private string RangeHeader { get; set; }
- private bool IsHeadRequest { get; set; }
-
- private long RangeStart { get; set; }
- private long RangeEnd { get; set; }
- private long RangeLength { get; set; }
- public long TotalContentLength { get; set; }
-
- public Action OnComplete { get; set; }
- public Action OnError { get; set; }
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public List Cookies { get; private set; }
-
- public FileShareMode FileShare { get; set; }
-
///
/// The _options
///
private readonly IDictionary _options = new Dictionary();
- ///
- /// Gets the options.
- ///
- /// The options.
- public IDictionary Headers => _options;
- public string Path { get; set; }
+ ///
+ /// The _requested ranges
+ ///
+ private List> _requestedRanges;
public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
{
@@ -57,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer
_fileSystem = fileSystem;
Path = path;
- Logger = logger;
+ _logger = logger;
RangeHeader = rangeHeader;
Headers[HeaderNames.ContentType] = contentType;
@@ -80,6 +73,88 @@ namespace Emby.Server.Implementations.HttpServer
Cookies = new List();
}
+ private string RangeHeader { get; set; }
+
+ private bool IsHeadRequest { get; set; }
+
+ private long RangeStart { get; set; }
+
+ private long RangeEnd { get; set; }
+
+ private long RangeLength { get; set; }
+
+ public long TotalContentLength { get; set; }
+
+ public Action OnComplete { get; set; }
+
+ public Action OnError { get; set; }
+
+ public List Cookies { get; private set; }
+
+ public FileShareMode FileShare { get; set; }
+
+ ///
+ /// Gets the options.
+ ///
+ /// The options.
+ public IDictionary Headers => _options;
+
+ public string Path { get; set; }
+
+ ///
+ /// Gets the requested ranges.
+ ///
+ /// The requested ranges.
+ protected List> RequestedRanges
+ {
+ get
+ {
+ if (_requestedRanges == null)
+ {
+ _requestedRanges = new List>();
+
+ // Example: bytes=0-,32-63
+ var ranges = RangeHeader.Split('=')[1].Split(',');
+
+ foreach (var range in ranges)
+ {
+ var vals = range.Split('-');
+
+ long start = 0;
+ long? end = null;
+
+ if (!string.IsNullOrEmpty(vals[0]))
+ {
+ start = long.Parse(vals[0], UsCulture);
+ }
+
+ if (!string.IsNullOrEmpty(vals[1]))
+ {
+ end = long.Parse(vals[1], UsCulture);
+ }
+
+ _requestedRanges.Add(new KeyValuePair(start, end));
+ }
+ }
+
+ return _requestedRanges;
+ }
+ }
+
+ public string ContentType { get; set; }
+
+ public IRequest RequestContext { get; set; }
+
+ public object Response { get; set; }
+
+ public int Status { get; set; }
+
+ public HttpStatusCode StatusCode
+ {
+ get => (HttpStatusCode)Status;
+ set => Status = (int)value;
+ }
+
///
/// Sets the range values.
///
@@ -106,59 +181,10 @@ namespace Emby.Server.Implementations.HttpServer
var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
Headers[HeaderNames.ContentRange] = rangeString;
- Logger.LogDebug("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+ _logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
}
- ///
- /// The _requested ranges
- ///
- private List> _requestedRanges;
- ///
- /// Gets the requested ranges.
- ///
- /// The requested ranges.
- protected List> RequestedRanges
- {
- get
- {
- if (_requestedRanges == null)
- {
- _requestedRanges = new List>();
-
- // Example: bytes=0-,32-63
- var ranges = RangeHeader.Split('=')[1].Split(',');
-
- foreach (var range in ranges)
- {
- var vals = range.Split('-');
-
- long start = 0;
- long? end = null;
-
- if (!string.IsNullOrEmpty(vals[0]))
- {
- start = long.Parse(vals[0], UsCulture);
- }
- if (!string.IsNullOrEmpty(vals[1]))
- {
- end = long.Parse(vals[1], UsCulture);
- }
-
- _requestedRanges.Add(new KeyValuePair(start, end));
- }
- }
-
- return _requestedRanges;
- }
- }
-
- private static readonly string[] SkipLogExtensions = {
- ".js",
- ".html",
- ".css"
- };
-
- public async Task WriteToAsync(IResponse response, CancellationToken cancellationToken)
+ public async Task WriteToAsync(HttpResponse response, CancellationToken cancellationToken)
{
try
{
@@ -176,16 +202,16 @@ namespace Emby.Server.Implementations.HttpServer
{
var extension = System.IO.Path.GetExtension(path);
- if (extension == null || !SkipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+ if (extension == null || !_skipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
- Logger.LogDebug("Transmit file {0}", path);
+ _logger.LogDebug("Transmit file {0}", path);
}
offset = 0;
count = 0;
}
- await response.TransmitFile(path, offset, count, FileShare, _fileSystem, _streamHelper, cancellationToken).ConfigureAwait(false);
+ await TransmitFile(response.Body, path, offset, count, FileShare, cancellationToken).ConfigureAwait(false);
}
finally
{
@@ -193,18 +219,32 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public string ContentType { get; set; }
-
- public IRequest RequestContext { get; set; }
-
- public object Response { get; set; }
-
- public int Status { get; set; }
-
- public HttpStatusCode StatusCode
+ public async Task TransmitFile(Stream stream, string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{
- get => (HttpStatusCode)Status;
- set => Status = (int)value;
+ var fileOpenOptions = FileOpenOptions.SequentialScan;
+
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileOpenOptions |= FileOpenOptions.Asynchronous;
+ }
+
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
+ {
+ if (offset > 0)
+ {
+ fs.Position = offset;
+ }
+
+ if (count > 0)
+ {
+ await _streamHelper.CopyToAsync(fs, stream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await fs.CopyToAsync(stream, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index d8938964fa..4c233456c4 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
@@ -30,11 +29,7 @@ namespace Emby.Server.Implementations.HttpServer
{
public class HttpListenerHost : IHttpServer, IDisposable
{
- private string DefaultRedirectPath { get; set; }
- public string[] UrlPrefixes { get; private set; }
-
- public event EventHandler> WebSocketConnected;
-
+ private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
private readonly IServerApplicationHost _appHost;
@@ -42,18 +37,15 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IXmlSerializer _xmlSerializer;
private readonly IHttpListener _socketListener;
private readonly Func> _funcParseFn;
-
- public Action[] ResponseFilters { get; set; }
-
+ private readonly string _defaultRedirectPath;
private readonly Dictionary ServiceOperationsMap = new Dictionary();
- public static HttpListenerHost Instance { get; protected set; }
-
private IWebSocketListener[] _webSocketListeners = Array.Empty();
private readonly List _webSocketConnections = new List();
+ private bool _disposed = false;
public HttpListenerHost(
IServerApplicationHost applicationHost,
- ILoggerFactory loggerFactory,
+ ILogger logger,
IServerConfigurationManager config,
IConfiguration configuration,
INetworkManager networkManager,
@@ -62,9 +54,9 @@ namespace Emby.Server.Implementations.HttpServer
IHttpListener socketListener)
{
_appHost = applicationHost;
- Logger = loggerFactory.CreateLogger("HttpServer");
+ _logger = logger;
_config = config;
- DefaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
+ _defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
_networkManager = networkManager;
_jsonSerializer = jsonSerializer;
_xmlSerializer = xmlSerializer;
@@ -74,12 +66,20 @@ namespace Emby.Server.Implementations.HttpServer
_funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
Instance = this;
- ResponseFilters = Array.Empty>();
+ ResponseFilters = Array.Empty>();
}
+ public Action[] ResponseFilters { get; set; }
+
+ public static HttpListenerHost Instance { get; protected set; }
+
+ public string[] UrlPrefixes { get; private set; }
+
public string GlobalResponse { get; set; }
- protected ILogger Logger { get; }
+ public ServiceController ServiceController { get; private set; }
+
+ public event EventHandler> WebSocketConnected;
public object CreateInstance(Type type)
{
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.HttpServer
/// and no more processing should be done.
///
///
- public void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
+ public void ApplyRequestFilters(IRequest req, HttpResponse res, object requestDto)
{
//Exec all RequestFilter attributes with Priority < 0
var attributes = GetRequestFilterAttributes(requestDto.GetType());
@@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, Logger)
+ var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
{
OnReceive = ProcessWebSocketMessageReceived,
Url = e.Url,
@@ -215,16 +215,16 @@ namespace Emby.Server.Implementations.HttpServer
if (logExceptionStackTrace)
{
- Logger.LogError(ex, "Error processing request");
+ _logger.LogError(ex, "Error processing request");
}
else if (logExceptionMessage)
{
- Logger.LogError(ex.Message);
+ _logger.LogError(ex.Message);
}
var httpRes = httpReq.Response;
- if (httpRes.OriginalResponse.HasStarted)
+ if (httpRes.HasStarted)
{
return;
}
@@ -233,11 +233,11 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.StatusCode = statusCode;
httpRes.ContentType = "text/html";
- await Write(httpRes, NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
+ await httpRes.WriteAsync(NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
}
catch (Exception errorEx)
{
- Logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
+ _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
}
}
@@ -431,7 +431,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 503;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Server shutting down").ConfigureAwait(false);
+ await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false);
return;
}
@@ -439,7 +439,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 400;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Invalid host").ConfigureAwait(false);
+ await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false);
return;
}
@@ -447,7 +447,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 403;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Forbidden").ConfigureAwait(false);
+ await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false);
return;
}
@@ -460,28 +460,27 @@ namespace Emby.Server.Implementations.HttpServer
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
httpRes.StatusCode = 200;
- httpRes.AddHeader("Access-Control-Allow-Origin", "*");
- httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
- httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
+ httpRes.Headers.Add("Access-Control-Allow-Origin", "*");
+ httpRes.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+ httpRes.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
httpRes.ContentType = "text/plain";
- await Write(httpRes, string.Empty).ConfigureAwait(false);
+ await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false);
return;
}
urlToLog = GetUrlToLog(urlString);
- Logger.LogDebug("HTTP {HttpMethod} {Url} UserAgent: {UserAgent} \nHeaders: {@Headers}", urlToLog, httpReq.UserAgent ?? string.Empty, httpReq.HttpMethod, httpReq.Headers);
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, DefaultRedirectPath);
+ httpRes.Redirect(_defaultRedirectPath);
return;
}
if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, "emby/" + DefaultRedirectPath);
+ httpRes.Redirect("emby/" + _defaultRedirectPath);
return;
}
@@ -494,9 +493,10 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{
- await Write(httpRes,
+ await httpRes.WriteAsync(
"EmbyPlease update your Emby bookmark to " + newUrl + "").ConfigureAwait(false);
+ newUrl + "\">" + newUrl + "