88*/
99
1010extension SocketDescriptor {
11- @frozen
11+ @frozen
1212 public struct Option : RawRepresentable , Hashable {
1313 @_alwaysEmitIntoClient
1414 public var rawValue : CInt
@@ -317,129 +317,129 @@ extension SocketDescriptor {
317317 /// A value of -1 resets to the default value.
318318 ///
319319 /// The corresponding C constant is `IPV6_UNICAST_HOPS`.
320- @_alwaysEmitIntoClient
321- public static var ipv6UnicastHops : Option { Option ( _IPV6_UNICAST_HOPS) }
322-
323- /// The interface from which multicast packets will be sent.
324- ///
325- /// A value of 0 specifies the default interface.
326- ///
327- /// The corresponding C constant is `IPV6_MULTICAST_IF`.
328- @_alwaysEmitIntoClient
329- public static var ipv6MulticastInterface : Option { Option ( _IPV6_MULTICAST_IF) }
330-
331- /// The default hop limit header field for outgoing multicast datagrams.
332- ///
333- /// The corresponding C constant is `IPV6_MULTICAST_HOPS`.
334- @_alwaysEmitIntoClient
335- public static var ipv6MulticastHops : Option { Option ( _IPV6_MULTICAST_HOPS) }
336-
337- /// Whether multicast datagrams will be looped back.
338- ///
339- /// The corresponding C constant is `IPV6_MULTICAST_LOOP`.
340- @_alwaysEmitIntoClient
341- public static var ipv6MulticastLoop : Option { Option ( _IPV6_MULTICAST_LOOP) }
342-
343- /// Join a multicast group.
344- ///
345- /// The corresponding C constant is `IPV6_JOIN_GROUP`.
346- @_alwaysEmitIntoClient
347- public static var ipv6JoinGroup : Option { Option ( _IPV6_JOIN_GROUP) }
348-
349- /// Leave a multicast group.
350- ///
351- /// The corresponding C constant is `IPV6_LEAVE_GROUP`.
352- @_alwaysEmitIntoClient
353- public static var ipv6LeaveGroup : Option { Option ( _IPV6_LEAVE_GROUP) }
354-
355- /// Allocation policy of ephemeral ports for when the kernel automatically
356- /// binds a local address to this socket.
357- ///
358- /// TODO: portrange struct somewhere, with _DEFAULT, _HIGH, _LOW
359- ///
360- /// The corresponding C constant is `IPV6_PORTRANGE`.
361- @_alwaysEmitIntoClient
362- public static var ipv6PortRange : Option { Option ( _IPV6_PORTRANGE) }
363-
364- // /// Whether additional information about subsequent packets will be
365- // /// provided in `recvmsg` calls.
366- // ///
367- // /// The corresponding C constant is `IPV6_PKTINFO`.
368- // @_alwaysEmitIntoClient
369- // public static var ipv6ReceivePacketInfo: Option { Option(_IPV6_PKTINFO) }
320+ @_alwaysEmitIntoClient
321+ public static var ipv6UnicastHops : Option { Option ( _IPV6_UNICAST_HOPS) }
322+
323+ /// The interface from which multicast packets will be sent.
324+ ///
325+ /// A value of 0 specifies the default interface.
326+ ///
327+ /// The corresponding C constant is `IPV6_MULTICAST_IF`.
328+ @_alwaysEmitIntoClient
329+ public static var ipv6MulticastInterface : Option { Option ( _IPV6_MULTICAST_IF) }
330+
331+ /// The default hop limit header field for outgoing multicast datagrams.
332+ ///
333+ /// The corresponding C constant is `IPV6_MULTICAST_HOPS`.
334+ @_alwaysEmitIntoClient
335+ public static var ipv6MulticastHops : Option { Option ( _IPV6_MULTICAST_HOPS) }
336+
337+ /// Whether multicast datagrams will be looped back.
338+ ///
339+ /// The corresponding C constant is `IPV6_MULTICAST_LOOP`.
340+ @_alwaysEmitIntoClient
341+ public static var ipv6MulticastLoop : Option { Option ( _IPV6_MULTICAST_LOOP) }
342+
343+ /// Join a multicast group.
344+ ///
345+ /// The corresponding C constant is `IPV6_JOIN_GROUP`.
346+ @_alwaysEmitIntoClient
347+ public static var ipv6JoinGroup : Option { Option ( _IPV6_JOIN_GROUP) }
348+
349+ /// Leave a multicast group.
350+ ///
351+ /// The corresponding C constant is `IPV6_LEAVE_GROUP`.
352+ @_alwaysEmitIntoClient
353+ public static var ipv6LeaveGroup : Option { Option ( _IPV6_LEAVE_GROUP) }
354+
355+ /// Allocation policy of ephemeral ports for when the kernel automatically
356+ /// binds a local address to this socket.
357+ ///
358+ /// TODO: portrange struct somewhere, with _DEFAULT, _HIGH, _LOW
359+ ///
360+ /// The corresponding C constant is `IPV6_PORTRANGE`.
361+ @_alwaysEmitIntoClient
362+ public static var ipv6PortRange : Option { Option ( _IPV6_PORTRANGE) }
363+
364+ // /// Whether additional information about subsequent packets will be
365+ // /// provided in `recvmsg` calls.
366+ // ///
367+ // /// The corresponding C constant is `IPV6_PKTINFO`.
368+ // @_alwaysEmitIntoClient
369+ // public static var ipv6ReceivePacketInfo: Option { Option(_IPV6_PKTINFO) }
370370//
371- // /// Whether the hop limit header field from subsequent packets will
372- // /// be provided in `recvmsg` calls.
373- // ///
374- // /// The corresponding C constant is `IPV6_HOPLIMIT`.
375- // @_alwaysEmitIntoClient
376- // public static var ipv6ReceiveHopLimit: Option { Option(_IPV6_HOPLIMIT) }
371+ // /// Whether the hop limit header field from subsequent packets will
372+ // /// be provided in `recvmsg` calls.
373+ // ///
374+ // /// The corresponding C constant is `IPV6_HOPLIMIT`.
375+ // @_alwaysEmitIntoClient
376+ // public static var ipv6ReceiveHopLimit: Option { Option(_IPV6_HOPLIMIT) }
377377//
378- // /// Whether hop-by-hop options from subsequent packets will
379- // /// be provided in `recvmsg` calls.
380- // ///
381- // /// The corresponding C constant is `IPV6_HOPOPTS`.
382- // @_alwaysEmitIntoClient
383- // public static var ipv6ReceiveHopOptions: Option { Option(_IPV6_HOPOPTS) }
378+ // /// Whether hop-by-hop options from subsequent packets will
379+ // /// be provided in `recvmsg` calls.
380+ // ///
381+ // /// The corresponding C constant is `IPV6_HOPOPTS`.
382+ // @_alwaysEmitIntoClient
383+ // public static var ipv6ReceiveHopOptions: Option { Option(_IPV6_HOPOPTS) }
384384//
385- // /// Whether destination options from subsequent packets will
386- // /// be provided in `recvmsg` calls.
387- // ///
388- // /// The corresponding C constant is `IPV6_DSTOPTS`.
389- // @_alwaysEmitIntoClient
390- // public static var ipv6ReceiveDestinationOptions: Option { Option(_IPV6_DSTOPTS) }
391-
392- /// The value of the traffic class field for outgoing datagrams.
393- ///
394- /// The corresponding C constant is `IPV6_TCLASS`.
395- @_alwaysEmitIntoClient
396- public static var ipv6TrafficClass : Option { Option ( _IPV6_TCLASS) }
397-
398- /// Whether traffic class header field from subsequent packets will
399- /// be provided in `recvmsg` calls.
400- ///
401- /// The corresponding C constant is `IPV6_RECVTCLASS`.
402- @_alwaysEmitIntoClient
403- public static var ipv6ReceiveTrafficClass : Option { Option ( _IPV6_RECVTCLASS) }
404-
405- // /// Whether the routing header from subsequent packets will
406- // /// be provided in `recvmsg` calls.
407- // ///
408- // /// The corresponding C constant is `IPV6_RTHDR`.
409- // @_alwaysEmitIntoClient
410- // public static var ipv6ReceiveRoutingHeader: Option { Option(_IPV6_RTHDR) }
385+ // /// Whether destination options from subsequent packets will
386+ // /// be provided in `recvmsg` calls.
387+ // ///
388+ // /// The corresponding C constant is `IPV6_DSTOPTS`.
389+ // @_alwaysEmitIntoClient
390+ // public static var ipv6ReceiveDestinationOptions: Option { Option(_IPV6_DSTOPTS) }
391+
392+ /// The value of the traffic class field for outgoing datagrams.
393+ ///
394+ /// The corresponding C constant is `IPV6_TCLASS`.
395+ @_alwaysEmitIntoClient
396+ public static var ipv6TrafficClass : Option { Option ( _IPV6_TCLASS) }
397+
398+ /// Whether traffic class header field from subsequent packets will
399+ /// be provided in `recvmsg` calls.
400+ ///
401+ /// The corresponding C constant is `IPV6_RECVTCLASS`.
402+ @_alwaysEmitIntoClient
403+ public static var ipv6ReceiveTrafficClass : Option { Option ( _IPV6_RECVTCLASS) }
404+
405+ // /// Whether the routing header from subsequent packets will
406+ // /// be provided in `recvmsg` calls.
407+ // ///
408+ // /// The corresponding C constant is `IPV6_RTHDR`.
409+ // @_alwaysEmitIntoClient
410+ // public static var ipv6ReceiveRoutingHeader: Option { Option(_IPV6_RTHDR) }
411411//
412- // /// Get or set all header options and extension headers at one time
413- // /// on the last packet sent or received.
414- // ///
415- // /// The corresponding C constant is `IPV6_PKTOPTIONS`.
416- // @_alwaysEmitIntoClient
417- // public static var ipv6PacketOptions: Option { Option(_IPV6_PKTOPTIONS) }
418-
419- /// The byte offset into a packet where 16-bit checksum is located.
420- ///
421- /// The corresponding C constant is `IPV6_CHECKSUM`.
422- @_alwaysEmitIntoClient
423- public static var ipv6Checksum : Option { Option ( _IPV6_CHECKSUM) }
424-
425- /// Whether only IPv6 connections can be made to this socket.
426- ///
427- /// The corresponding C constant is `IPV6_V6ONLY`.
428- @_alwaysEmitIntoClient
429- public static var ipv6Only : Option { Option ( _IPV6_V6ONLY) }
430-
431- // /// Whether the minimal IPv6 maximum transmission unit (MTU) size
432- // /// will be used to avoid fragmentation for subsequenet outgoing
433- // /// datagrams.
434- // ///
435- // /// The corresponding C constant is `IPV6_USE_MIN_MTU`.
436- // @_alwaysEmitIntoClient
437- // public static var ipv6UseMinimalMTU: Option { Option(_IPV6_USE_MIN_MTU) }
412+ // /// Get or set all header options and extension headers at one time
413+ // /// on the last packet sent or received.
414+ // ///
415+ // /// The corresponding C constant is `IPV6_PKTOPTIONS`.
416+ // @_alwaysEmitIntoClient
417+ // public static var ipv6PacketOptions: Option { Option(_IPV6_PKTOPTIONS) }
418+
419+ /// The byte offset into a packet where 16-bit checksum is located.
420+ ///
421+ /// The corresponding C constant is `IPV6_CHECKSUM`.
422+ @_alwaysEmitIntoClient
423+ public static var ipv6Checksum : Option { Option ( _IPV6_CHECKSUM) }
424+
425+ /// Whether only IPv6 connections can be made to this socket.
426+ ///
427+ /// The corresponding C constant is `IPV6_V6ONLY`.
428+ @_alwaysEmitIntoClient
429+ public static var ipv6Only : Option { Option ( _IPV6_V6ONLY) }
430+
431+ // /// Whether the minimal IPv6 maximum transmission unit (MTU) size
432+ // /// will be used to avoid fragmentation for subsequenet outgoing
433+ // /// datagrams.
434+ // ///
435+ // /// The corresponding C constant is `IPV6_USE_MIN_MTU`.
436+ // @_alwaysEmitIntoClient
437+ // public static var ipv6UseMinimalMTU: Option { Option(_IPV6_USE_MIN_MTU) }
438438 }
439439}
440440
441441extension SocketDescriptor . Option {
442- /// The level at which a socket option resides
442+ /// The level at which a socket option resides
443443 @frozen
444444 public struct Level : RawRepresentable , Hashable {
445445 @_alwaysEmitIntoClient
@@ -453,27 +453,87 @@ extension SocketDescriptor.Option {
453453
454454 /// Socket options that only apply to IP sockets.
455455 ///
456- /// The corresponding C constant is `IPPROTO_IP`.
456+ /// The corresponding C constant is `IPPROTO_IP`.
457457 @_alwaysEmitIntoClient
458458 public static var ip : Level { Level ( _IPPROTO_IP) }
459459
460460 /// Socket options that only apply to IPv6 sockets
461461 ///
462- /// The corresponding C constant is `IPPROTO_IPV6`.
462+ /// The corresponding C constant is `IPPROTO_IPV6`.
463463 @_alwaysEmitIntoClient
464464 public static var ipv6 : Level { Level ( _IPPROTO_IPV6) }
465465
466466 /// Socket options that only apply to TCP sockets
467467 ///
468- /// The corresponding C constant is `IPPROTO_TCP`.
468+ /// The corresponding C constant is `IPPROTO_TCP`.
469469 @_alwaysEmitIntoClient
470470 public static var tcp : Level { Level ( _IPPROTO_TCP) }
471471
472472 /// Socket options that apply to all sockets.
473473 ///
474- /// The corresponding C constant is `SOL_SOCKET`.
474+ /// The corresponding C constant is `SOL_SOCKET`.
475475 @_alwaysEmitIntoClient
476476 public static var socket : Level { Level ( _SOL_SOCKET) }
477477 }
478478}
479479
480+ extension SocketDescriptor {
481+ // TODO: Convenience/performance overloads for `Bool` and other concrete types
482+
483+ @_alwaysEmitIntoClient
484+ public func getOption< T> (
485+ _ level: Option . Level , _ option: Option
486+ ) throws -> T {
487+ try _getOption ( level, option) . get ( )
488+ }
489+
490+ @usableFromInline
491+ internal func _getOption< T> (
492+ _ level: Option . Level , _ option: Option
493+ ) -> Result < T , Errno > {
494+ // We can't zero-initialize `T` directly, nor can we pass an uninitialized `T`
495+ // to `withUnsafeMutableBytes(of:)`. Instead, we will allocate :-(
496+ let rawBuf = UnsafeMutableRawBufferPointer . allocate (
497+ byteCount: MemoryLayout< T> . stride,
498+ alignment: MemoryLayout< T> . alignment)
499+ rawBuf. initializeMemory ( as: UInt8 . self, repeating: 0 )
500+ let resultPtr = rawBuf. baseAddress!. bindMemory ( to: T . self, capacity: 1 )
501+ defer {
502+ resultPtr. deinitialize ( count: 1 )
503+ rawBuf. deallocate ( )
504+ }
505+
506+ var length : _CSockLenT = 0
507+
508+ let success = system_getsockopt (
509+ self . rawValue,
510+ level. rawValue,
511+ option. rawValue,
512+ resultPtr, & length)
513+
514+ return nothingOrErrno ( success) . map { resultPtr. pointee }
515+ }
516+
517+ @_alwaysEmitIntoClient
518+ public func setOption< T> (
519+ _ level: Option . Level , _ option: Option , to value: T
520+ ) throws {
521+ try _setOption ( level, option, to: value) . get ( )
522+ }
523+
524+ @usableFromInline
525+ internal func _setOption< T> (
526+ _ level: Option . Level , _ option: Option , to value: T
527+ ) -> Result < ( ) , Errno > {
528+ let len = _CSockLenT ( MemoryLayout< T> . stride)
529+ let success = withUnsafeBytes ( of: value) {
530+ return system_setsockopt (
531+ self . rawValue,
532+ level. rawValue,
533+ option. rawValue,
534+ $0. baseAddress,
535+ len)
536+ }
537+ return nothingOrErrno ( success)
538+ }
539+ }
0 commit comments