451 lines
16 KiB
Swift
451 lines
16 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the SwiftNIO open source project
|
|
//
|
|
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
|
|
// Licensed under Apache License v2.0
|
|
//
|
|
// See LICENSE.txt for license information
|
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
protocol _SocketShutdownProtocol {
|
|
var cValue: CInt { get }
|
|
}
|
|
|
|
internal enum Shutdown: _SocketShutdownProtocol {
|
|
case RD
|
|
case WR
|
|
case RDWR
|
|
}
|
|
|
|
public enum NIOBSDSocket {
|
|
#if os(Windows)
|
|
public typealias Handle = SOCKET
|
|
#else
|
|
public typealias Handle = CInt
|
|
#endif
|
|
}
|
|
|
|
extension NIOBSDSocket {
|
|
/// Specifies the type of socket.
|
|
internal struct SocketType: RawRepresentable {
|
|
public typealias RawValue = CInt
|
|
public var rawValue: RawValue
|
|
public init(rawValue: RawValue) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
extension NIOBSDSocket.SocketType: Equatable {
|
|
}
|
|
|
|
extension NIOBSDSocket.SocketType: Hashable {
|
|
}
|
|
|
|
extension NIOBSDSocket {
|
|
/// Specifies the addressing scheme that the socket can use.
|
|
public struct AddressFamily: RawRepresentable {
|
|
public typealias RawValue = CInt
|
|
public var rawValue: RawValue
|
|
public init(rawValue: RawValue) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
extension NIOBSDSocket.AddressFamily: Equatable {
|
|
}
|
|
|
|
extension NIOBSDSocket.AddressFamily: Hashable {
|
|
}
|
|
|
|
extension NIOBSDSocket {
|
|
/// Specifies the type of protocol that the socket can use.
|
|
public struct ProtocolFamily: RawRepresentable {
|
|
public typealias RawValue = CInt
|
|
public var rawValue: RawValue
|
|
public init(rawValue: RawValue) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
extension NIOBSDSocket.ProtocolFamily: Equatable {
|
|
}
|
|
|
|
extension NIOBSDSocket.ProtocolFamily: Hashable {
|
|
}
|
|
|
|
extension NIOBSDSocket {
|
|
/// Defines socket option levels.
|
|
public struct OptionLevel: RawRepresentable {
|
|
public typealias RawValue = CInt
|
|
public var rawValue: RawValue
|
|
public init(rawValue: RawValue) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
extension NIOBSDSocket.OptionLevel: Equatable {
|
|
}
|
|
|
|
extension NIOBSDSocket.OptionLevel: Hashable {
|
|
}
|
|
|
|
extension NIOBSDSocket {
|
|
/// Defines configuration option names.
|
|
public struct Option: RawRepresentable {
|
|
public typealias RawValue = CInt
|
|
public var rawValue: RawValue
|
|
public init(rawValue: RawValue) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
extension NIOBSDSocket.Option: Equatable {
|
|
}
|
|
|
|
extension NIOBSDSocket.Option: Hashable {
|
|
}
|
|
|
|
// Address Family
|
|
extension NIOBSDSocket.AddressFamily {
|
|
/// Address for IP version 4.
|
|
public static let inet: NIOBSDSocket.AddressFamily =
|
|
NIOBSDSocket.AddressFamily(rawValue: AF_INET)
|
|
|
|
/// Address for IP version 6.
|
|
public static let inet6: NIOBSDSocket.AddressFamily =
|
|
NIOBSDSocket.AddressFamily(rawValue: AF_INET6)
|
|
|
|
/// Unix local to host address.
|
|
public static let unix: NIOBSDSocket.AddressFamily =
|
|
NIOBSDSocket.AddressFamily(rawValue: AF_UNIX)
|
|
}
|
|
|
|
// Protocol Family
|
|
extension NIOBSDSocket.ProtocolFamily {
|
|
/// IP network 4 protocol.
|
|
public static let inet: NIOBSDSocket.ProtocolFamily =
|
|
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET)
|
|
|
|
/// IP network 6 protocol.
|
|
public static let inet6: NIOBSDSocket.ProtocolFamily =
|
|
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET6)
|
|
|
|
/// UNIX local to the host.
|
|
public static let unix: NIOBSDSocket.ProtocolFamily =
|
|
NIOBSDSocket.ProtocolFamily(rawValue: PF_UNIX)
|
|
}
|
|
|
|
#if !os(Windows)
|
|
extension NIOBSDSocket.ProtocolFamily {
|
|
/// UNIX local to the host, alias for `PF_UNIX` (`.unix`)
|
|
public static let local: NIOBSDSocket.ProtocolFamily =
|
|
NIOBSDSocket.ProtocolFamily(rawValue: PF_LOCAL)
|
|
}
|
|
#endif
|
|
|
|
// Socket Types
|
|
extension NIOBSDSocket.SocketType {
|
|
/// Supports datagrams, which are connectionless, unreliable messages of a
|
|
/// fixed (typically small) maximum length.
|
|
#if os(Linux)
|
|
internal static let datagram: NIOBSDSocket.SocketType =
|
|
NIOBSDSocket.SocketType(rawValue: CInt(SOCK_DGRAM.rawValue))
|
|
#else
|
|
internal static let datagram: NIOBSDSocket.SocketType =
|
|
NIOBSDSocket.SocketType(rawValue: SOCK_DGRAM)
|
|
#endif
|
|
|
|
/// Supports reliable, two-way, connection-based byte streams without
|
|
/// duplication of data and without preservation of boundaries.
|
|
#if os(Linux)
|
|
internal static let stream: NIOBSDSocket.SocketType =
|
|
NIOBSDSocket.SocketType(rawValue: CInt(SOCK_STREAM.rawValue))
|
|
#else
|
|
internal static let stream: NIOBSDSocket.SocketType =
|
|
NIOBSDSocket.SocketType(rawValue: SOCK_STREAM)
|
|
#endif
|
|
}
|
|
|
|
// Option Level
|
|
extension NIOBSDSocket.OptionLevel {
|
|
/// Socket options that apply only to IP sockets.
|
|
#if os(Linux)
|
|
public static let ip: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IP))
|
|
#else
|
|
public static let ip: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IP)
|
|
#endif
|
|
|
|
/// Socket options that apply only to IPv6 sockets.
|
|
#if os(Linux)
|
|
public static let ipv6: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IPV6))
|
|
#elseif os(Windows)
|
|
public static let ipv6: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6.rawValue)
|
|
#else
|
|
public static let ipv6: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6)
|
|
#endif
|
|
|
|
/// Socket options that apply only to TCP sockets.
|
|
#if os(Linux)
|
|
public static let tcp: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_TCP))
|
|
#elseif os(Windows)
|
|
public static let tcp: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP.rawValue)
|
|
#else
|
|
public static let tcp: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP)
|
|
#endif
|
|
|
|
/// Socket options that apply to all sockets.
|
|
public static let socket: NIOBSDSocket.OptionLevel =
|
|
NIOBSDSocket.OptionLevel(rawValue: SOL_SOCKET)
|
|
}
|
|
|
|
// IPv4 Options
|
|
extension NIOBSDSocket.Option {
|
|
/// Add a multicast group membership.
|
|
public static let ip_add_membership: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_ADD_MEMBERSHIP)
|
|
|
|
/// Drop a multicast group membership.
|
|
public static let ip_drop_membership: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_DROP_MEMBERSHIP)
|
|
|
|
/// Set the interface for outgoing multicast packets.
|
|
public static let ip_multicast_if: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_MULTICAST_IF)
|
|
|
|
/// Control multicast loopback.
|
|
public static let ip_multicast_loop: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_MULTICAST_LOOP)
|
|
|
|
/// Control multicast time-to-live.
|
|
public static let ip_multicast_ttl: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_MULTICAST_TTL)
|
|
|
|
/// Request that we are passed type of service details when receiving datagrams.
|
|
/// Not public as the way to request this is to use `ChannelOptions.explicitCongestionNotification`
|
|
/// which works for both IPv4 and IPv6.
|
|
static let ip_recv_tos: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IP_RECVTOS)
|
|
}
|
|
|
|
// IPv6 Options
|
|
extension NIOBSDSocket.Option {
|
|
/// Add an IPv6 group membership.
|
|
public static let ipv6_join_group: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_JOIN_GROUP)
|
|
|
|
/// Drop an IPv6 group membership.
|
|
public static let ipv6_leave_group: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_LEAVE_GROUP)
|
|
|
|
/// Specify the maximum number of router hops for an IPv6 packet.
|
|
public static let ipv6_multicast_hops: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_HOPS)
|
|
|
|
/// Set the interface for outgoing multicast packets.
|
|
public static let ipv6_multicast_if: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_IF)
|
|
|
|
/// Control multicast loopback.
|
|
public static let ipv6_multicast_loop: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_LOOP)
|
|
|
|
/// Indicates if a socket created for the `AF_INET6` address family is
|
|
/// restricted to IPv6 only.
|
|
public static let ipv6_v6only: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_V6ONLY)
|
|
|
|
/// Request that we are passed traffic class details when receiving datagrams.
|
|
/// Not public as the way to request this is to use `ChannelOptions.explicitCongestionNotification`
|
|
/// which works for both IPv4 and IPv6.
|
|
static let ipv6_recv_tclass: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: IPV6_RECVTCLASS)
|
|
}
|
|
|
|
// TCP Options
|
|
extension NIOBSDSocket.Option {
|
|
/// Disables the Nagle algorithm for send coalescing.
|
|
public static let tcp_nodelay: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: TCP_NODELAY)
|
|
}
|
|
|
|
#if os(Linux) || os(FreeBSD)
|
|
extension NIOBSDSocket.Option {
|
|
/// Get information about the TCP connection.
|
|
public static let tcp_info: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: TCP_INFO)
|
|
}
|
|
#endif
|
|
|
|
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
|
|
extension NIOBSDSocket.Option {
|
|
/// Get information about the TCP connection.
|
|
public static let tcp_connection_info: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: TCP_CONNECTION_INFO)
|
|
}
|
|
#endif
|
|
|
|
// Socket Options
|
|
extension NIOBSDSocket.Option {
|
|
/// Get the error status and clear.
|
|
public static let so_error: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_ERROR)
|
|
|
|
/// Use keep-alives.
|
|
public static let so_keepalive: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_KEEPALIVE)
|
|
|
|
/// Linger on close if unsent data is present.
|
|
public static let so_linger: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_LINGER)
|
|
|
|
/// Specifies the total per-socket buffer space reserved for receives.
|
|
public static let so_rcvbuf: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_RCVBUF)
|
|
|
|
/// Specifies the receive timeout.
|
|
public static let so_rcvtimeo: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_RCVTIMEO)
|
|
|
|
/// Allows the socket to be bound to an address that is already in use.
|
|
public static let so_reuseaddr: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_REUSEADDR)
|
|
}
|
|
|
|
#if !os(Windows)
|
|
extension NIOBSDSocket.Option {
|
|
/// Indicate when to generate timestamps.
|
|
public static let so_timestamp: NIOBSDSocket.Option =
|
|
NIOBSDSocket.Option(rawValue: SO_TIMESTAMP)
|
|
}
|
|
#endif
|
|
|
|
|
|
/// This protocol defines the methods that are expected to be found on `NIOBSDSocket`. While defined as a protocol
|
|
/// there is no expectation that any object other than `NIOBSDSocket` will implement this protocol: instead, this protocol
|
|
/// acts as a reference for what new supported operating systems must implement.
|
|
protocol _BSDSocketProtocol {
|
|
static func accept(socket s: NIOBSDSocket.Handle,
|
|
address addr: UnsafeMutablePointer<sockaddr>?,
|
|
address_len addrlen: UnsafeMutablePointer<socklen_t>?) throws -> NIOBSDSocket.Handle?
|
|
|
|
static func bind(socket s: NIOBSDSocket.Handle,
|
|
address addr: UnsafePointer<sockaddr>,
|
|
address_len namelen: socklen_t) throws
|
|
|
|
static func close(socket s: NIOBSDSocket.Handle) throws
|
|
|
|
static func connect(socket s: NIOBSDSocket.Handle,
|
|
address name: UnsafePointer<sockaddr>,
|
|
address_len namelen: socklen_t) throws -> Bool
|
|
|
|
static func getpeername(socket s: NIOBSDSocket.Handle,
|
|
address name: UnsafeMutablePointer<sockaddr>,
|
|
address_len namelen: UnsafeMutablePointer<socklen_t>) throws
|
|
|
|
static func getsockname(socket s: NIOBSDSocket.Handle,
|
|
address name: UnsafeMutablePointer<sockaddr>,
|
|
address_len namelen: UnsafeMutablePointer<socklen_t>) throws
|
|
|
|
static func getsockopt(socket: NIOBSDSocket.Handle,
|
|
level: NIOBSDSocket.OptionLevel,
|
|
option_name optname: NIOBSDSocket.Option,
|
|
option_value optval: UnsafeMutableRawPointer,
|
|
option_len optlen: UnsafeMutablePointer<socklen_t>) throws
|
|
|
|
static func listen(socket s: NIOBSDSocket.Handle, backlog: CInt) throws
|
|
|
|
static func recv(socket s: NIOBSDSocket.Handle,
|
|
buffer buf: UnsafeMutableRawPointer,
|
|
length len: size_t) throws -> IOResult<size_t>
|
|
|
|
static func recvmsg(descriptor: CInt, msgHdr: UnsafeMutablePointer<msghdr>, flags: CInt) throws -> IOResult<ssize_t>
|
|
|
|
static func sendmsg(descriptor: CInt,
|
|
msgHdr: UnsafePointer<msghdr>,
|
|
flags: CInt) throws -> IOResult<ssize_t>
|
|
|
|
static func send(socket s: NIOBSDSocket.Handle,
|
|
buffer buf: UnsafeRawPointer,
|
|
length len: size_t) throws -> IOResult<size_t>
|
|
|
|
static func setsockopt(socket: NIOBSDSocket.Handle,
|
|
level: NIOBSDSocket.OptionLevel,
|
|
option_name optname: NIOBSDSocket.Option,
|
|
option_value optval: UnsafeRawPointer,
|
|
option_len optlen: socklen_t) throws
|
|
|
|
static func shutdown(socket: NIOBSDSocket.Handle, how: Shutdown) throws
|
|
|
|
static func socket(domain af: NIOBSDSocket.ProtocolFamily,
|
|
type: NIOBSDSocket.SocketType,
|
|
`protocol`: CInt) throws -> NIOBSDSocket.Handle
|
|
|
|
static func recvmmsg(socket: NIOBSDSocket.Handle,
|
|
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
|
vlen: CUnsignedInt,
|
|
flags: CInt,
|
|
timeout: UnsafeMutablePointer<timespec>?) throws -> IOResult<Int>
|
|
|
|
static func sendmmsg(socket: NIOBSDSocket.Handle,
|
|
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
|
vlen: CUnsignedInt,
|
|
flags: CInt) throws -> IOResult<Int>
|
|
|
|
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
|
// type, and defining that type is difficult. Opt to return a `size_t`
|
|
// which is the same size, but is unsigned.
|
|
static func pread(socket: NIOBSDSocket.Handle,
|
|
pointer: UnsafeMutableRawPointer,
|
|
size: size_t,
|
|
offset: off_t) throws -> IOResult<size_t>
|
|
|
|
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
|
// type, and defining that type is difficult. Opt to return a `size_t`
|
|
// which is the same size, but is unsigned.
|
|
static func pwrite(socket: NIOBSDSocket.Handle,
|
|
pointer: UnsafeRawPointer,
|
|
size: size_t,
|
|
offset: off_t) throws -> IOResult<size_t>
|
|
|
|
static func poll(fds: UnsafeMutablePointer<pollfd>,
|
|
nfds: nfds_t,
|
|
timeout: CInt) throws -> CInt
|
|
|
|
static func inet_ntop(af family: NIOBSDSocket.AddressFamily,
|
|
src addr: UnsafeRawPointer,
|
|
dst dstBuf: UnsafeMutablePointer<CChar>,
|
|
size dstSize: socklen_t) throws -> UnsafePointer<CChar>?
|
|
|
|
static func inet_pton(af family: NIOBSDSocket.AddressFamily,
|
|
src description: UnsafePointer<CChar>,
|
|
dst address: UnsafeMutableRawPointer) throws
|
|
|
|
static func sendfile(socket s: NIOBSDSocket.Handle,
|
|
fd: CInt,
|
|
offset: off_t,
|
|
len: off_t) throws -> IOResult<Int>
|
|
|
|
static func setNonBlocking(socket: NIOBSDSocket.Handle) throws
|
|
}
|
|
|
|
/// If this extension is hitting a compile error, your platform is missing one of the functions defined above!
|
|
extension NIOBSDSocket: _BSDSocketProtocol { }
|