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 Sendability annotations on SocketOptionProvider #3034

Merged
merged 3 commits into from
Jan 13, 2025
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
227 changes: 205 additions & 22 deletions Sources/NIOCore/SocketOptionProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public protocol SocketOptionProvider: _NIOPreconcurrencySendable {
/// - value: The value to set the socket option to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
func unsafeSetSocketOption<Value>(
@preconcurrency
func unsafeSetSocketOption<Value: Sendable>(
level: SocketOptionLevel,
name: SocketOptionName,
value: Value
Expand All @@ -95,7 +96,8 @@ public protocol SocketOptionProvider: _NIOPreconcurrencySendable {
/// - value: The value to set the socket option to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
func unsafeSetSocketOption<Value>(
@preconcurrency
func unsafeSetSocketOption<Value: Sendable>(
level: NIOBSDSocket.OptionLevel,
name: NIOBSDSocket.Option,
value: Value
Expand All @@ -114,7 +116,11 @@ public protocol SocketOptionProvider: _NIOPreconcurrencySendable {
/// - name: The name of the socket option, e.g. `SO_REUSEADDR`.
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
func unsafeGetSocketOption<Value>(level: SocketOptionLevel, name: SocketOptionName) -> EventLoopFuture<Value>
@preconcurrency
func unsafeGetSocketOption<Value: Sendable>(
level: SocketOptionLevel,
name: SocketOptionName
) -> EventLoopFuture<Value>
#endif

/// Obtain the value of the socket option for the given level and name.
Expand All @@ -129,15 +135,16 @@ public protocol SocketOptionProvider: _NIOPreconcurrencySendable {
/// - name: The name of the socket option, e.g. `SO_REUSEADDR`.
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
func unsafeGetSocketOption<Value>(
@preconcurrency
func unsafeGetSocketOption<Value: Sendable>(
level: NIOBSDSocket.OptionLevel,
name: NIOBSDSocket.Option
) -> EventLoopFuture<Value>
}

#if !os(Windows)
extension SocketOptionProvider {
func unsafeSetSocketOption<Value>(
func unsafeSetSocketOption<Value: Sendable>(
level: NIOBSDSocket.OptionLevel,
name: NIOBSDSocket.Option,
value: Value
Expand All @@ -149,7 +156,7 @@ extension SocketOptionProvider {
)
}

func unsafeGetSocketOption<Value>(
func unsafeGetSocketOption<Value: Sendable>(
level: NIOBSDSocket.OptionLevel,
name: NIOBSDSocket.Option
) -> EventLoopFuture<Value> {
Expand All @@ -175,6 +182,12 @@ public typealias NIOLinger = linger
// around. As a result, if you change one, you should probably change them all.
//
// You are welcome to add more helper methods here, but each helper method you add must be tested.
//
// Please note that to work around a Swift compiler issue regarding lookup of the Sendability of
// libc types across modules, the actual calls to `unsafeSetSocketOption` and `unsafeGetSocketOption`
// _must_ be made inside non-`public` non-`@inlinable` methods. Otherwise we'll produce crashes
// in release mode. NIO's integration tests are a good canary for this: if you call your method
// from an alloc counter test in the integration tests, it'll crash if you messed it up.
extension SocketOptionProvider {
/// Sets the socket option SO_LINGER to `value`.
///
Expand All @@ -183,6 +196,176 @@ extension SocketOptionProvider {
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setSoLinger(_ value: linger) -> EventLoopFuture<Void> {
self._setSoLinger(value)
}

/// Gets the value of the socket option SO_LINGER.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getSoLinger() -> EventLoopFuture<NIOLinger> {
self._getSoLinger()
}

/// Sets the socket option IP_MULTICAST_IF to `value`.
///
/// - Parameters:
/// - value: The value to set IP_MULTICAST_IF to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastIF(_ value: in_addr) -> EventLoopFuture<Void> {
self._setIPMulticastIF(value)
}

/// Gets the value of the socket option IP_MULTICAST_IF.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastIF() -> EventLoopFuture<in_addr> {
self._getIPMulticastIF()
}

/// Sets the socket option IP_MULTICAST_TTL to `value`.
///
/// - Parameters:
/// - value: The value to set IP_MULTICAST_TTL to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastTTL(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
self._setIPMulticastTTL(value)
}

/// Gets the value of the socket option IP_MULTICAST_TTL.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastTTL() -> EventLoopFuture<CUnsignedChar> {
self._getIPMulticastTTL()
}

/// Sets the socket option IP_MULTICAST_LOOP to `value`.
///
/// - Parameters:
/// - value: The value to set IP_MULTICAST_LOOP to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastLoop(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
self._setIPMulticastLoop(value)
}

/// Gets the value of the socket option IP_MULTICAST_LOOP.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastLoop() -> EventLoopFuture<CUnsignedChar> {
self._getIPMulticastLoop()
}

/// Sets the socket option IPV6_MULTICAST_IF to `value`.
///
/// - Parameters:
/// - value: The value to set IPV6_MULTICAST_IF to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastIF(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
self._setIPv6MulticastIF(value)
}

/// Gets the value of the socket option IPV6_MULTICAST_IF.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastIF() -> EventLoopFuture<CUnsignedInt> {
self._getIPv6MulticastIF()
}

/// Sets the socket option IPV6_MULTICAST_HOPS to `value`.
///
/// - Parameters:
/// - value: The value to set IPV6_MULTICAST_HOPS to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastHops(_ value: CInt) -> EventLoopFuture<Void> {
self._setIPv6MulticastHops(value)
}

/// Gets the value of the socket option IPV6_MULTICAST_HOPS.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastHops() -> EventLoopFuture<CInt> {
self._getIPv6MulticastHops()
}

/// Sets the socket option IPV6_MULTICAST_LOOP to `value`.
///
/// - Parameters:
/// - value: The value to set IPV6_MULTICAST_LOOP to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastLoop(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
self._setIPv6MulticastLoop(value)
}

/// Gets the value of the socket option IPV6_MULTICAST_LOOP.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastLoop() -> EventLoopFuture<CUnsignedInt> {
self._getIPv6MulticastLoop()
}

#if os(Linux) || os(FreeBSD) || os(Android)
/// Gets the value of the socket option TCP_INFO.
///
/// This socket option cannot be set.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getTCPInfo() -> EventLoopFuture<tcp_info> {
self._getTCPInfo()
}
#endif

#if canImport(Darwin)
/// Gets the value of the socket option TCP_CONNECTION_INFO.
///
/// This socket option cannot be set.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getTCPConnectionInfo() -> EventLoopFuture<tcp_connection_info> {
self._getTCPConnectionInfo()
}
#endif

#if os(Linux)
/// Gets the value of the socket option MPTCP_INFO.
///
/// This socket option cannot be set.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getMPTCPInfo() -> EventLoopFuture<mptcp_info> {
self._getMPTCPInfo()
}
#endif

// MARK: Non-public non-inlinable actual implementations for the above.
//
// As discussed above, these are needed to work around a compiler issue
// that was present at least up to the 6.0 compiler series. This prevents
// the specialization being emitted in the caller code, which is unfortunate,
// but it also ensures that we avoid the crash. We should remove these when
// they're no longer needed.

/// Sets the socket option SO_LINGER to `value`.
///
/// - Parameters:
/// - value: The value to set SO_LINGER to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
private func _setSoLinger(_ value: linger) -> EventLoopFuture<Void> {
#if os(WASI)
self.eventLoop.makeFailedFuture(SocketOptionProviderError.unsupported)
#else
Expand All @@ -194,7 +377,7 @@ extension SocketOptionProvider {
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getSoLinger() -> EventLoopFuture<NIOLinger> {
private func _getSoLinger() -> EventLoopFuture<NIOLinger> {
#if os(WASI)
self.eventLoop.makeFailedFuture(SocketOptionProviderError.unsupported)
#else
Expand All @@ -208,15 +391,15 @@ extension SocketOptionProvider {
/// - value: The value to set IP_MULTICAST_IF to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastIF(_ value: in_addr) -> EventLoopFuture<Void> {
private func _setIPMulticastIF(_ value: in_addr) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ip, name: .ip_multicast_if, value: value)
}

/// Gets the value of the socket option IP_MULTICAST_IF.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastIF() -> EventLoopFuture<in_addr> {
private func _getIPMulticastIF() -> EventLoopFuture<in_addr> {
self.unsafeGetSocketOption(level: .ip, name: .ip_multicast_if)
}

Expand All @@ -226,15 +409,15 @@ extension SocketOptionProvider {
/// - value: The value to set IP_MULTICAST_TTL to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastTTL(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
private func _setIPMulticastTTL(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ip, name: .ip_multicast_ttl, value: value)
}

/// Gets the value of the socket option IP_MULTICAST_TTL.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastTTL() -> EventLoopFuture<CUnsignedChar> {
private func _getIPMulticastTTL() -> EventLoopFuture<CUnsignedChar> {
self.unsafeGetSocketOption(level: .ip, name: .ip_multicast_ttl)
}

Expand All @@ -244,15 +427,15 @@ extension SocketOptionProvider {
/// - value: The value to set IP_MULTICAST_LOOP to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPMulticastLoop(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
private func _setIPMulticastLoop(_ value: CUnsignedChar) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ip, name: .ip_multicast_loop, value: value)
}

/// Gets the value of the socket option IP_MULTICAST_LOOP.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPMulticastLoop() -> EventLoopFuture<CUnsignedChar> {
private func _getIPMulticastLoop() -> EventLoopFuture<CUnsignedChar> {
self.unsafeGetSocketOption(level: .ip, name: .ip_multicast_loop)
}

Expand All @@ -262,15 +445,15 @@ extension SocketOptionProvider {
/// - value: The value to set IPV6_MULTICAST_IF to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastIF(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
private func _setIPv6MulticastIF(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ipv6, name: .ipv6_multicast_if, value: value)
}

/// Gets the value of the socket option IPV6_MULTICAST_IF.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastIF() -> EventLoopFuture<CUnsignedInt> {
private func _getIPv6MulticastIF() -> EventLoopFuture<CUnsignedInt> {
self.unsafeGetSocketOption(level: .ipv6, name: .ipv6_multicast_if)
}

Expand All @@ -280,15 +463,15 @@ extension SocketOptionProvider {
/// - value: The value to set IPV6_MULTICAST_HOPS to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastHops(_ value: CInt) -> EventLoopFuture<Void> {
private func _setIPv6MulticastHops(_ value: CInt) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ipv6, name: .ipv6_multicast_hops, value: value)
}

/// Gets the value of the socket option IPV6_MULTICAST_HOPS.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastHops() -> EventLoopFuture<CInt> {
private func _getIPv6MulticastHops() -> EventLoopFuture<CInt> {
self.unsafeGetSocketOption(level: .ipv6, name: .ipv6_multicast_hops)
}

Expand All @@ -298,15 +481,15 @@ extension SocketOptionProvider {
/// - value: The value to set IPV6_MULTICAST_LOOP to.
/// - Returns: An `EventLoopFuture` that fires when the option has been set,
/// or if an error has occurred.
public func setIPv6MulticastLoop(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
private func _setIPv6MulticastLoop(_ value: CUnsignedInt) -> EventLoopFuture<Void> {
self.unsafeSetSocketOption(level: .ipv6, name: .ipv6_multicast_loop, value: value)
}

/// Gets the value of the socket option IPV6_MULTICAST_LOOP.
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getIPv6MulticastLoop() -> EventLoopFuture<CUnsignedInt> {
private func _getIPv6MulticastLoop() -> EventLoopFuture<CUnsignedInt> {
self.unsafeGetSocketOption(level: .ipv6, name: .ipv6_multicast_loop)
}

Expand All @@ -317,7 +500,7 @@ extension SocketOptionProvider {
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getTCPInfo() -> EventLoopFuture<tcp_info> {
private func _getTCPInfo() -> EventLoopFuture<tcp_info> {
self.unsafeGetSocketOption(level: .tcp, name: .tcp_info)
}
#endif
Expand All @@ -329,7 +512,7 @@ extension SocketOptionProvider {
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getTCPConnectionInfo() -> EventLoopFuture<tcp_connection_info> {
private func _getTCPConnectionInfo() -> EventLoopFuture<tcp_connection_info> {
self.unsafeGetSocketOption(level: .tcp, name: .tcp_connection_info)
}
#endif
Expand All @@ -341,7 +524,7 @@ extension SocketOptionProvider {
///
/// - Returns: An `EventLoopFuture` containing the value of the socket option, or
/// any error that occurred while retrieving the socket option.
public func getMPTCPInfo() -> EventLoopFuture<mptcp_info> {
private func _getMPTCPInfo() -> EventLoopFuture<mptcp_info> {
self.unsafeGetSocketOption(level: .mptcp, name: .mptcp_info)
}
#endif
Expand Down
Loading
Loading