Skip to content
Merged
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
72 changes: 72 additions & 0 deletions Tests/SocketTests/SocketOptionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using nanoFramework.TestFramework;
using System;
using System.Net.Sockets;

namespace NFUnitTestSocketTests
{
[TestClass]
public class SocketOptionsTests
{
[Setup]
public void SetupConnectToEthernetTests()
{
// Comment next line to run the tests on a real hardware
Assert.SkipTest("Skipping tests using nanoCLR Win32 in a pipeline");
}

[TestMethod]
public void SocketGetSocketOptions_00()
{
SocketType socketType = SocketType.Stream;

Socket testSocket = new(
AddressFamily.InterNetwork,
socketType,
ProtocolType.Tcp);

Assert.Throws(typeof(NotSupportedException), () =>
{
testSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AddMembership);
}, "Getting SocketOptionName.AddMembership should have thrown an exception");

Assert.Throws(typeof(NotSupportedException), () =>
{
testSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DropMembership);
}, "Getting SocketOptionName.DropMembership should have thrown an exception");

Assert.True((SocketType)testSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Type) == socketType, "Getting SocketOptionName.Type returned a different type.");

testSocket?.Close();
}

[TestMethod]
public void SocketLinger()
{
SocketType socketType = SocketType.Stream;

Socket testSocket = new(
AddressFamily.InterNetwork,
socketType,
ProtocolType.Tcp);

// TODO
// connect to endpoint

// get linger option
//Assert.IsType(typeof(bool), testSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger), "SocketOptionName.DontLinger should return a bool.");

// set DontLinger option
// read back linger option
// set LINGER value

// read back linger option

testSocket?.Close();
}
}
}
1 change: 1 addition & 0 deletions Tests/SocketTests/SocketTests.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<RunSettingsFilePath>$(MSBuildProjectDirectory)\nano.runsettings</RunSettingsFilePath>
</PropertyGroup>
<ItemGroup>
<Compile Include="SocketOptionsTests.cs" />
<Compile Include="SocketPair.cs" />
<Compile Include="SocketExceptionsTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
53 changes: 37 additions & 16 deletions nanoFramework.System.Net/Sockets/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,8 @@ public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP)
/// <para><see cref="Socket"/> options determine the behavior of the current <see cref="Socket"/>. For an option with a Boolean data type, specify a nonzero value to enable the option, and a
/// zero value to disable the option. For an option with an integer data type, specify the appropriate value. <see cref="Socket"/> options are grouped by level of protocol support.
/// </para>
/// For <see cref="SocketOptionName.Linger"/> option the <paramref name="optionValue"/> it's the number of seconds that the socket will linger before closing the connection.
/// To disable socket linger call <see cref="SetSocketOption(SocketOptionLevel,SocketOptionName,bool)"/> with <see cref="SocketOptionName.DontLinger"/> and setting it to <see langword="true"/>.
/// </remarks>
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
{
Expand Down Expand Up @@ -931,32 +933,33 @@ public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName opti
/// <param name="optionLevel">One of the <see cref="SocketOptionLevel"/> values.</param>
/// <param name="optionName">One of the <see cref="SocketOptionName"/> values.</param>
/// <returns>
/// An object that represents the value of the option. When the optionName parameter is set to <see cref="SocketOptionName.Linger"/> the return value is an instance of the LingerOption
/// class. When optionName is set to <see cref="SocketOptionName.AddMembership"/> or <see cref="SocketOptionName.DropMembership"/>, the return value is an instance of the MulticastOption class. When optionName is
/// any other value, the return value is an integer.
/// <para>/// An object that represents the value of the option.</para>
/// <para>
/// When the <paramref name="optionName"/> parameter is set to <see cref="SocketOptionName.Linger"/> the return value is an <see cref="int"/> with the value in seconds that the socket will linger after close.
/// To check if linger is enabled for the socket the <see cref="SocketOptionName.DontLinger"/> option should be queried.
/// </para>
/// <para>
/// When optionName is set to <see cref="SocketOptionName.ExclusiveAddressUse"/>, <see cref="SocketOptionName.DontLinger"/>, <see cref="SocketOptionName.AcceptConnection"/>, <see cref="SocketOptionName.Broadcast"/> or <see cref="SocketOptionName.KeepAlive"/>, the return value is <see cref="bool"/>.
/// </para>
/// <para>
/// When optionName is any other value, the return value is an integer.
/// </para>
/// </returns>
/// <remarks>
/// <see cref="Socket"/> options determine the behavior of the current <see cref="Socket"/>. Use this overload to get the <see cref="SocketOptionName.Linger"/>, <see cref="SocketOptionName.AddMembership"/>, and <see cref="SocketOptionName.DropMembership"/> options.
/// For the <see cref="SocketOptionName.Linger"/> option, use <see cref="Socket"/> for the optionLevel parameter. For <see cref="SocketOptionName.AddMembership"/> and <see cref="SocketOptionName.DropMembership"/>, use <see cref="SocketOptionLevel.IP"/>. If you want to set the value of any of
/// the options listed above, use the <see cref="SetSocketOption(SocketOptionLevel, SocketOptionName, Int32)"/> method.
/// </remarks>
/// <exception cref="NotSupportedException">When using an <see cref="SocketOptionName"/> that can't be retrieved.</exception>
public object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName)
{
if (optionName == SocketOptionName.DontLinger ||
optionName == SocketOptionName.AddMembership ||
optionName == SocketOptionName.DropMembership)
if (optionName is SocketOptionName.AddMembership
or SocketOptionName.DropMembership)
{
//special case linger?
throw new NotSupportedException();
}

// socket options that don't require any request to the native end
if(optionLevel == SocketOptionLevel.Socket)
if (optionLevel == SocketOptionLevel.Socket
&& optionName == SocketOptionName.Type)
{
if(optionName == SocketOptionName.Type)
{
return _socketType;
}
return _socketType;
}

// reached here: have to make a request to the lower level to get it
Expand All @@ -965,6 +968,24 @@ public object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName op

GetSocketOption(optionLevel, optionName, val);

// process specific options
if (optionName is
SocketOptionName.ExclusiveAddressUse or
SocketOptionName.DontLinger)
{
// these are boolean AND negated
return val[0] == 0;
}
else if (optionName is
SocketOptionName.AcceptConnection or
SocketOptionName.Broadcast or
SocketOptionName.KeepAlive)
{
// these are boolean
return val[0] == 1;
}

// all the others are integers
int iVal = (val[0] << 0) | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);

return iVal;
Expand Down