@@ -442,64 +442,164 @@ extension SocketDescriptor {
442
442
}
443
443
444
444
extension 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.
448
460
@_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 ( )
453
467
}
454
468
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 ( )
469
490
}
491
+ return value
492
+ }
470
493
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
+ }
472
513
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)
473
521
let success = system_getsockopt (
474
522
self . rawValue,
475
523
level. rawValue,
476
524
option. rawValue,
477
- resultPtr, & length)
525
+ buffer. baseAddress, & length)
526
+ return nothingOrErrno ( success) . map { _ in Int ( length) }
527
+ }
528
+ }
478
529
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
+ }
480
570
}
481
571
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)`).
483
583
@_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
486
588
) throws {
487
- try _setOption ( level, option, to: value) . get ( )
589
+ try setOption ( level, option, to: ( value ? 1 : 0 ) as CInt )
488
590
}
489
591
490
592
@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) )
503
603
return nothingOrErrno ( success)
504
604
}
505
605
}
0 commit comments