Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ For dev or build tags, use the same logical version string embedded in the tag.

## [Unreleased]

- Listener IP and port changes no longer report a reconnect requirement after
Soulseek.NET has already rebound the live listeners and advertised the new
endpoint to the Soulseek server.
- Live Soulseek listener changes now apply updated type-1 obfuscation options
before rebinding, keeping the obfuscated socket and advertised metadata on
the configured port instead of the previous one.
- The web footer and README now offer direct PayPal and Ko-fi links for
supporting slskdN development.
- GitLab CI configuration now keeps the Arch package-smoke sudoers command as
Expand Down
2 changes: 0 additions & 2 deletions src/slskd/Core/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2546,7 +2546,6 @@ public class SoulseekOptions
[EnvironmentVariable("SLSK_LISTEN_IP_ADDRESS")]
[Description("local IP address on which to listen for incoming connections")]
[IPAddress]
[RequiresReconnect]
public string ListenIpAddress { get; init; } = "0.0.0.0";

/// <summary>
Expand All @@ -2556,7 +2555,6 @@ public class SoulseekOptions
[EnvironmentVariable("SLSK_LISTEN_PORT")]
[Description("port on which to listen for incoming connections")]
[Range(1024, 65535)]
[RequiresReconnect]
public int ListenPort { get; init; } = 50300;

/// <summary>
Expand Down
11 changes: 7 additions & 4 deletions tests/slskd.Tests.Unit/Core/ApplicationLifecycleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,10 @@ public void Dispose_UnsubscribesGlobalAndSoulseekEvents()
soulseekClient.VerifyRemove(x => x.ExcludedSearchPhrasesReceived -= It.IsAny<EventHandler<IReadOnlyCollection<string>>>(), Times.Once);
}

[Fact]
public async Task OptionsChanged_WhenListenPortChangesWhileConnected_SetsPendingReconnect()
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task OptionsChanged_WhenListenerReconfigurationSucceeds_DoesNotSetPendingReconnect(bool changeIpAddress)
{
var optionsMonitor = new TestOptionsMonitor<Options>(new Options());
var applicationState = new ManagedState<State>();
Expand All @@ -199,13 +201,14 @@ public async Task OptionsChanged_WhenListenPortChangesWhileConnected_SetsPending
{
Soulseek = new Options.SoulseekOptions
{
ListenPort = 50301,
ListenIpAddress = changeIpAddress ? "0.0.0.1" : "0.0.0.0",
ListenPort = changeIpAddress ? 50300 : 50301,
},
});

await reconfigured.Task.WaitAsync(TimeSpan.FromSeconds(5));

Assert.True(applicationState.CurrentValue.PendingReconnect);
Assert.False(applicationState.CurrentValue.PendingReconnect);
application.Dispose();
}

Expand Down
17 changes: 14 additions & 3 deletions vendor/slskNet.Runtime/src/SoulseekClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4612,8 +4612,17 @@ private async Task<bool> ReconfigureOptionsInternalAsync(SoulseekClientOptionsPa
var listenAddressChanged = patch.ListenIPAddress != null && !patch.ListenIPAddress.Equals(Options.ListenIPAddress);
var listenPortChanged = patch.ListenPort.HasValue && patch.ListenPort.Value != Options.ListenPort;
var incomingConnectionOptionsChanged = patch.IncomingConnectionOptions != null && patch.IncomingConnectionOptions != Options.IncomingConnectionOptions;

if (enableListenerChanged || listenAddressChanged || listenPortChanged || incomingConnectionOptionsChanged)
var peerObfuscationOptionsChanged = patch.PeerObfuscationOptions != null &&
(patch.PeerObfuscationOptions.Enabled != Options.PeerObfuscationOptions.Enabled ||
patch.PeerObfuscationOptions.ListenPort != Options.PeerObfuscationOptions.ListenPort ||
patch.PeerObfuscationOptions.Type != Options.PeerObfuscationOptions.Type ||
patch.PeerObfuscationOptions.AdvertiseRegularPort != Options.PeerObfuscationOptions.AdvertiseRegularPort ||
patch.PeerObfuscationOptions.PreferOutbound != Options.PeerObfuscationOptions.PreferOutbound);
var peerObfuscationListenerChanged = peerObfuscationOptionsChanged &&
(patch.PeerObfuscationOptions.Enabled != Options.PeerObfuscationOptions.Enabled ||
patch.PeerObfuscationOptions.ListenPort != Options.PeerObfuscationOptions.ListenPort);

if (enableListenerChanged || listenAddressChanged || listenPortChanged || incomingConnectionOptionsChanged || peerObfuscationListenerChanged)
{
var wasListening = Listener?.Listening ?? false;

Expand All @@ -4626,7 +4635,8 @@ private async Task<bool> ReconfigureOptionsInternalAsync(SoulseekClientOptionsPa
enableListener: patch.EnableListener,
listenIPAddress: patch.ListenIPAddress,
listenPort: patch.ListenPort,
incomingConnectionOptions: patch.IncomingConnectionOptions);
incomingConnectionOptions: patch.IncomingConnectionOptions,
peerObfuscationOptions: patch.PeerObfuscationOptions);

if (wasListening && Options.EnableListener)
{
Expand Down Expand Up @@ -4664,6 +4674,7 @@ private async Task<bool> ReconfigureOptionsInternalAsync(SoulseekClientOptionsPa
peerConnectionOptions: patch.PeerConnectionOptions,
transferConnectionOptions: patch.TransferConnectionOptions,
incomingConnectionOptions: patch.IncomingConnectionOptions,
peerObfuscationOptions: patch.PeerObfuscationOptions,
distributedConnectionOptions: patch.DistributedConnectionOptions,
userEndPointCache: patch.UserEndPointCache,
searchResponseResolver: patch.SearchResponseResolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,53 @@ public async Task Reconfigures_Listener_If_ListenPort_Changed()
}
}

[Trait("Category", "ReconfigureOptions")]
[Fact(DisplayName = "Reconfigures obfuscated listener and metadata if listen ports changed")]
public async Task Reconfigures_Obfuscated_Listener_And_Metadata_If_Listen_Ports_Changed()
{
var regularPort = GetAvailablePort();
var oldObfuscatedPort = GetAvailablePort();
while (oldObfuscatedPort == regularPort)
{
oldObfuscatedPort = GetAvailablePort();
}

var newRegularPort = GetAvailablePort();
while (newRegularPort == regularPort || newRegularPort == oldObfuscatedPort)
{
newRegularPort = GetAvailablePort();
}

var newObfuscatedPort = GetAvailablePort();
while (newObfuscatedPort == regularPort || newObfuscatedPort == oldObfuscatedPort || newObfuscatedPort == newRegularPort)
{
newObfuscatedPort = GetAvailablePort();
}

var oldObfuscation = new PeerObfuscationOptions(enabled: true, listenPort: oldObfuscatedPort);
var newObfuscation = new PeerObfuscationOptions(enabled: true, listenPort: newObfuscatedPort, preferOutbound: true);
var (client, mocks) = GetFixture(new SoulseekClientOptions(
listenPort: regularPort,
peerObfuscationOptions: oldObfuscation));

mocks.Listener.Setup(m => m.Listening).Returns(true);
var patch = new SoulseekClientOptionsPatch(
listenPort: newRegularPort,
peerObfuscationOptions: newObfuscation);

using (client)
{
client.SetProperty("State", SoulseekClientStates.Connected | SoulseekClientStates.LoggedIn);

await client.ReconfigureOptionsAsync(patch);

Assert.Equal(newRegularPort, client.Listener.Port);
Assert.NotNull(client.ObfuscatedListener);
Assert.Equal(newObfuscatedPort, client.ObfuscatedListener.Port);
Assert.Same(newObfuscation, client.Options.PeerObfuscationOptions);
}
}

[Trait("Category", "ReconfigureOptions")]
[Fact(DisplayName = "Reconfigures listener if ListenIPAddress changed")]
public async Task Reconfigures_Listener_If_ListenIPAddress_Changed()
Expand Down
Loading