@@ -442,64 +442,164 @@ extension SocketDescriptor {
442442}
443443
444444extension SocketDescriptor {
445- // TODO: Convenience/performance overloads for `Bool` and other concrete types
446-
447- /// Get an option associated with this socket.
445+ // TODO: Wrappers and convenience overloads for other concrete types
446+ // (timeval, linger)
447+ // For now, clients can use the UMRBP-based variants below.
448+
449+ /// Copy an option associated with this socket into the specified buffer.
450+ ///
451+ /// The method corresponds to the C function `getsockopt`.
452+ ///
453+ /// - Parameters:
454+ /// - level: The option level. To get a socket-level option, specify `.socketLevel`.
455+ /// Otherwise use the protocol value that defines your desired option.
456+ /// - option: The option identifier within the level.
457+ /// - buffer: The buffer into which to copy the option value.
458+ ///
459+ /// - Returns: The number of bytes copied into the supplied buffer.
448460 @_alwaysEmitIntoClient
449- public func getOption< T> (
450- _ level: ProtocolID , _ option: Option
451- ) throws -> T {
452- try _getOption ( level, option) . get ( )
461+ public func getOption(
462+ _ level: ProtocolID ,
463+ _ option: Option ,
464+ into buffer: UnsafeMutableRawBufferPointer
465+ ) throws -> Int {
466+ try _getOption ( level, option, into: buffer) . get ( )
453467 }
454468
455- @usableFromInline
456- internal func _getOption< T> (
457- _ level: ProtocolID , _ option: Option
458- ) -> Result < T , Errno > {
459- // We can't zero-initialize `T` directly, nor can we pass an uninitialized `T`.
460- // to `withUnsafeMutableBytes(of:)`. Instead, we will allocate :-(
461- let rawBuf = UnsafeMutableRawBufferPointer . allocate (
462- byteCount: MemoryLayout< T> . stride,
463- alignment: MemoryLayout< T> . alignment)
464- rawBuf. initializeMemory ( as: UInt8 . self, repeating: 0 )
465- let resultPtr = rawBuf. baseAddress!. bindMemory ( to: T . self, capacity: 1 )
466- defer {
467- resultPtr. deinitialize ( count: 1 )
468- rawBuf. deallocate ( )
469+ /// Return the value of an option associated with this socket as a `CInt` value.
470+ ///
471+ /// The method corresponds to the C function `getsockopt`.
472+ ///
473+ /// - Parameters:
474+ /// - level: The option level. To get a socket-level option, specify `.socketLevel`.
475+ /// Otherwise use the protocol value that defines your desired option.
476+ /// - option: The option identifier within the level.
477+ /// - type: The type to return. Must be set to `CInt.self` (the default).
478+ ///
479+ /// - Returns: The current value of the option.
480+ @_alwaysEmitIntoClient
481+ public func getOption(
482+ _ level: ProtocolID ,
483+ _ option: Option ,
484+ as type: CInt . Type = CInt . self
485+ ) throws -> CInt {
486+ var value : CInt = 0
487+ try withUnsafeMutableBytes ( of: & value) { buffer in
488+ // Note: return value is intentionally ignored.
489+ _ = try _getOption ( level, option, into: buffer) . get ( )
469490 }
491+ return value
492+ }
470493
471- var length : CInterop . SockLen = 0
494+ /// Return the value of an option associated with this socket as a `Bool` value.
495+ ///
496+ /// The method corresponds to the C function `getsockopt`.
497+ ///
498+ /// - Parameters:
499+ /// - level: The option level. To get a socket-level option, specify `.socketLevel`.
500+ /// Otherwise use the protocol value that defines your desired option.
501+ /// - option: The option identifier within the level.
502+ /// - type: The type to return. Must be set to `Bool.self` (the default).
503+ ///
504+ /// - Returns: True if the current value is not zero; otherwise false.
505+ @_alwaysEmitIntoClient
506+ public func getOption(
507+ _ level: ProtocolID ,
508+ _ option: Option ,
509+ as type: Bool . Type = Bool . self
510+ ) throws -> Bool {
511+ try 0 != getOption ( level, option, as: CInt . self)
512+ }
472513
514+ @usableFromInline
515+ internal func _getOption(
516+ _ level: ProtocolID ,
517+ _ option: Option ,
518+ into buffer: UnsafeMutableRawBufferPointer
519+ ) -> Result < Int , Errno > {
520+ var length = CInterop . SockLen ( buffer. count)
473521 let success = system_getsockopt (
474522 self . rawValue,
475523 level. rawValue,
476524 option. rawValue,
477- resultPtr, & length)
525+ buffer. baseAddress, & length)
526+ return nothingOrErrno ( success) . map { _ in Int ( length) }
527+ }
528+ }
478529
479- return nothingOrErrno ( success) . map { resultPtr. pointee }
530+ extension SocketDescriptor {
531+ /// Set the value of an option associated with this socket to the contents
532+ /// of the specified buffer.
533+ ///
534+ /// The method corresponds to the C function `setsockopt`.
535+ ///
536+ /// - Parameters:
537+ /// - level: The option level. To set a socket-level option, specify `.socketLevel`.
538+ /// Otherwise use the protocol value that defines your desired option.
539+ /// - option: The option identifier within the level.
540+ /// - buffer: The buffer that contains the desired option value.
541+ @_alwaysEmitIntoClient
542+ public func setOption(
543+ _ level: ProtocolID ,
544+ _ option: Option ,
545+ from buffer: UnsafeRawBufferPointer
546+ ) throws {
547+ try _setOption ( level, option, from: buffer) . get ( )
548+ }
549+
550+ /// Set the value of an option associated with this socket to the supplied
551+ /// `CInt` value.
552+ ///
553+ /// The method corresponds to the C function `setsockopt`.
554+ ///
555+ /// - Parameters:
556+ /// - level: The option level. To set a socket-level option, specify `.socketLevel`.
557+ /// Otherwise use the protocol value that defines your desired option.
558+ /// - option: The option identifier within the level.
559+ /// - value: The desired new value for the option.
560+ @_alwaysEmitIntoClient
561+ public func setOption(
562+ _ level: ProtocolID ,
563+ _ option: Option ,
564+ to value: CInt
565+ ) throws {
566+ return try withUnsafeBytes ( of: value) { buffer in
567+ // Note: return value is intentionally ignored.
568+ _ = try _setOption ( level, option, from: buffer) . get ( )
569+ }
480570 }
481571
482- /// Set an option associated with this socket.
572+ /// Set the value of an option associated with this socket to the supplied
573+ /// `Bool` value.
574+ ///
575+ /// The method corresponds to the C function `setsockopt`.
576+ ///
577+ /// - Parameters:
578+ /// - level: The option level. To set a socket-level option, specify `.socketLevel`.
579+ /// Otherwise use the protocol value that defines your desired option.
580+ /// - option: The option identifier within the level.
581+ /// - value: The desired new value for the option. (`true` gets stored
582+ /// as `(1 as CInt)`. `false` is represented by `(0 as CInt)`).
483583 @_alwaysEmitIntoClient
484- public func setOption< T> (
485- _ level: ProtocolID , _ option: Option , to value: T
584+ public func setOption(
585+ _ level: ProtocolID ,
586+ _ option: Option ,
587+ to value: Bool
486588 ) throws {
487- try _setOption ( level, option, to: value) . get ( )
589+ try setOption ( level, option, to: ( value ? 1 : 0 ) as CInt )
488590 }
489591
490592 @usableFromInline
491- internal func _setOption< T> (
492- _ level: ProtocolID , _ option: Option , to value: T
493- ) -> Result < ( ) , Errno > {
494- let len = CInterop . SockLen ( MemoryLayout< T> . stride)
495- let success = withUnsafeBytes ( of: value) {
496- return system_setsockopt (
497- self . rawValue,
498- level. rawValue,
499- option. rawValue,
500- $0. baseAddress,
501- len)
502- }
593+ internal func _setOption(
594+ _ level: ProtocolID ,
595+ _ option: Option ,
596+ from buffer: UnsafeRawBufferPointer
597+ ) -> Result < Void , Errno > {
598+ let success = system_setsockopt (
599+ self . rawValue,
600+ level. rawValue,
601+ option. rawValue,
602+ buffer. baseAddress, CInterop . SockLen ( buffer. count) )
503603 return nothingOrErrno ( success)
504604 }
505605}
0 commit comments