Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache for Socket.LocalEndPoint #39313

Merged
merged 28 commits into from
Sep 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2e977ea
Add cache for LocalEndPoint
CarnaViire Jul 14, 2020
579f788
Add RightEndPoint property, clear _localEndPoint in RightEndPoint setter
CarnaViire Jul 14, 2020
bc08140
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Jul 14, 2020
c68e608
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Jul 20, 2020
3771a6d
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Jul 23, 2020
d953b0f
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Jul 23, 2020
f0a5ec9
Roll back property changes
CarnaViire Jul 23, 2020
999d596
Fix _nonBlockingConnectRightEndPoint
CarnaViire Jul 23, 2020
79b7153
Merge branch 'master' into issue-1482
CarnaViire Jul 31, 2020
d715a31
Add clear on error
CarnaViire Aug 4, 2020
c3eb4ec
Add clear on connect and tests
CarnaViire Aug 5, 2020
324e060
Add caching test
CarnaViire Aug 5, 2020
283f11b
Use BindToAnonymousPort
CarnaViire Aug 11, 2020
0a6a26a
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 11, 2020
1ff3e14
Fix typo
CarnaViire Aug 11, 2020
40f872e
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 11, 2020
09b42c0
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 12, 2020
24e1b66
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 18, 2020
ec8e54e
Assign _localEndPoint from the listener
CarnaViire Aug 18, 2020
3d9385b
tmp commit to check on mac
CarnaViire Aug 24, 2020
4e183ed
tmp
CarnaViire Aug 24, 2020
e626406
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 24, 2020
74988a2
Merge branch 'master' into issue-1482
CarnaViire Aug 25, 2020
eeb057d
Fix _localEndPoint clearing on mac
CarnaViire Aug 25, 2020
85de50d
Inline wildcard addresses
CarnaViire Aug 26, 2020
b86cc93
Merge remote-tracking branch 'upstream/master' into issue-1482
CarnaViire Aug 26, 2020
cbaed88
PR fixes
CarnaViire Aug 27, 2020
d0fa759
Rewrite tests with SocketTestHelperBase
CarnaViire Sep 1, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ partial void WildcardBindForConnectIfNecessary(AddressFamily addressFamily)
switch (addressFamily)
{
case AddressFamily.InterNetwork:
address = IsDualMode ? IPAddress.Any.MapToIPv6() : IPAddress.Any;
address = IsDualMode ? s_IPAddressAnyMapToIPv6 : IPAddress.Any;
break;

case AddressFamily.InterNetworkV6:
Expand Down
81 changes: 71 additions & 10 deletions src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ public partial class Socket : IDisposable
{
internal const int DefaultCloseTimeout = -1; // NOTE: changing this default is a breaking change.

private static readonly IPAddress s_IPAddressAnyMapToIPv6 = IPAddress.Any.MapToIPv6();

private SafeSocketHandle _handle;

// _rightEndPoint is null if the socket has not been bound. Otherwise, it is any EndPoint of the
// correct type (IPEndPoint, etc).
internal EndPoint? _rightEndPoint;
internal EndPoint? _remoteEndPoint;

// Cached LocalEndPoint value. Cleared on disconnect and error. Cached wildcard addresses are
// also cleared on connect and accept.
private EndPoint? _localEndPoint;

// These flags monitor if the socket was ever connected at any time and if it still is.
private bool _isConnected;
private bool _isDisconnected;
Expand Down Expand Up @@ -317,6 +323,7 @@ public EndPoint? LocalEndPoint
// Update the state if we've become connected after a non-blocking connect.
_isConnected = true;
_rightEndPoint = _nonBlockingConnectRightEndPoint;
UpdateLocalEndPointOnConnect();
_nonBlockingConnectInProgress = false;
}

Expand All @@ -325,23 +332,27 @@ public EndPoint? LocalEndPoint
return null;
}

Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(_rightEndPoint);

unsafe
if (_localEndPoint == null)
{
fixed (byte* buffer = socketAddress.Buffer)
fixed (int* bufferSize = &socketAddress.InternalSize)
Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(_rightEndPoint);

unsafe
{
// This may throw ObjectDisposedException.
SocketError errorCode = SocketPal.GetSockName(_handle, buffer, bufferSize);
if (errorCode != SocketError.Success)
fixed (byte* buffer = socketAddress.Buffer)
fixed (int* bufferSize = &socketAddress.InternalSize)
{
UpdateStatusAfterSocketErrorAndThrowException(errorCode);
// This may throw ObjectDisposedException.
SocketError errorCode = SocketPal.GetSockName(_handle, buffer, bufferSize);
if (errorCode != SocketError.Success)
{
UpdateStatusAfterSocketErrorAndThrowException(errorCode);
}
}
}
_localEndPoint = _rightEndPoint.Create(socketAddress);
CarnaViire marked this conversation as resolved.
Show resolved Hide resolved
}

return _rightEndPoint.Create(socketAddress);
return _localEndPoint;
}
}

Expand All @@ -359,6 +370,7 @@ public EndPoint? RemoteEndPoint
// Update the state if we've become connected after a non-blocking connect.
_isConnected = true;
_rightEndPoint = _nonBlockingConnectRightEndPoint;
UpdateLocalEndPointOnConnect();
_nonBlockingConnectInProgress = false;
}

Expand Down Expand Up @@ -470,6 +482,7 @@ public bool Connected
// Update the state if we've become connected after a non-blocking connect.
_isConnected = true;
_rightEndPoint = _nonBlockingConnectRightEndPoint;
UpdateLocalEndPointOnConnect();
_nonBlockingConnectInProgress = false;
}

Expand Down Expand Up @@ -2303,6 +2316,7 @@ private void DoBeginDisconnect(bool reuseSocket, DisconnectOverlappedAsyncResult
{
SetToDisconnected();
_remoteEndPoint = null;
_localEndPoint = null;
}

if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"UnsafeNclNativeMethods.OSSOCK.DisConnectEx returns:{errorCode}");
Expand Down Expand Up @@ -2332,6 +2346,7 @@ public void Disconnect(bool reuseSocket)

SetToDisconnected();
_remoteEndPoint = null;
_localEndPoint = null;
}

// Routine Description:
Expand Down Expand Up @@ -2760,6 +2775,7 @@ private void DoBeginSendTo(byte[] buffer, int offset, int size, SocketFlags sock
catch (ObjectDisposedException)
{
_rightEndPoint = oldEndPoint;
_localEndPoint = null;
throw;
}

Expand All @@ -2769,6 +2785,7 @@ private void DoBeginSendTo(byte[] buffer, int offset, int size, SocketFlags sock
UpdateSendSocketErrorForDisposed(ref errorCode);
// Update the internal state of this socket according to the error before throwing.
_rightEndPoint = oldEndPoint;
_localEndPoint = null;

throw new SocketException((int)errorCode);
}
Expand Down Expand Up @@ -3148,6 +3165,7 @@ public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size,
catch (ObjectDisposedException)
{
_rightEndPoint = oldEndPoint;
_localEndPoint = null;
throw;
}

Expand All @@ -3157,6 +3175,7 @@ public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size,
{
// Update the internal state of this socket according to the error before throwing.
_rightEndPoint = oldEndPoint;
_localEndPoint = null;

throw new SocketException((int)errorCode);
}
Expand Down Expand Up @@ -3357,6 +3376,7 @@ private void DoBeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags
catch (ObjectDisposedException)
{
_rightEndPoint = oldEndPoint;
_localEndPoint = null;
throw;
}

Expand All @@ -3366,6 +3386,7 @@ private void DoBeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags
{
// Update the internal state of this socket according to the error before throwing.
_rightEndPoint = oldEndPoint;
_localEndPoint = null;

throw new SocketException((int)errorCode);
}
Expand Down Expand Up @@ -3762,6 +3783,7 @@ private bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket)
catch
{
_rightEndPoint = oldEndPoint;
_localEndPoint = null;

// Clear in-use flag on event args object.
e.Complete();
Expand Down Expand Up @@ -4091,6 +4113,7 @@ public bool SendToAsync(SocketAsyncEventArgs e)
catch
{
_rightEndPoint = null;
_localEndPoint = null;
// Clear in-use flag on event args object.
e.Complete();
throw;
Expand All @@ -4099,6 +4122,7 @@ public bool SendToAsync(SocketAsyncEventArgs e)
if (!CheckErrorAndUpdateStatus(socketError))
{
_rightEndPoint = oldEndPoint;
_localEndPoint = null;
}

return socketError == SocketError.IOPending;
Expand Down Expand Up @@ -4610,6 +4634,7 @@ private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCa
{
// _rightEndPoint will always equal oldEndPoint.
_rightEndPoint = oldEndPoint;
_localEndPoint = null;
throw;
}

Expand All @@ -4626,6 +4651,7 @@ private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCa
UpdateConnectSocketErrorForDisposed(ref errorCode);
// Update the internal state of this socket according to the error before throwing.
_rightEndPoint = oldEndPoint;
_localEndPoint = null;

throw new SocketException((int)errorCode);
}
Expand Down Expand Up @@ -4849,6 +4875,12 @@ internal Socket UpdateAcceptSocket(Socket socket, EndPoint remoteEP)
socket._rightEndPoint = _rightEndPoint;
socket._remoteEndPoint = remoteEP;

// If the listener socket was bound to a wildcard address, then the `accept` system call
// will assign a specific address to the accept socket's local endpoint instead of a
// wildcard address. In that case we should not copy listener's wildcard local endpoint.

socket._localEndPoint = !IsWildcardEndPoint(_localEndPoint) ? _localEndPoint : null;

// The socket is connected.
socket.SetToConnected();

Expand Down Expand Up @@ -4880,9 +4912,38 @@ internal void SetToConnected()
// some point in time update the perf counter as well.
_isConnected = true;
_isDisconnected = false;
UpdateLocalEndPointOnConnect();
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "now connected");
}

private void UpdateLocalEndPointOnConnect()
{
// If the client socket was bound to a wildcard address, then the `connect` system call
// will assign a specific address to the client socket's local endpoint instead of a
// wildcard address. In that case we should clear the cached wildcard local endpoint.

if (IsWildcardEndPoint(_localEndPoint))
{
_localEndPoint = null;
}
}

private bool IsWildcardEndPoint(EndPoint? endPoint)
{
if (endPoint == null)
{
return false;
}

if (endPoint is IPEndPoint ipEndpoint)
{
IPAddress address = ipEndpoint.Address;
return IPAddress.Any.Equals(address) || IPAddress.IPv6Any.Equals(address) || s_IPAddressAnyMapToIPv6.Equals(address);
}

return false;
}

internal void SetToDisconnected()
{
if (!_isConnected)
Expand Down
Loading