/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.
package std.net
@When[os == "Windows"]
@C
struct Linger {
var enabled: UInt16 = 0
var seconds: UInt16 = 0
init(onOff: Bool, seconds: Int64) {
this.enabled = if (onOff) {
1
} else {
0
}
this.seconds = match {
case seconds > Int64(UInt16.Max) => UInt16.Max
case _ => UInt16(seconds)
}
}
static const size: UIntNative = 4
static func use<R>(block: (CPointer<Linger>) -> R): R {
unsafe {
let ptr = LibC.malloc<Linger>()
if (ptr.isNull()) {
throw IllegalMemoryException("Malloc failed.")
}
try {
block(ptr)
} finally {
LibC.free(ptr)
}
}
}
}
@When[os != "Windows"]
@C
struct Linger {
var enabled: Int32 = 0
var seconds: Int32 = 0
init(onOff: Bool, seconds: Int64) {
this.enabled = if (onOff) {
1
} else {
0
}
this.seconds = match {
case seconds > Int64(Int32.Max) => Int32.Max
case _ => Int32(seconds)
}
}
static let size: UIntNative = 8
static func use<R>(block: (CPointer<Linger>) -> R): R {
unsafe {
let ptr = LibC.malloc<Linger>()
if (ptr.isNull()) {
throw IllegalMemoryException("Malloc failed.")
}
try {
block(ptr)
} finally {
LibC.free(ptr)
}
}
}
}
extend<ActualPlatformSocket> SocketCommon<ActualPlatformSocket> {
func getLinger(): ?Duration {
Linger.use<?Duration> {
ptr => unsafe {
let sizePtr = LibC.malloc<UIntNative>()
if (sizePtr.isNull()) {
throw IllegalMemoryException("Malloc failed.")
}
try {
sizePtr.write(Linger.size)
getSocketOption(SOL_SOCKET, SOCK_LINGER, CPointer(ptr), sizePtr)
} finally {
LibC.free(sizePtr)
}
let lingerValue = ptr.read()
match {
case lingerValue.enabled != 0 => Duration.second * Int64(lingerValue.seconds)
case _ => None
}
}
}
}
func setLinger(newLinger: ?Duration): Unit {
Linger.use<Unit> {
ptr => unsafe {
var lingerValue = match (newLinger) {
case Some(linger) => Linger(true,
linger.throwIfNegative("Linger").bumpAtLeast(Duration.second * 1).toSeconds())
case _ => Linger(false, 0)
}
ptr.write(lingerValue)
setSocketOption(SOL_SOCKET, SOCK_LINGER, CPointer(ptr), Linger.size)
}
}
}
}