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

Set of offset-based APIs for thread-safe file IO #53669

Merged
merged 74 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
d37d1ee
move logic related to opening and initializing handle from FileStream…
adamsitnik May 27, 2021
539393d
move the arguments validation logic common for FileStream ctor and Fi…
adamsitnik May 27, 2021
b60e876
introduce File.OpenHandle
adamsitnik May 27, 2021
c61d639
fix the new tests
adamsitnik May 28, 2021
ad252de
FileStream created from a handle should allow for bufferSize == 0
adamsitnik May 28, 2021
1540dba
File.OpenHandle should always use full path
adamsitnik May 28, 2021
d8a3113
fix a bug in NtCreateFile mapping logic
adamsitnik May 28, 2021
02cd564
always use NtCreateFile for SafeFileHandle.Open
adamsitnik May 28, 2021
1430dd6
move the ThreadPoolBinding initialization logic to one place
adamsitnik May 28, 2021
ebaa92a
IsAsync: use syscall when not provided and validate it early
adamsitnik May 28, 2021
fbbcd4d
read all FileOptions, not just FileOptions.Asynchronous
adamsitnik May 28, 2021
7f94f85
move IsPipe CanSeek to SafeFileHandle as well (the new APIs like Rand…
adamsitnik May 28, 2021
33ecb8d
disable the Append test as it's currently not supported by design
adamsitnik May 28, 2021
f1af8f6
expose SafeFileHandle.IsAsync and write a test for it
adamsitnik May 28, 2021
a46da91
fix compilation errors on Linux
adamsitnik May 31, 2021
9ef23eb
don't try to test DeleteOnClose for FileStreams created from handle a…
adamsitnik May 31, 2021
485eb93
take advantage of knowing the file type and avoid one syscall for Can…
adamsitnik May 31, 2021
c8818aa
revert some ordering changes to make the code easier to review
adamsitnik May 31, 2021
dc13de0
Apply suggestions from code review
adamsitnik May 31, 2021
6c58252
add missing ;
adamsitnik May 31, 2021
fb24f5c
simplify Windows implementation:
adamsitnik May 31, 2021
8baf0bd
unify CanSeek and IsPipe for the .NET 5 Windows strategy as well
adamsitnik May 31, 2021
50aba1f
move the !MS_IO_REDIST methods from `File.cs` to `File.netcoreapp.cs`…
adamsitnik May 31, 2021
143d31c
RandomAccess: GetLength, Read and Write single buffer
adamsitnik May 31, 2021
1d41d65
fix Unix build
adamsitnik May 31, 2021
2d8ac90
refactor the tests
adamsitnik Jun 1, 2021
bbbd267
ReadAsync and WriteAsync
adamsitnik Jun 1, 2021
46d9b6f
move AsyncWindowsFileStreamStrategy.ValueTaskSource to SafeFileHandle
adamsitnik Jun 1, 2021
a946c5d
ReadScatter and WriteGather
adamsitnik Jun 1, 2021
4f807ef
some polishing
adamsitnik Jun 1, 2021
638e67a
ReadScatterAsync and WriteGatherAsync
adamsitnik Jun 1, 2021
fe8fbd1
use ReadFileScatter and WriteFileGather when possible
adamsitnik Jun 1, 2021
381776b
complete Unix implementation
adamsitnik Jun 3, 2021
1febba1
add tests for handling already cancelled tokens
adamsitnik Jun 3, 2021
8db3f7a
add tests for unauthorized access
adamsitnik Jun 3, 2021
f33d4ca
some polishing before sending PR
adamsitnik Jun 3, 2021
f8c8423
always treat EOF as success with 0 bytes read (read at end of file)
adamsitnik Jun 3, 2021
2126f15
simplify the NoBuffering tests logic
adamsitnik Jun 3, 2021
e613e72
handle lack of preadv pwritev on OSX
adamsitnik Jun 3, 2021
73f0751
fix the Linux build
adamsitnik Jun 3, 2021
940609c
Apply suggestions from code review
adamsitnik Jun 7, 2021
891c2b3
code review fixes and suggestions
adamsitnik Jun 7, 2021
e462d49
Unix fixes
adamsitnik Jun 7, 2021
253faa1
skip the test that uses System.IO.Pipes for Browser (it's not supported)
adamsitnik Jun 7, 2021
fd86735
remove the invalid assumption that every file file opened from path m…
adamsitnik Jun 7, 2021
6241b08
support ReadFileScatter and WriteFileGather on 32-bit systems as we d…
adamsitnik Jun 7, 2021
648ab9b
move the unpinning to finally block
adamsitnik Jun 7, 2021
e075441
update the comment
adamsitnik Jun 7, 2021
b1d3006
move the call to Dispose to the catch block
adamsitnik Jun 7, 2021
98eaf24
InitThreadPoolBindingIfNeeded can dispose the handle only if we own it
adamsitnik Jun 7, 2021
76a4326
when 0 is allowed, the exception message should ask for non-negative …
adamsitnik Jun 7, 2021
dcd9e12
fix the casting compilation error
adamsitnik Jun 7, 2021
2b6a555
don't make ownsHandle a protected field as it would become a part of …
adamsitnik Jun 7, 2021
4a6bb62
move IOVector from pal_networking.h to pal_io.h and use it in pal_io.…
adamsitnik Jun 7, 2021
5ec9e1f
don't use nullable field to store canSeek information. Store the file…
adamsitnik Jun 7, 2021
4d002b2
update outdated debug assert
adamsitnik Jun 7, 2021
d5c9229
Revert "don't use nullable field to store canSeek information. Store …
adamsitnik Jun 8, 2021
994b112
CanSeek should be thread-safe
adamsitnik Jun 8, 2021
9405abe
add more debug asserts to try to see why two CI legs have failed with…
adamsitnik Jun 8, 2021
752ff9d
fix invalid link (it was pointing to a closed duplicate)
adamsitnik Jun 8, 2021
e609c06
async File IO is not supported on Windows for Mono
adamsitnik Jun 8, 2021
5ae1dfb
async file IO is not supported on browser
adamsitnik Jun 8, 2021
d4e5b09
fix WASM build
adamsitnik Jun 9, 2021
abc4b14
don't use preadv and pwritev on WASM as WASM implementation has bugs
adamsitnik Jun 9, 2021
043a926
Merge remote-tracking branch 'upstream/main' into randomAcess
adamsitnik Jun 9, 2021
fc76167
fix a typo
adamsitnik Jun 9, 2021
93db089
Merge remote-tracking branch 'upstream/main' into randomAcess
adamsitnik Jun 10, 2021
1014688
add missing CreateFileW default flags
adamsitnik Jun 10, 2021
fde8c34
Merge remote-tracking branch 'upstream/main' into randomAcess
adamsitnik Jun 10, 2021
05327b1
reduce code duplication
adamsitnik Jun 11, 2021
05e65eb
Apply suggestions from code review
adamsitnik Jun 11, 2021
c87354c
address code review feedback
adamsitnik Jun 11, 2021
f80bbb7
Apply suggestions from code review
adamsitnik Jun 15, 2021
07051fa
address code review feedback
adamsitnik Jun 15, 2021
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
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

internal static partial class Interop
{
internal static partial class Sys
{
internal unsafe struct IOVector
{
public byte* Base;
public UIntPtr Count;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: nuint

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ internal static partial class Interop
{
internal static partial class Sys
{
internal unsafe struct IOVector
{
public byte* Base;
public UIntPtr Count;
}

internal unsafe struct MessageHeader
{
public byte* SocketAddress;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PRead", SetLastError = true)]
internal static extern unsafe int PRead(SafeHandle fd, byte* buffer, int count, long fileOffset);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PReadV", SetLastError = true)]
internal static extern unsafe long PReadV(SafeHandle fd, IOVector* vectors, int vectorCount, long fileOffset);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PWrite", SetLastError = true)]
internal static extern unsafe int PWrite(SafeHandle fd, byte* buffer, int bufferSize, long fileOffset);
adamsitnik marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PWriteV", SetLastError = true)]
internal static extern unsafe long PWriteV(SafeHandle fd, IOVector* vectors, int vectorCount, long fileOffset);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;
using System.Threading;

internal static partial class Interop
{
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern unsafe int ReadFileScatter(
SafeHandle handle,
long* segments,
int numBytesToRead,
IntPtr reserved_mustBeZero,
NativeOverlapped* overlapped);

[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern unsafe int WriteFileGather(
SafeHandle handle,
long* segments,
int numBytesToWrite,
IntPtr reserved_mustBeZero,
NativeOverlapped* overlapped);
adamsitnik marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ internal static partial class Interop
{
internal static partial class NtDll
{
internal const uint NT_ERROR_STATUS_DISK_FULL = 0xC000007F;
internal const uint NT_ERROR_STATUS_FILE_TOO_LARGE = 0xC0000904;
internal const uint NT_STATUS_INVALID_PARAMETER = 0xC000000D;

// https://msdn.microsoft.com/en-us/library/bb432380.aspx
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424.aspx
[DllImport(Libraries.NtDll, CharSet = CharSet.Unicode, ExactSpelling = true)]
Expand Down Expand Up @@ -76,7 +72,7 @@ internal static unsafe (uint status, IntPtr handle) CreateFile(
}
}

internal static unsafe (uint status, IntPtr handle) CreateFile(ReadOnlySpan<char> path, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize)
internal static unsafe (uint status, IntPtr handle) NtCreateFile(ReadOnlySpan<char> path, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize)
{
// For mitigating local elevation of privilege attack through named pipes
// make sure we always call NtCreateFile with SECURITY_ANONYMOUS so that the
Expand Down Expand Up @@ -120,7 +116,7 @@ private static CreateDisposition GetCreateDisposition(FileMode mode)

private static DesiredAccess GetDesiredAccess(FileAccess access, FileMode fileMode, FileOptions options)
{
DesiredAccess result = 0;
DesiredAccess result = DesiredAccess.FILE_READ_ATTRIBUTES | DesiredAccess.SYNCHRONIZE; // default values used by CreateFileW

if ((access & FileAccess.Read) != 0)
{
Expand All @@ -134,13 +130,9 @@ private static DesiredAccess GetDesiredAccess(FileAccess access, FileMode fileMo
{
result |= DesiredAccess.FILE_APPEND_DATA;
}
if ((options & FileOptions.Asynchronous) == 0)
{
result |= DesiredAccess.SYNCHRONIZE; // required by FILE_SYNCHRONOUS_IO_NONALERT
}
if ((options & FileOptions.DeleteOnClose) != 0 || fileMode == FileMode.Create)
adamsitnik marked this conversation as resolved.
Show resolved Hide resolved
if ((options & FileOptions.DeleteOnClose) != 0)
{
result |= DesiredAccess.DELETE; // required by FILE_DELETE_ON_CLOSE and FILE_SUPERSEDE (which deletes a file if it exists)
result |= DesiredAccess.DELETE; // required by FILE_DELETE_ON_CLOSE
}

return result;
Expand Down Expand Up @@ -190,7 +182,8 @@ private static CreateOptions GetCreateOptions(FileOptions options)
}

private static ObjectAttributes GetObjectAttributes(FileShare share)
=> (share & FileShare.Inheritable) != 0 ? ObjectAttributes.OBJ_INHERIT : 0;
=> ObjectAttributes.OBJ_CASE_INSENSITIVE | // default value used by CreateFileW
((share & FileShare.Inheritable) != 0 ? ObjectAttributes.OBJ_INHERIT : 0);

/// <summary>
/// File creation disposition when calling directly to NT APIs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

internal static partial class Interop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ internal static class StatusOptions
internal const uint STATUS_ACCOUNT_RESTRICTION = 0xC000006E;
internal const uint STATUS_NONE_MAPPED = 0xC0000073;
internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A;
internal const uint STATUS_DISK_FULL = 0xC000007F;
internal const uint STATUS_FILE_TOO_LARGE = 0xC0000904;
}
}
2 changes: 2 additions & 0 deletions src/libraries/Native/Unix/Common/pal_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#cmakedefine01 HAVE_POSIX_ADVISE
#cmakedefine01 HAVE_POSIX_FALLOCATE
#cmakedefine01 HAVE_POSIX_FALLOCATE64
#cmakedefine01 HAVE_PREADV
#cmakedefine01 HAVE_PWRITEV
#cmakedefine01 PRIORITY_REQUIRES_INT_WHO
#cmakedefine01 KEVENT_REQUIRES_INT_PARAMS
#cmakedefine01 HAVE_IOCTL
Expand Down
4 changes: 4 additions & 0 deletions src/libraries/Native/Unix/System.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_iOSSupportVersion)
DllImportEntry(SystemNative_GetErrNo)
DllImportEntry(SystemNative_SetErrNo)
DllImportEntry(SystemNative_PRead)
DllImportEntry(SystemNative_PWrite)
DllImportEntry(SystemNative_PReadV)
DllImportEntry(SystemNative_PWriteV)
};

EXTERN_C const void* SystemResolveDllImport(const char* name);
Expand Down
105 changes: 105 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
Expand Down Expand Up @@ -1454,3 +1455,107 @@ int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStat
return -1;
#endif // __sun
}

int32_t SystemNative_PRead(intptr_t fd, void* buffer, int32_t bufferSize, int64_t fileOffset)
{
assert(buffer != NULL);
assert(bufferSize >= 0);

ssize_t count;
while ((count = pread(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize, (off_t)fileOffset)) < 0 && errno == EINTR);

assert(count >= -1 && count <= bufferSize);
return (int32_t)count;
}

int32_t SystemNative_PWrite(intptr_t fd, void* buffer, int32_t bufferSize, int64_t fileOffset)
{
assert(buffer != NULL);
assert(bufferSize >= 0);

ssize_t count;
while ((count = pwrite(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize, (off_t)fileOffset)) < 0 && errno == EINTR);

assert(count >= -1 && count <= bufferSize);
return (int32_t)count;
}

int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset)
{
assert(vectors != NULL);
assert(vectorCount >= 0);

int64_t count = 0;
int fileDescriptor = ToFileDescriptor(fd);
#if HAVE_PREADV && !defined(TARGET_WASM) // preadv is buggy on WASM
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue to go along with that bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephentoub I've not reported it yet.

@vargaz when I was testing preadv and pwritev for WASM, our unit tests were failing (while there were passing on the same Ubuntu machine for coreclr built). It seemed that when providing n-buffers and offset=0 to preadv|pwritev, all read|write operations were happening at offset 0 (while only the first should, every next operation should start where the previous has finished). I've decided to simply not to use them on WASM (hence !defined(TARGET_WASM) ) and instead fallback to our own implementation that uses pread and pwrite (which we need for macOS anyway, as only macOS 11+ provides preadv and pwritev)

The most suprising thing is that it happens in the native layer (source code)

@vargaz where should I report the bug?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's open an issue in runtime for now and include the link here.

while ((count = preadv(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR);
#else
int64_t current;
for (int i = 0; i < vectorCount; i++)
{
IOVector vector = vectors[i];
while ((current = pread(fileDescriptor, vector.Base, vector.Count, (off_t)(fileOffset + count))) < 0 && errno == EINTR);

if (current < 0)
{
// if previous calls were succesfull, we return what we got so far
// otherwise, we return the error code
return count > 0 ? count : current;
}

count += current;

// Incomplete pread operation may happen for two reasons:
// a) We have reached EOF.
// b) The operation was interrupted by a signal handler.
// To mimic preadv, we stop on the first incomplete operation.
if (current != (int64_t)vector.Count)
{
return count;
}
}
#endif

assert(count >= -1);
return count;
}

int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset)
{
assert(vectors != NULL);
assert(vectorCount >= 0);

int64_t count = 0;
int fileDescriptor = ToFileDescriptor(fd);
#if HAVE_PWRITEV && !defined(TARGET_WASM) // pwritev is buggy on WASM
while ((count = pwritev(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR);
#else
int64_t current;
for (int i = 0; i < vectorCount; i++)
{
IOVector vector = vectors[i];
while ((current = pwrite(fileDescriptor, vector.Base, vector.Count, (off_t)(fileOffset + count))) < 0 && errno == EINTR);

if (current < 0)
{
// if previous calls were succesfull, we return what we got so far
// otherwise, we return the error code
return count > 0 ? count : current;
}

count += current;

// Incomplete pwrite operation may happen for few reasons:
// a) There was not enough space available or the file is too large for given file system.
// b) The operation was interrupted by a signal handler.
// To mimic pwritev, we stop on the first incomplete operation.
if (current != (int64_t)vector.Count)
{
return count;
}
}
#endif

assert(count >= -1);
return count;
}
36 changes: 36 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ typedef struct
// add more fields when needed.
} ProcessStatus;

// NOTE: the layout of this type is intended to exactly match the layout of a `struct iovec`. There are
// assertions in pal_networking.c that validate this.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move them to here?

// We require that IOVector have the same layout as iovec.
c_static_assert(sizeof(IOVector) == sizeof(iovec));
c_static_assert(sizeof_member(IOVector, Base) == sizeof_member(iovec, iov_base));
c_static_assert(offsetof(IOVector, Base) == offsetof(iovec, iov_base));
c_static_assert(sizeof_member(IOVector, Count) == sizeof_member(iovec, iov_len));
c_static_assert(offsetof(IOVector, Count) == offsetof(iovec, iov_len));

typedef struct
{
uint8_t* Base;
uintptr_t Count;
} IOVector;

/* Provide consistent access to nanosecond fields, if they exist. */
/* Seconds are always available through st_atime, st_mtime, st_ctime. */

Expand Down Expand Up @@ -730,3 +738,31 @@ PALEXPORT int32_t SystemNative_LChflagsCanSetHiddenFlag(void);
* Returns 1 if the process status was read; otherwise, 0.
*/
PALEXPORT int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStatus);

/**
* Reads the number of bytes specified into the provided buffer from the specified, opened file descriptor at specified offset.
*
* Returns the number of bytes read on success; otherwise, -1 is returned an errno is set.
*/
PALEXPORT int32_t SystemNative_PRead(intptr_t fd, void* buffer, int32_t bufferSize, int64_t fileOffset);

/**
* Writes the number of bytes specified in the buffer into the specified, opened file descriptor at specified offset.
*
* Returns the number of bytes written on success; otherwise, -1 is returned an errno is set.
*/
PALEXPORT int32_t SystemNative_PWrite(intptr_t fd, void* buffer, int32_t bufferSize, int64_t fileOffset);

/**
* Reads the number of bytes specified into the provided buffers from the specified, opened file descriptor at specified offset.
*
* Returns the number of bytes read on success; otherwise, -1 is returned an errno is set.
*/
PALEXPORT int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset);

/**
* Writes the number of bytes specified in the buffers into the specified, opened file descriptor at specified offset.
*
* Returns the number of bytes written on success; otherwise, -1 is returned an errno is set.
*/
PALEXPORT int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset);
5 changes: 2 additions & 3 deletions src/libraries/Native/Unix/System.Native/pal_networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include "pal_config.h"
#include "pal_networking.h"
#include "pal_io.h"
#include "pal_safecrt.h"
#include "pal_utilities.h"
#include <pal_networking_common.h>
Expand Down Expand Up @@ -3104,11 +3103,11 @@ int32_t SystemNative_Disconnect(intptr_t socket)
addr.sa_family = AF_UNSPEC;

err = connect(fd, &addr, sizeof(addr));
if (err != 0)
if (err != 0)
{
// On some older kernels connect(AF_UNSPEC) may fail. Fall back to shutdown in these cases:
err = shutdown(fd, SHUT_RDWR);
}
}
#elif HAVE_DISCONNECTX
// disconnectx causes a FIN close on OSX. It's the best we can do.
err = disconnectx(fd, SAE_ASSOCID_ANY, SAE_CONNID_ANY);
Expand Down
Loading