Skip to content

Commit

Permalink
Add TCP_INFO/TCP_CONNECTION_INFO queries. (#811)
Browse files Browse the repository at this point in the history
Motivation:

Many users may wish to see the underlying TCP connection state for
important calculations, such as for BDP or RTT numbers. We can make this
available easily enough.

Modifications:

- Added a function to get TCP_INFO on Linux/FreeBSD.
- Added a function to get TCP_CONNECTION_INFO on Darwin.

Result:

Better connection stats
  • Loading branch information
Lukasa authored and weissi committed Feb 11, 2019
1 parent 642076e commit 2738b6d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
24 changes: 24 additions & 0 deletions Sources/NIO/SocketOptionProvider.swift
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -207,6 +207,30 @@ public extension SocketOptionProvider {
func getIPv6MulticastLoop() -> EventLoopFuture<CUnsignedInt> { func getIPv6MulticastLoop() -> EventLoopFuture<CUnsignedInt> {
return self.unsafeGetSocketOption(level: IPPROTO_IPV6, name: IPV6_MULTICAST_LOOP) return self.unsafeGetSocketOption(level: IPPROTO_IPV6, name: IPV6_MULTICAST_LOOP)
} }

#if os(Linux) || os(FreeBSD)
/// 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.
func getTCPInfo() -> EventLoopFuture<tcp_info> {
return self.unsafeGetSocketOption(level: IPPROTO_TCP, name: TCP_INFO)
}
#endif

#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
/// 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.
func getTCPConnectionInfo() -> EventLoopFuture<tcp_connection_info> {
return self.unsafeGetSocketOption(level: IPPROTO_TCP, name: TCP_CONNECTION_INFO)
}
#endif
} }




Expand Down
2 changes: 2 additions & 0 deletions Tests/NIOTests/SocketOptionProviderTest+XCTest.swift
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extension SocketOptionProviderTest {
("testIpv6MulticastIf", testIpv6MulticastIf), ("testIpv6MulticastIf", testIpv6MulticastIf),
("testIPv6MulticastHops", testIPv6MulticastHops), ("testIPv6MulticastHops", testIPv6MulticastHops),
("testIPv6MulticastLoop", testIPv6MulticastLoop), ("testIPv6MulticastLoop", testIPv6MulticastLoop),
("testTCPInfo", testTCPInfo),
("testTCPConnectionInfo", testTCPConnectionInfo),
] ]
} }
} }
Expand Down
22 changes: 22 additions & 0 deletions Tests/NIOTests/SocketOptionProviderTest.swift
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -241,4 +241,26 @@ final class SocketOptionProviderTest: XCTestCase {
XCTAssertNotEqual($0, 0) XCTAssertNotEqual($0, 0)
}.wait()) }.wait())
} }

func testTCPInfo() throws {
// This test only runs on Linux and FreeBSD.
#if os(Linux) || os(FreeBSD)
let channel = self.clientChannel! as! SocketOptionProvider
let tcpInfo = try assertNoThrowWithValue(channel.getTCPInfo().wait())

// We just need to sanity check something here to ensure that the data is vaguely reasonable.
XCTAssertEqual(tcpInfo.tcpi_state, UInt8(TCP_ESTABLISHED))
#endif
}

func testTCPConnectionInfo() throws {
// This test only runs on Darwin.
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
let channel = self.clientChannel! as! SocketOptionProvider
let tcpConnectionInfo = try assertNoThrowWithValue(channel.getTCPConnectionInfo().wait())

// We just need to sanity check something here to ensure that the data is vaguely reasonable.
XCTAssertEqual(tcpConnectionInfo.tcpi_state, UInt8(TSI_S_ESTABLISHED))
#endif
}
} }

0 comments on commit 2738b6d

Please sign in to comment.