SocketAddress.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /// An address to which a socket may connect or bind.
  17. public struct SocketAddress: Hashable, Sendable {
  18. private enum Value: Hashable, Sendable {
  19. case ipv4(IPv4)
  20. case ipv6(IPv6)
  21. case unix(UnixDomainSocket)
  22. case vsock(VirtualSocket)
  23. }
  24. private var value: Value
  25. private init(_ value: Value) {
  26. self.value = value
  27. }
  28. /// Returns the address as an IPv4 address, if possible.
  29. public var ipv4: IPv4? {
  30. switch self.value {
  31. case .ipv4(let address):
  32. return address
  33. default:
  34. return nil
  35. }
  36. }
  37. /// Returns the address as an IPv6 address, if possible.
  38. public var ipv6: IPv6? {
  39. switch self.value {
  40. case .ipv6(let address):
  41. return address
  42. default:
  43. return nil
  44. }
  45. }
  46. /// Returns the address as an Unix domain socket address, if possible.
  47. public var unixDomainSocket: UnixDomainSocket? {
  48. switch self.value {
  49. case .unix(let address):
  50. return address
  51. default:
  52. return nil
  53. }
  54. }
  55. /// Returns the address as an VSOCK address, if possible.
  56. public var virtualSocket: VirtualSocket? {
  57. switch self.value {
  58. case .vsock(let address):
  59. return address
  60. default:
  61. return nil
  62. }
  63. }
  64. }
  65. extension SocketAddress {
  66. /// Creates a socket address by wrapping a ``SocketAddress/IPv4-swift.struct``.
  67. public static func ipv4(_ address: IPv4) -> Self {
  68. return Self(.ipv4(address))
  69. }
  70. /// Creates a socket address by wrapping a ``SocketAddress/IPv6-swift.struct``.
  71. public static func ipv6(_ address: IPv6) -> Self {
  72. return Self(.ipv6(address))
  73. }
  74. /// Creates a socket address by wrapping a ``SocketAddress/UnixDomainSocket-swift.struct``.
  75. public static func unixDomainSocket(_ address: UnixDomainSocket) -> Self {
  76. return Self(.unix(address))
  77. }
  78. /// Creates a socket address by wrapping a ``SocketAddress/VirtualSocket-swift.struct``.
  79. public static func vsock(_ address: VirtualSocket) -> Self {
  80. return Self(.vsock(address))
  81. }
  82. }
  83. extension SocketAddress {
  84. /// Creates an IPv4 socket address.
  85. public static func ipv4(host: String, port: Int) -> Self {
  86. return .ipv4(IPv4(host: host, port: port))
  87. }
  88. /// Creates an IPv6 socket address.
  89. public static func ipv6(host: String, port: Int) -> Self {
  90. return .ipv6(IPv6(host: host, port: port))
  91. }
  92. /// Creates a Unix socket address.
  93. public static func unixDomainSocket(path: String) -> Self {
  94. return .unixDomainSocket(UnixDomainSocket(path: path))
  95. }
  96. /// Create a Virtual Socket ('vsock') address.
  97. public static func vsock(contextID: VirtualSocket.ContextID, port: VirtualSocket.Port) -> Self {
  98. return .vsock(VirtualSocket(contextID: contextID, port: port))
  99. }
  100. }
  101. extension SocketAddress: CustomStringConvertible {
  102. public var description: String {
  103. switch self.value {
  104. case .ipv4(let address):
  105. return String(describing: address)
  106. case .ipv6(let address):
  107. return String(describing: address)
  108. case .unix(let address):
  109. return String(describing: address)
  110. case .vsock(let address):
  111. return String(describing: address)
  112. }
  113. }
  114. }
  115. extension SocketAddress {
  116. public struct IPv4: Hashable, Sendable {
  117. /// The resolved host address.
  118. public var host: String
  119. /// The port to connect to.
  120. public var port: Int
  121. /// Creates a new IPv4 address.
  122. ///
  123. /// - Parameters:
  124. /// - host: Resolved host address.
  125. /// - port: Port to connect to.
  126. public init(host: String, port: Int) {
  127. self.host = host
  128. self.port = port
  129. }
  130. }
  131. public struct IPv6: Hashable, Sendable {
  132. /// The resolved host address.
  133. public var host: String
  134. /// The port to connect to.
  135. public var port: Int
  136. /// Creates a new IPv6 address.
  137. ///
  138. /// - Parameters:
  139. /// - host: Resolved host address.
  140. /// - port: Port to connect to.
  141. public init(host: String, port: Int) {
  142. self.host = host
  143. self.port = port
  144. }
  145. }
  146. public struct UnixDomainSocket: Hashable, Sendable {
  147. /// The path name of the Unix domain socket.
  148. public var path: String
  149. /// Create a new Unix domain socket address.
  150. ///
  151. /// - Parameter path: The path name of the Unix domain socket.
  152. public init(path: String) {
  153. self.path = path
  154. }
  155. }
  156. public struct VirtualSocket: Hashable, Sendable {
  157. /// A context identifier.
  158. ///
  159. /// Indicates the source or destination which is either a virtual machine or the host.
  160. public var contextID: ContextID
  161. /// The port number.
  162. public var port: Port
  163. /// Create a new VSOCK address.
  164. ///
  165. /// - Parameters:
  166. /// - contextID: The context ID (or 'cid') of the address.
  167. /// - port: The port number.
  168. public init(contextID: ContextID, port: Port) {
  169. self.contextID = contextID
  170. self.port = port
  171. }
  172. public struct Port: Hashable, Sendable, RawRepresentable, ExpressibleByIntegerLiteral {
  173. /// The port number.
  174. public var rawValue: UInt32
  175. public init(rawValue: UInt32) {
  176. self.rawValue = rawValue
  177. }
  178. public init(integerLiteral value: UInt32) {
  179. self.rawValue = value
  180. }
  181. public init(_ value: Int) {
  182. self.init(rawValue: UInt32(bitPattern: Int32(truncatingIfNeeded: value)))
  183. }
  184. /// Used to bind to any port number.
  185. ///
  186. /// This is equal to `VMADDR_PORT_ANY (-1U)`.
  187. public static var any: Self {
  188. Self(rawValue: UInt32(bitPattern: -1))
  189. }
  190. }
  191. public struct ContextID: Hashable, Sendable, RawRepresentable, ExpressibleByIntegerLiteral {
  192. /// The context identifier.
  193. public var rawValue: UInt32
  194. public init(rawValue: UInt32) {
  195. self.rawValue = rawValue
  196. }
  197. public init(integerLiteral value: UInt32) {
  198. self.rawValue = value
  199. }
  200. public init(_ value: Int) {
  201. self.rawValue = UInt32(bitPattern: Int32(truncatingIfNeeded: value))
  202. }
  203. /// Wildcard, matches any address.
  204. ///
  205. /// On all platforms, using this value with `bind(2)` means "any address".
  206. ///
  207. /// On Darwin platforms, the man page states this can be used with `connect(2)`
  208. /// to mean "this host".
  209. ///
  210. /// This is equal to `VMADDR_CID_ANY (-1U)`.
  211. public static var any: Self {
  212. Self(rawValue: UInt32(bitPattern: -1))
  213. }
  214. /// The address of the hypervisor.
  215. ///
  216. /// This is equal to `VMADDR_CID_HYPERVISOR (0)`.
  217. public static var hypervisor: Self {
  218. Self(rawValue: 0)
  219. }
  220. /// The address of the host.
  221. ///
  222. /// This is equal to `VMADDR_CID_HOST (2)`.
  223. public static var host: Self {
  224. Self(rawValue: 2)
  225. }
  226. /// The address for local communication (loopback).
  227. ///
  228. /// This directs packets to the same host that generated them. This is useful for testing
  229. /// applications on a single host and for debugging.
  230. ///
  231. /// This is equal to `VMADDR_CID_LOCAL (1)` on platforms that define it.
  232. ///
  233. /// - Warning: `VMADDR_CID_LOCAL (1)` is available from Linux 5.6. Its use is unsupported on
  234. /// other platforms.
  235. /// - SeeAlso: https://man7.org/linux/man-pages/man7/vsock.7.html
  236. public static var local: Self {
  237. Self(rawValue: 1)
  238. }
  239. }
  240. }
  241. }
  242. extension SocketAddress.IPv4: CustomStringConvertible {
  243. public var description: String {
  244. "[ipv4]\(self.host):\(self.port)"
  245. }
  246. }
  247. extension SocketAddress.IPv6: CustomStringConvertible {
  248. public var description: String {
  249. "[ipv6]\(self.host):\(self.port)"
  250. }
  251. }
  252. extension SocketAddress.UnixDomainSocket: CustomStringConvertible {
  253. public var description: String {
  254. "[unix]\(self.path)"
  255. }
  256. }
  257. extension SocketAddress.VirtualSocket: CustomStringConvertible {
  258. public var description: String {
  259. "[vsock]\(self.contextID):\(self.port)"
  260. }
  261. }
  262. extension SocketAddress.VirtualSocket.ContextID: CustomStringConvertible {
  263. public var description: String {
  264. self == .any ? "-1" : String(describing: self.rawValue)
  265. }
  266. }
  267. extension SocketAddress.VirtualSocket.Port: CustomStringConvertible {
  268. public var description: String {
  269. self == .any ? "-1" : String(describing: self.rawValue)
  270. }
  271. }