mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support SO_LINGER socket option.
When SO_LINGER option is enabled, the close will not return until all the queued messages are sent and acknowledged for the socket or linger timeout is reached. If the option is not set, close will return immediately. This option is mainly supported for connection oriented protocols such as TCP. PiperOrigin-RevId: 328350576
This commit is contained in:
committed by
gVisor bot
parent
10fa583c36
commit
b26f7503b5
@@ -479,8 +479,35 @@ func (s *socketOpsCommon) fetchReadView() *syserr.Error {
|
||||
}
|
||||
|
||||
// Release implements fs.FileOperations.Release.
|
||||
func (s *socketOpsCommon) Release(context.Context) {
|
||||
func (s *socketOpsCommon) Release(ctx context.Context) {
|
||||
e, ch := waiter.NewChannelEntry(nil)
|
||||
s.EventRegister(&e, waiter.EventHUp|waiter.EventErr)
|
||||
defer s.EventUnregister(&e)
|
||||
|
||||
s.Endpoint.Close()
|
||||
|
||||
// SO_LINGER option is valid only for TCP. For other socket types
|
||||
// return after endpoint close.
|
||||
if family, skType, _ := s.Type(); skType != linux.SOCK_STREAM || (family != linux.AF_INET && family != linux.AF_INET6) {
|
||||
return
|
||||
}
|
||||
|
||||
var v tcpip.LingerOption
|
||||
if err := s.Endpoint.GetSockOpt(&v); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// The case for zero timeout is handled in tcp endpoint close function.
|
||||
// Close is blocked until either:
|
||||
// 1. The endpoint state is not in any of the states: FIN-WAIT1,
|
||||
// CLOSING and LAST_ACK.
|
||||
// 2. Timeout is reached.
|
||||
if v.Enabled && v.Timeout != 0 {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
start := t.Kernel().MonotonicClock().Now()
|
||||
deadline := start.Add(v.Timeout)
|
||||
t.BlockWithDeadline(ch, true, deadline)
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements fs.FileOperations.Read.
|
||||
@@ -1195,7 +1222,16 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
linger := linux.Linger{}
|
||||
var v tcpip.LingerOption
|
||||
var linger linux.Linger
|
||||
if err := ep.GetSockOpt(&v); err != nil {
|
||||
return &linger, nil
|
||||
}
|
||||
|
||||
if v.Enabled {
|
||||
linger.OnOff = 1
|
||||
}
|
||||
linger.Linger = int32(v.Timeout.Seconds())
|
||||
return &linger, nil
|
||||
|
||||
case linux.SO_SNDTIMEO:
|
||||
@@ -1865,7 +1901,10 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
|
||||
socket.SetSockOptEmitUnimplementedEvent(t, name)
|
||||
}
|
||||
|
||||
return nil
|
||||
return syserr.TranslateNetstackError(
|
||||
ep.SetSockOpt(tcpip.LingerOption{
|
||||
Enabled: v.OnOff != 0,
|
||||
Timeout: time.Second * time.Duration(v.Linger)}))
|
||||
|
||||
case linux.SO_DETACH_FILTER:
|
||||
// optval is ignored.
|
||||
|
||||
Reference in New Issue
Block a user